Coverage Report

Created: 2026-07-02 14:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/segment/column_reader.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <gen_cpp/Descriptors_types.h>
21
#include <gen_cpp/segment_v2.pb.h>
22
#include <sys/types.h>
23
24
#include <cstddef> // for size_t
25
#include <cstdint> // for uint32_t
26
#include <memory>  // for unique_ptr
27
#include <optional>
28
#include <string>
29
#include <utility>
30
#include <vector>
31
32
#include "common/compiler_util.h"
33
#include "common/config.h"
34
#include "common/logging.h"
35
#include "common/status.h"            // for Status
36
#include "core/column/column_array.h" // ColumnArray
37
#include "core/data_type/data_type.h"
38
#include "io/cache/cached_remote_file_reader.h"
39
#include "io/fs/file_reader_writer_fwd.h"
40
#include "io/io_common.h"
41
#include "storage/index/index_reader.h"
42
#include "storage/index/ordinal_page_index.h" // for OrdinalPageIndexIterator
43
#include "storage/index/zone_map/zone_map_index.h"
44
#include "storage/olap_common.h"
45
#include "storage/predicate/column_predicate.h"
46
#include "storage/segment/common.h"
47
#include "storage/segment/page_handle.h" // for PageHandle
48
#include "storage/segment/page_pointer.h"
49
#include "storage/segment/parsed_page.h" // for ParsedPage
50
#include "storage/segment/row_ranges.h"
51
#include "storage/segment/segment_prefetcher.h"
52
#include "storage/segment/stream_reader.h"
53
#include "storage/tablet/tablet_schema.h"
54
#include "storage/types.h"
55
#include "storage/utils.h"
56
#include "util/once.h"
57
58
namespace doris {
59
60
class BlockCompressionCodec;
61
class AndBlockColumnPredicate;
62
class ColumnPredicate;
63
class TabletIndex;
64
class StorageReadOptions;
65
66
namespace io {
67
class FileReader;
68
} // namespace io
69
struct Slice;
70
struct StringRef;
71
72
using TColumnAccessPaths = std::vector<TColumnAccessPath>;
73
74
namespace segment_v2 {
75
class EncodingInfo;
76
class ColumnIterator;
77
class BloomFilterIndexReader;
78
class InvertedIndexIterator;
79
class InvertedIndexReader;
80
class IndexFileReader;
81
class PageDecoder;
82
class RowRanges;
83
class ZoneMapIndexReader;
84
class IndexIterator;
85
class ColumnMetaAccessor;
86
87
struct ColumnReaderOptions {
88
    // whether verify checksum when read page
89
    bool verify_checksum = true;
90
    // for in memory olap table, use DURABLE CachePriority in page cache
91
    bool kept_in_memory = false;
92
93
    int be_exec_version = -1;
94
95
    TabletSchemaSPtr tablet_schema = nullptr;
96
97
    // When set, ColumnReader::create returns a ConstantColumnReader carrying this value instead
98
    // of reading on-disk data. Used for read-time-filled constant columns (e.g.
99
    // __DORIS_COMMIT_TSO_COL__) on a single-version segment, whose on-disk value is only a
100
    // placeholder. The value is constant within a segment, so the resulting reader is cacheable.
101
    std::optional<Field> const_value = std::nullopt;
102
};
103
104
struct ColumnIteratorOptions {
105
    bool use_page_cache = false;
106
    bool is_predicate_column = false;
107
    // for page cache allocation
108
    // page types are divided into DATA_PAGE & INDEX_PAGE
109
    // INDEX_PAGE including index_page, dict_page and short_key_page
110
    PageTypePB type = PageTypePB::UNKNOWN_PAGE_TYPE;
111
    io::FileReader* file_reader = nullptr; // Ref
112
    // reader statistics
113
    OlapReaderStatistics* stats = nullptr; // Ref
114
    io::IOContext io_ctx;
115
    bool only_read_offsets = false;
116
117
13.8k
    void sanity_check() const {
118
13.8k
        CHECK_NOTNULL(file_reader);
119
13.8k
        CHECK_NOTNULL(stats);
120
13.8k
    }
121
};
122
123
class ColumnIterator;
124
class OffsetFileColumnIterator;
125
class FileColumnIterator;
126
127
using ColumnIteratorUPtr = std::unique_ptr<ColumnIterator>;
128
using OffsetFileColumnIteratorUPtr = std::unique_ptr<OffsetFileColumnIterator>;
129
using FileColumnIteratorUPtr = std::unique_ptr<FileColumnIterator>;
130
using ColumnIteratorSPtr = std::shared_ptr<ColumnIterator>;
131
132
// There will be concurrent users to read the same column. So
133
// we should do our best to reduce resource usage through share
134
// same information, such as OrdinalPageIndex and Page data.
135
// This will cache data shared by all reader
136
class ColumnReader : public MetadataAdder<ColumnReader>,
137
                     public std::enable_shared_from_this<ColumnReader> {
138
public:
139
    ColumnReader();
140
    // Create an initialized ColumnReader in *reader.
141
    // This should be a lightweight operation without I/O.
142
    static Status create(const ColumnReaderOptions& opts, const ColumnMetaPB& meta,
143
                         uint64_t num_rows, const io::FileReaderSPtr& file_reader,
144
                         std::shared_ptr<ColumnReader>* reader);
145
146
    static Status create_array(const ColumnReaderOptions& opts, const ColumnMetaPB& meta,
147
                               const io::FileReaderSPtr& file_reader,
148
                               std::shared_ptr<ColumnReader>* reader);
149
    static Status create_map(const ColumnReaderOptions& opts, const ColumnMetaPB& meta,
150
                             const io::FileReaderSPtr& file_reader,
151
                             std::shared_ptr<ColumnReader>* reader);
152
    static Status create_struct(const ColumnReaderOptions& opts, const ColumnMetaPB& meta,
153
                                uint64_t num_rows, const io::FileReaderSPtr& file_reader,
154
                                std::shared_ptr<ColumnReader>* reader);
155
    static Status create_agg_state(const ColumnReaderOptions& opts, const ColumnMetaPB& meta,
156
                                   uint64_t num_rows, const io::FileReaderSPtr& file_reader,
157
                                   std::shared_ptr<ColumnReader>* reader);
158
159
    enum DictEncodingType { UNKNOWN_DICT_ENCODING, PARTIAL_DICT_ENCODING, ALL_DICT_ENCODING };
160
161
    static bool is_compaction_reader_type(ReaderType type);
162
163
    ~ColumnReader() override;
164
165
    // create a new column iterator. Client should delete returned iterator
166
    virtual Status new_iterator(ColumnIteratorUPtr* iterator, const TabletColumn* col,
167
                                const StorageReadOptions*);
168
    Status new_iterator(ColumnIteratorUPtr* iterator, const TabletColumn* tablet_column);
169
    Status new_array_iterator(ColumnIteratorUPtr* iterator, const TabletColumn* tablet_column);
170
    Status new_struct_iterator(ColumnIteratorUPtr* iterator, const TabletColumn* tablet_column);
171
    Status new_map_iterator(ColumnIteratorUPtr* iterator, const TabletColumn* tablet_column);
172
    Status new_agg_state_iterator(ColumnIteratorUPtr* iterator);
173
174
    Status new_index_iterator(const std::shared_ptr<IndexFileReader>& index_file_reader,
175
                              const TabletIndex* index_meta, const std::string& rowset_id,
176
                              uint32_t segment_id, size_t rows_of_segment,
177
                              std::unique_ptr<IndexIterator>* iterator);
178
179
    Status seek_at_or_before(ordinal_t ordinal, OrdinalPageIndexIterator* iter,
180
                             const ColumnIteratorOptions& iter_opts);
181
    Status get_ordinal_index_reader(OrdinalIndexReader*& reader,
182
                                    OlapReaderStatistics* index_load_stats);
183
184
    // read a page from file into a page handle
185
    Status read_page(const ColumnIteratorOptions& iter_opts, const PagePointer& pp,
186
                     PageHandle* handle, Slice* page_body, PageFooterPB* footer,
187
                     BlockCompressionCodec* codec) const;
188
189
4.73k
    bool is_nullable() const { return _meta_is_nullable; }
190
191
27.8k
    const EncodingInfo* encoding_info() const { return _encoding_info; }
192
193
144
    virtual bool has_zone_map() const { return _zone_map_index != nullptr; }
194
    bool has_bloom_filter_index(bool ngram) const;
195
    // Check if this column could match `cond' using segment zone map.
196
    // Since segment zone map is stored in metadata, this function is fast without I/O.
197
    // set matched to true if segment zone map is absent or `cond' could be satisfied, false otherwise.
198
    virtual Status match_condition(const AndBlockColumnPredicate* col_predicates,
199
                                   bool* matched) const;
200
201
    Status next_batch_of_zone_map(size_t* n, MutableColumnPtr& dst) const;
202
203
    // get row ranges with zone map
204
    // - cond_column is user's query predicate
205
    // - delete_condition is a delete predicate of one version
206
    Status get_row_ranges_by_zone_map(
207
            const AndBlockColumnPredicate* col_predicates,
208
            const std::vector<std::shared_ptr<const ColumnPredicate>>* delete_predicates,
209
            RowRanges* row_ranges, const ColumnIteratorOptions& iter_opts);
210
211
    // get row ranges with bloom filter index
212
    Status get_row_ranges_by_bloom_filter(const AndBlockColumnPredicate* col_predicates,
213
                                          RowRanges* row_ranges,
214
                                          const ColumnIteratorOptions& iter_opts);
215
216
3.07k
    PagePointer get_dict_page_pointer() const { return _meta_dict_page; }
217
218
9.50k
    bool is_empty() const { return _num_rows == 0; }
219
220
    Status prune_predicates_by_zone_map(std::vector<std::shared_ptr<ColumnPredicate>>& predicates,
221
                                        const int column_id, bool* pruned) const;
222
223
    Status get_segment_zone_map(segment_v2::ZoneMap* zone_map) const;
224
    Status get_page_zone_maps(const ColumnIteratorOptions& iter_opts,
225
                              const std::vector<ZoneMapPB>** zone_maps);
226
    Status get_row_range_for_page(uint32_t page_index, const ColumnIteratorOptions& iter_opts,
227
                                  RowRange* row_range);
228
229
8.57k
    CompressionTypePB get_compression() const { return _meta_compression; }
230
231
6.92k
    uint64_t num_rows() const { return _num_rows; }
232
233
33
    void set_dict_encoding_type(DictEncodingType type) {
234
33
        static_cast<void>(_set_dict_encoding_type_once.call([&] {
235
33
            _dict_encoding_type = type;
236
33
            return Status::OK();
237
33
        }));
238
33
    }
239
240
139
    DictEncodingType get_dict_encoding_type() { return _dict_encoding_type; }
241
242
8.57k
    void disable_index_meta_cache() { _use_index_page_cache = false; }
243
244
514
    DataTypePtr get_vec_data_type() { return _data_type; }
245
246
17.3k
    virtual FieldType get_meta_type() { return _meta_type; }
247
248
    int64_t get_metadata_size() const override;
249
250
#ifdef BE_TEST
251
    void check_data_by_zone_map_for_test(const MutableColumnPtr& dst) const;
252
#endif
253
254
private:
255
    friend class VariantColumnReader;
256
    friend class FileColumnIterator;
257
    friend class SegmentPrefetcher;
258
259
    ColumnReader(const ColumnReaderOptions& opts, const ColumnMetaPB& meta, uint64_t num_rows,
260
                 io::FileReaderSPtr file_reader);
261
    Status init(const ColumnMetaPB* meta);
262
263
    [[nodiscard]] Status _load_zone_map_index(bool use_page_cache, bool kept_in_memory,
264
                                              const ColumnIteratorOptions& iter_opts);
265
    [[nodiscard]] Status _load_ordinal_index(bool use_page_cache, bool kept_in_memory,
266
                                             const ColumnIteratorOptions& iter_opts);
267
268
    [[nodiscard]] Status _load_index(const std::shared_ptr<IndexFileReader>& index_file_reader,
269
                                     const TabletIndex* index_meta, const std::string& rowset_id,
270
                                     uint32_t segment_id, size_t rows_of_segment);
271
    [[nodiscard]] Status _load_bloom_filter_index(bool use_page_cache, bool kept_in_memory,
272
                                                  const ColumnIteratorOptions& iter_opts);
273
274
    bool _zone_map_match_condition(const segment_v2::ZoneMap& zone_map,
275
                                   const AndBlockColumnPredicate* col_predicates) const;
276
277
    Status _get_filtered_pages(
278
            const AndBlockColumnPredicate* col_predicates,
279
            const std::vector<std::shared_ptr<const ColumnPredicate>>* delete_predicates,
280
            std::vector<uint32_t>* page_indexes, const ColumnIteratorOptions& iter_opts);
281
282
    Status _calculate_row_ranges(const std::vector<uint32_t>& page_indexes, RowRanges* row_ranges,
283
                                 const ColumnIteratorOptions& iter_opts);
284
285
    int64_t _meta_length;
286
    FieldType _meta_type;
287
    FieldType _meta_children_column_type;
288
    bool _meta_is_nullable;
289
    bool _use_index_page_cache;
290
    int _be_exec_version = -1;
291
292
    PagePointer _meta_dict_page;
293
    CompressionTypePB _meta_compression;
294
295
    ColumnReaderOptions _opts;
296
    uint64_t _num_rows;
297
298
    io::FileReaderSPtr _file_reader;
299
300
    DictEncodingType _dict_encoding_type;
301
302
    DataTypePtr _data_type;
303
304
    FieldType _type =
305
            FieldType::OLAP_FIELD_TYPE_NONE; // initialized in init(), may changed by subclasses.
306
    const EncodingInfo* _encoding_info =
307
            nullptr; // initialized in init(), used for create PageDecoder
308
309
    // meta for various column indexes (null if the index is absent)
310
    std::unique_ptr<ZoneMapPB> _segment_zone_map;
311
312
    mutable std::shared_mutex _load_index_lock;
313
    std::unique_ptr<ZoneMapIndexReader> _zone_map_index;
314
    std::unique_ptr<OrdinalIndexReader> _ordinal_index;
315
    std::shared_ptr<BloomFilterIndexReader> _bloom_filter_index;
316
317
    std::unordered_map<int64_t, IndexReaderPtr> _index_readers;
318
319
    std::vector<std::shared_ptr<ColumnReader>> _sub_readers;
320
321
    DorisCallOnce<Status> _set_dict_encoding_type_once;
322
};
323
324
// Base iterator to read one column data
325
class ColumnIterator {
326
public:
327
9.79k
    ColumnIterator() = default;
328
9.79k
    virtual ~ColumnIterator() = default;
329
330
158
    virtual Status init(const ColumnIteratorOptions& opts) {
331
158
        _opts = opts;
332
158
        return Status::OK();
333
158
    }
334
335
    // Seek to the given ordinal entry in the column.
336
    // Entry 0 is the first entry written to the column.
337
    // If provided seek point is past the end of the file,
338
    // then returns false.
339
    virtual Status seek_to_ordinal(ordinal_t ord) = 0;
340
341
18.8k
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
342
18.8k
        bool has_null;
343
18.8k
        return next_batch(n, dst, &has_null);
344
18.8k
    }
345
346
0
    virtual Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) {
347
0
        return Status::NotSupported("next_batch not implement");
348
0
    }
349
350
0
    virtual Status next_batch_of_zone_map(size_t* n, MutableColumnPtr& dst) {
351
0
        return Status::NotSupported("next_batch_of_zone_map not implement");
352
0
    }
353
354
    virtual Status read_by_rowids(const rowid_t* rowids, const size_t count,
355
0
                                  MutableColumnPtr& dst) {
356
0
        return Status::NotSupported("read_by_rowids not implement");
357
0
    }
358
359
    virtual ordinal_t get_current_ordinal() const = 0;
360
361
    virtual Status get_row_ranges_by_zone_map(
362
            const AndBlockColumnPredicate* col_predicates,
363
            const std::vector<std::shared_ptr<const ColumnPredicate>>* delete_predicates,
364
0
            RowRanges* row_ranges) {
365
0
        return Status::OK();
366
0
    }
367
368
    virtual Status get_row_ranges_by_bloom_filter(const AndBlockColumnPredicate* col_predicates,
369
0
                                                  RowRanges* row_ranges) {
370
0
        return Status::OK();
371
0
    }
372
373
    virtual Status get_row_ranges_by_dict(const AndBlockColumnPredicate* col_predicates,
374
0
                                          RowRanges* row_ranges) {
375
0
        return Status::OK();
376
0
    }
377
378
0
    virtual bool is_all_dict_encoding() const { return false; }
379
380
    virtual Status set_access_paths(const TColumnAccessPaths& all_access_paths,
381
4
                                    const TColumnAccessPaths& predicate_access_paths) {
382
4
        if (!predicate_access_paths.empty()) {
383
2
            _reading_flag = ReadingFlag::READING_FOR_PREDICATE;
384
2
        }
385
4
        return Status::OK();
386
4
    }
387
388
9.03k
    void set_column_name(const std::string& column_name) { _column_name = column_name; }
389
390
10
    const std::string& column_name() const { return _column_name; }
391
392
    // Since there may be multiple paths with conflicts or overlaps,
393
    // we need to define several reading flags:
394
    //
395
    // NORMAL_READING — Default value, indicating that the column should be read.
396
    // SKIP_READING — The column should not be read.
397
    // NEED_TO_READ — The column must be read.
398
    // READING_FOR_PREDICATE — The column is required for predicate evaluation.
399
    //
400
    // For example, suppose there are two paths:
401
    // - Path 1 specifies that column A needs to be read, so it is marked as NEED_TO_READ.
402
    // - Path 2 specifies that the column should not be read, but since it is already marked as NEED_TO_READ,
403
    //   it should not be changed to SKIP_READING.
404
    enum class ReadingFlag : int {
405
        NORMAL_READING,
406
        SKIP_READING,
407
        NEED_TO_READ,
408
        READING_FOR_PREDICATE
409
    };
410
24
    void set_reading_flag(ReadingFlag flag) {
411
24
        if (static_cast<int>(flag) > static_cast<int>(_reading_flag)) {
412
15
            _reading_flag = flag;
413
15
        }
414
24
    }
415
416
666
    ReadingFlag reading_flag() const { return _reading_flag; }
417
418
3
    virtual void set_need_to_read() { set_reading_flag(ReadingFlag::NEED_TO_READ); }
419
420
0
    virtual void remove_pruned_sub_iterators() {};
421
422
0
    virtual Status init_prefetcher(const SegmentPrefetchParams& params) { return Status::OK(); }
423
424
    virtual void collect_prefetchers(
425
            std::map<PrefetcherInitMethod, std::vector<SegmentPrefetcher*>>& prefetchers,
426
0
            PrefetcherInitMethod init_method) {}
427
428
    static constexpr const char* ACCESS_OFFSET = "OFFSET";
429
    static constexpr const char* ACCESS_ALL = "*";
430
    static constexpr const char* ACCESS_MAP_KEYS = "KEYS";
431
    static constexpr const char* ACCESS_MAP_VALUES = "VALUES";
432
    static constexpr const char* ACCESS_NULL = "NULL";
433
434
    // Meta-only read modes:
435
    // - OFFSET_ONLY: only read offset information (e.g., for array_size/map_size/string_length)
436
    // - NULL_MAP_ONLY: only read null map (e.g., for IS NULL / IS NOT NULL predicates)
437
    // When these modes are enabled, actual content data is skipped.
438
    enum class ReadMode : int { DEFAULT, OFFSET_ONLY, NULL_MAP_ONLY };
439
440
3.44k
    bool read_offset_only() const { return _read_mode == ReadMode::OFFSET_ONLY; }
441
24.6k
    bool read_null_map_only() const { return _read_mode == ReadMode::NULL_MAP_ONLY; }
442
443
protected:
444
    // Checks sub access paths for OFFSET or NULL meta-only modes and
445
    // updates _read_mode accordingly. Use the accessor helpers
446
    // read_offset_only() / read_null_map_only() to query the current mode.
447
    void _check_and_set_meta_read_mode(const TColumnAccessPaths& sub_all_access_paths);
448
449
    Result<TColumnAccessPaths> _get_sub_access_paths(const TColumnAccessPaths& access_paths);
450
    ColumnIteratorOptions _opts;
451
452
    ReadingFlag _reading_flag {ReadingFlag::NORMAL_READING};
453
    ReadMode _read_mode = ReadMode::DEFAULT;
454
    std::string _column_name;
455
};
456
457
// This iterator is used to read column data from file
458
// for scalar type
459
class FileColumnIterator : public ColumnIterator {
460
public:
461
    explicit FileColumnIterator(std::shared_ptr<ColumnReader> reader);
462
    ~FileColumnIterator() override;
463
464
    Status init(const ColumnIteratorOptions& opts) override;
465
466
    Status seek_to_ordinal(ordinal_t ord) override;
467
468
    Status seek_to_page_start();
469
470
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override;
471
472
    Status next_batch_of_zone_map(size_t* n, MutableColumnPtr& dst) override;
473
474
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
475
                          MutableColumnPtr& dst) override;
476
477
2
    ordinal_t get_current_ordinal() const override { return _current_ordinal; }
478
479
    // get row ranges by zone map
480
    // - cond_column is user's query predicate
481
    // - delete_condition is delete predicate of one version
482
    Status get_row_ranges_by_zone_map(
483
            const AndBlockColumnPredicate* col_predicates,
484
            const std::vector<std::shared_ptr<const ColumnPredicate>>* delete_predicates,
485
            RowRanges* row_ranges) override;
486
487
    Status get_row_ranges_by_bloom_filter(const AndBlockColumnPredicate* col_predicates,
488
                                          RowRanges* row_ranges) override;
489
490
    Status get_row_ranges_by_dict(const AndBlockColumnPredicate* col_predicates,
491
                                  RowRanges* row_ranges) override;
492
493
1.24k
    ParsedPage* get_current_page() { return &_page; }
494
495
0
    bool is_nullable() { return _reader->is_nullable(); }
496
497
5
    bool is_all_dict_encoding() const override { return _is_all_dict_encoding; }
498
499
    Status init_prefetcher(const SegmentPrefetchParams& params) override;
500
    void collect_prefetchers(
501
            std::map<PrefetcherInitMethod, std::vector<SegmentPrefetcher*>>& prefetchers,
502
            PrefetcherInitMethod init_method) override;
503
504
protected:
505
    // Exposed to derived iterators (e.g. StringFileColumnIterator) so they can
506
    // query column metadata such as the storage field type.
507
2
    const std::shared_ptr<ColumnReader>& get_reader() const { return _reader; }
508
509
private:
510
    Status _seek_to_pos_in_page(ParsedPage* page, ordinal_t offset_in_page) const;
511
    Status _load_next_page(bool* eos);
512
    Status _read_data_page(const OrdinalPageIndexIterator& iter);
513
    Status _read_dict_data();
514
    void _trigger_prefetch_if_eligible(ordinal_t ord);
515
516
    std::shared_ptr<ColumnReader> _reader = nullptr;
517
518
    BlockCompressionCodec* _compress_codec = nullptr;
519
520
    // 1. The _page represents current page.
521
    // 2. We define an operation is one seek and following read,
522
    //    If new seek is issued, the _page will be reset.
523
    ParsedPage _page;
524
525
    // keep dict page decoder
526
    std::unique_ptr<PageDecoder> _dict_decoder;
527
528
    // keep dict page handle to avoid released
529
    PageHandle _dict_page_handle;
530
531
    // page iterator used to get next page when current page is finished.
532
    // This value will be reset when a new seek is issued
533
    OrdinalPageIndexIterator _page_iter;
534
535
    // current value ordinal
536
    ordinal_t _current_ordinal = 0;
537
538
    bool _is_all_dict_encoding = false;
539
540
    std::unique_ptr<StringRef[]> _dict_word_info;
541
542
    bool _enable_prefetch {false};
543
    std::unique_ptr<SegmentPrefetcher> _prefetcher;
544
    std::shared_ptr<io::CachedRemoteFileReader> _cached_remote_file_reader {nullptr};
545
};
546
547
class EmptyFileColumnIterator final : public ColumnIterator {
548
public:
549
134
    Status seek_to_ordinal(ordinal_t ord) override { return Status::OK(); }
550
0
    ordinal_t get_current_ordinal() const override { return 0; }
551
};
552
553
// StringFileColumnIterator extends FileColumnIterator with meta-only reading
554
// support for string/binary column types. When the OFFSET path is detected in
555
// set_access_paths, it sets only_read_offsets on the ColumnIteratorOptions so
556
// that the BinaryPlainPageDecoder skips chars memcpy and only fills offsets.
557
class StringFileColumnIterator final : public FileColumnIterator {
558
public:
559
    explicit StringFileColumnIterator(std::shared_ptr<ColumnReader> reader);
560
2.90k
    ~StringFileColumnIterator() override = default;
561
562
    Status init(const ColumnIteratorOptions& opts) override;
563
564
    Status set_access_paths(const TColumnAccessPaths& all_access_paths,
565
                            const TColumnAccessPaths& predicate_access_paths) override;
566
};
567
568
// This iterator make offset operation write once for
569
class OffsetFileColumnIterator final : public ColumnIterator {
570
public:
571
325
    explicit OffsetFileColumnIterator(FileColumnIteratorUPtr offset_reader) {
572
325
        _offset_iterator = std::move(offset_reader);
573
325
    }
574
575
325
    ~OffsetFileColumnIterator() override = default;
576
577
    Status init(const ColumnIteratorOptions& opts) override;
578
579
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override;
580
581
0
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
582
0
        bool has_null;
583
0
        return next_batch(n, dst, &has_null);
584
0
    }
585
586
0
    ordinal_t get_current_ordinal() const override {
587
0
        return _offset_iterator->get_current_ordinal();
588
0
    }
589
317
    Status seek_to_ordinal(ordinal_t ord) override {
590
317
        RETURN_IF_ERROR(_offset_iterator->seek_to_ordinal(ord));
591
317
        return Status::OK();
592
317
    }
593
594
    Status _peek_one_offset(ordinal_t* offset);
595
596
    Status _calculate_offsets(ssize_t start, ColumnArray::ColumnOffsets& column_offsets);
597
598
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
599
48
                          MutableColumnPtr& dst) override {
600
48
        return _offset_iterator->read_by_rowids(rowids, count, dst);
601
48
    }
602
603
    Status init_prefetcher(const SegmentPrefetchParams& params) override;
604
    void collect_prefetchers(
605
            std::map<PrefetcherInitMethod, std::vector<SegmentPrefetcher*>>& prefetchers,
606
            PrefetcherInitMethod init_method) override;
607
608
private:
609
    std::unique_ptr<FileColumnIterator> _offset_iterator;
610
    // reuse a tiny column for peek to avoid frequent allocations
611
    MutableColumnPtr _peek_tmp_col;
612
};
613
614
// This iterator is used to read map value column
615
class MapFileColumnIterator final : public ColumnIterator {
616
public:
617
    explicit MapFileColumnIterator(std::shared_ptr<ColumnReader> reader,
618
                                   ColumnIteratorUPtr null_iterator,
619
                                   OffsetFileColumnIteratorUPtr offsets_iterator,
620
                                   ColumnIteratorUPtr key_iterator,
621
                                   ColumnIteratorUPtr val_iterator);
622
623
292
    ~MapFileColumnIterator() override = default;
624
625
    Status init(const ColumnIteratorOptions& opts) override;
626
627
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override;
628
629
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
630
                          MutableColumnPtr& dst) override;
631
632
    Status seek_to_ordinal(ordinal_t ord) override;
633
634
0
    ordinal_t get_current_ordinal() const override {
635
0
        if (read_null_map_only() && _null_iterator) {
636
0
            return _null_iterator->get_current_ordinal();
637
0
        }
638
0
        return _offsets_iterator->get_current_ordinal();
639
0
    }
640
    Status init_prefetcher(const SegmentPrefetchParams& params) override;
641
    void collect_prefetchers(
642
            std::map<PrefetcherInitMethod, std::vector<SegmentPrefetcher*>>& prefetchers,
643
            PrefetcherInitMethod init_method) override;
644
645
    Status set_access_paths(const TColumnAccessPaths& all_access_paths,
646
                            const TColumnAccessPaths& predicate_access_paths) override;
647
648
    void set_need_to_read() override;
649
650
    void remove_pruned_sub_iterators() override;
651
652
private:
653
    std::shared_ptr<ColumnReader> _map_reader = nullptr;
654
    ColumnIteratorUPtr _null_iterator;
655
    OffsetFileColumnIteratorUPtr _offsets_iterator; //OffsetFileIterator
656
    ColumnIteratorUPtr _key_iterator;
657
    ColumnIteratorUPtr _val_iterator;
658
};
659
660
class StructFileColumnIterator final : public ColumnIterator {
661
public:
662
    explicit StructFileColumnIterator(std::shared_ptr<ColumnReader> reader,
663
                                      ColumnIteratorUPtr null_iterator,
664
                                      std::vector<ColumnIteratorUPtr>&& sub_column_iterators);
665
666
4
    ~StructFileColumnIterator() override = default;
667
668
    Status init(const ColumnIteratorOptions& opts) override;
669
670
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override;
671
672
0
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
673
0
        bool has_null;
674
0
        return next_batch(n, dst, &has_null);
675
0
    }
676
677
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
678
                          MutableColumnPtr& dst) override;
679
680
    Status seek_to_ordinal(ordinal_t ord) override;
681
682
0
    ordinal_t get_current_ordinal() const override {
683
0
        if (read_null_map_only() && _null_iterator) {
684
0
            return _null_iterator->get_current_ordinal();
685
0
        }
686
0
        return _sub_column_iterators[0]->get_current_ordinal();
687
0
    }
688
689
    Status set_access_paths(const TColumnAccessPaths& all_access_paths,
690
                            const TColumnAccessPaths& predicate_access_paths) override;
691
692
    void set_need_to_read() override;
693
694
    void remove_pruned_sub_iterators() override;
695
696
    Status init_prefetcher(const SegmentPrefetchParams& params) override;
697
    void collect_prefetchers(
698
            std::map<PrefetcherInitMethod, std::vector<SegmentPrefetcher*>>& prefetchers,
699
            PrefetcherInitMethod init_method) override;
700
701
private:
702
    std::shared_ptr<ColumnReader> _struct_reader = nullptr;
703
    ColumnIteratorUPtr _null_iterator;
704
    std::vector<ColumnIteratorUPtr> _sub_column_iterators;
705
};
706
707
class ArrayFileColumnIterator final : public ColumnIterator {
708
public:
709
    explicit ArrayFileColumnIterator(std::shared_ptr<ColumnReader> reader,
710
                                     OffsetFileColumnIteratorUPtr offset_reader,
711
                                     ColumnIteratorUPtr item_iterator,
712
                                     ColumnIteratorUPtr null_iterator);
713
714
31
    ~ArrayFileColumnIterator() override = default;
715
716
    Status init(const ColumnIteratorOptions& opts) override;
717
718
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override;
719
720
12
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
721
12
        bool has_null;
722
12
        return next_batch(n, dst, &has_null);
723
12
    }
724
725
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
726
                          MutableColumnPtr& dst) override;
727
728
    Status seek_to_ordinal(ordinal_t ord) override;
729
730
0
    ordinal_t get_current_ordinal() const override {
731
0
        if (read_null_map_only() && _null_iterator) {
732
0
            return _null_iterator->get_current_ordinal();
733
0
        }
734
0
        return _offset_iterator->get_current_ordinal();
735
0
    }
736
737
    Status set_access_paths(const TColumnAccessPaths& all_access_paths,
738
                            const TColumnAccessPaths& predicate_access_paths) override;
739
    void set_need_to_read() override;
740
741
    void remove_pruned_sub_iterators() override;
742
743
    Status init_prefetcher(const SegmentPrefetchParams& params) override;
744
    void collect_prefetchers(
745
            std::map<PrefetcherInitMethod, std::vector<SegmentPrefetcher*>>& prefetchers,
746
            PrefetcherInitMethod init_method) override;
747
748
private:
749
    std::shared_ptr<ColumnReader> _array_reader = nullptr;
750
    std::unique_ptr<OffsetFileColumnIterator> _offset_iterator;
751
    std::unique_ptr<ColumnIterator> _null_iterator;
752
    std::unique_ptr<ColumnIterator> _item_iterator;
753
754
    Status _seek_by_offsets(ordinal_t ord);
755
};
756
757
class RowIdColumnIterator : public ColumnIterator {
758
public:
759
    RowIdColumnIterator() = delete;
760
    RowIdColumnIterator(int64_t tid, RowsetId rid, int32_t segid)
761
0
            : _tablet_id(tid), _rowset_id(rid), _segment_id(segid) {}
762
763
0
    Status seek_to_ordinal(ordinal_t ord_idx) override {
764
0
        _current_rowid = cast_set<uint32_t>(ord_idx);
765
0
        return Status::OK();
766
0
    }
767
768
0
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
769
0
        bool has_null;
770
0
        return next_batch(n, dst, &has_null);
771
0
    }
772
773
0
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override {
774
0
        for (size_t i = 0; i < *n; ++i) {
775
0
            const auto row_id = cast_set<uint32_t>(_current_rowid + i);
776
0
            GlobalRowLoacation location(_tablet_id, _rowset_id, _segment_id, row_id);
777
0
            dst->insert_data(reinterpret_cast<const char*>(&location), sizeof(GlobalRowLoacation));
778
0
        }
779
0
        _current_rowid += *n;
780
0
        return Status::OK();
781
0
    }
782
783
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
784
0
                          MutableColumnPtr& dst) override {
785
0
        for (size_t i = 0; i < count; ++i) {
786
0
            rowid_t row_id = rowids[i];
787
0
            GlobalRowLoacation location(_tablet_id, _rowset_id, _segment_id, row_id);
788
0
            dst->insert_data(reinterpret_cast<const char*>(&location), sizeof(GlobalRowLoacation));
789
0
        }
790
0
        return Status::OK();
791
0
    }
792
793
0
    ordinal_t get_current_ordinal() const override { return _current_rowid; }
794
795
private:
796
    rowid_t _current_rowid = 0;
797
    int64_t _tablet_id = 0;
798
    RowsetId _rowset_id;
799
    int32_t _segment_id = 0;
800
};
801
802
// Add new RowIdColumnIteratorV2
803
class RowIdColumnIteratorV2 : public ColumnIterator {
804
public:
805
    RowIdColumnIteratorV2(uint8_t version, int64_t backend_id, uint32_t file_id)
806
16
            : _version(version), _backend_id(backend_id), _file_id(file_id) {}
807
808
0
    Status seek_to_ordinal(ordinal_t ord_idx) override {
809
0
        _current_rowid = cast_set<uint32_t>(ord_idx);
810
0
        return Status::OK();
811
0
    }
812
813
0
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
814
0
        bool has_null;
815
0
        return next_batch(n, dst, &has_null);
816
0
    }
817
818
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override;
819
820
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
821
                          MutableColumnPtr& dst) override;
822
823
0
    ordinal_t get_current_ordinal() const override { return _current_rowid; }
824
825
private:
826
    uint32_t _current_rowid = 0;
827
    uint8_t _version;
828
    int64_t _backend_id;
829
    uint32_t _file_id;
830
};
831
832
// This iterator is used to read default value column
833
class DefaultValueColumnIterator : public ColumnIterator {
834
public:
835
    DefaultValueColumnIterator(bool has_default_value, std::string default_value, bool is_nullable,
836
                               FieldType type, int precision, int scale, int len)
837
14
            : _has_default_value(has_default_value),
838
14
              _default_value(std::move(default_value)),
839
14
              _is_nullable(is_nullable),
840
14
              _type(type),
841
14
              _precision(precision),
842
14
              _scale(scale),
843
14
              _len(len) {}
844
845
    Status init(const ColumnIteratorOptions& opts) override;
846
847
8
    Status seek_to_ordinal(ordinal_t ord_idx) override {
848
8
        _current_rowid = ord_idx;
849
8
        return Status::OK();
850
8
    }
851
852
0
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
853
0
        bool has_null;
854
0
        return next_batch(n, dst, &has_null);
855
0
    }
856
857
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override;
858
859
0
    Status next_batch_of_zone_map(size_t* n, MutableColumnPtr& dst) override {
860
0
        return next_batch(n, dst);
861
0
    }
862
863
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
864
                          MutableColumnPtr& dst) override;
865
866
0
    ordinal_t get_current_ordinal() const override { return _current_rowid; }
867
868
private:
869
    void _insert_many_default(MutableColumnPtr& dst, size_t n);
870
871
    bool _has_default_value;
872
    std::string _default_value;
873
    bool _is_nullable;
874
    FieldType _type;
875
    int _precision;
876
    int _scale;
877
    const int _len;
878
    Field _default_value_field;
879
880
    // current rowid
881
    ordinal_t _current_rowid = 0;
882
};
883
884
// Produces a column whose every row is the same constant Field value.
885
// Used for read-time-filled constant hidden columns (e.g. __DORIS_COMMIT_TSO_COL__),
886
// where the on-disk value is only a placeholder and the real value comes from the read
887
// context (StorageReadOptions).
888
class ConstantColumnIterator : public ColumnIterator {
889
public:
890
    ConstantColumnIterator() = delete;
891
5
    explicit ConstantColumnIterator(Field value) : _value(std::move(value)) {}
892
893
1
    Status seek_to_ordinal(ordinal_t ord_idx) override {
894
1
        _current_rowid = ord_idx;
895
1
        return Status::OK();
896
1
    }
897
898
1
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
899
1
        bool has_null;
900
1
        return next_batch(n, dst, &has_null);
901
1
    }
902
903
4
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override {
904
4
        *has_null = _value.is_null();
905
4
        Status st = _insert_many(dst, *n);
906
4
        if (!st.ok()) {
907
0
            return st;
908
0
        }
909
4
        _current_rowid += *n;
910
4
        return st;
911
4
    }
912
913
1
    Status next_batch_of_zone_map(size_t* n, MutableColumnPtr& dst) override {
914
1
        return next_batch(n, dst);
915
1
    }
916
917
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
918
1
                          MutableColumnPtr& dst) override {
919
1
        return _insert_many(dst, count);
920
1
    }
921
922
3
    ordinal_t get_current_ordinal() const override { return _current_rowid; }
923
924
private:
925
5
    Status _insert_many(MutableColumnPtr& dst, size_t n) {
926
5
        if (_value.is_null()) {
927
1
            if (UNLIKELY(!dst->is_nullable())) {
928
0
                return Status::InternalError(
929
0
                        "try to apply constant null value to not nullable target column");
930
0
            }
931
1
            dst->insert_many_defaults(n);
932
1
            return Status::OK();
933
1
        }
934
4
        dst->insert_duplicate_fields(_value, n);
935
4
        return Status::OK();
936
5
    }
937
938
    Field _value;
939
    ordinal_t _current_rowid = 0;
940
};
941
942
// A ColumnReader that represents a single constant value for the whole segment instead of reading
943
// on-disk data. Used for read-time-filled constant columns (e.g. __DORIS_COMMIT_TSO_COL__) on a
944
// single-version segment, whose on-disk zonemap only reflects the placeholder. It advertises a
945
// single-value [v, v] zonemap so segment-level pruning matches against the real value, and produces
946
// a ConstantColumnIterator for data reads.
947
class ConstantColumnReader : public ColumnReader {
948
public:
949
0
    explicit ConstantColumnReader(Field value) : _value(std::move(value)) {}
950
951
0
    bool has_zone_map() const override { return true; }
952
953
    // The base ColumnReader default-constructs without initializing its _meta_type. The data-read
954
    // path (Segment::new_column_iterator) verifies tablet_column.type() == reader->get_meta_type()
955
    // when config::enable_column_type_check is on (default true), so derive the real OLAP type from
956
    // the constant value to avoid a spurious "different type between schema and column reader" error.
957
0
    FieldType get_meta_type() override {
958
0
        return TabletColumn::get_field_type_by_type(_value.get_type());
959
0
    }
960
961
    Status match_condition(const AndBlockColumnPredicate* col_predicates,
962
                           bool* matched) const override;
963
964
    Status new_iterator(ColumnIteratorUPtr* iterator, const TabletColumn* /*col*/,
965
0
                        const StorageReadOptions* /*opt*/) override {
966
0
        *iterator = std::make_unique<ConstantColumnIterator>(_value);
967
0
        return Status::OK();
968
0
    }
969
970
private:
971
    Field _value;
972
};
973
974
} // namespace segment_v2
975
} // namespace doris