Coverage Report

Created: 2026-08-25 18:04

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 <glog/logging.h>
23
#include <sys/types.h>
24
25
#include <cstddef> // for size_t
26
#include <cstdint> // for uint32_t
27
#include <map>
28
#include <memory> // for unique_ptr
29
#include <optional>
30
#include <string>
31
#include <utility>
32
#include <vector>
33
34
#include "common/compiler_util.h"
35
#include "common/config.h"
36
#include "common/logging.h"
37
#include "common/status.h"            // for Status
38
#include "core/column/column_array.h" // ColumnArray
39
#include "core/data_type/data_type.h"
40
#include "core/data_type/storage_field_type.h"
41
#include "io/cache/cached_remote_file_reader.h"
42
#include "io/fs/file_reader_writer_fwd.h"
43
#include "io/io_common.h"
44
#include "storage/index/index_reader.h"
45
#include "storage/index/ordinal_page_index.h" // for OrdinalPageIndexIterator
46
#include "storage/index/zone_map/zone_map_index.h"
47
#include "storage/olap_common.h"
48
#include "storage/predicate/column_predicate.h"
49
#include "storage/segment/common.h"
50
#include "storage/segment/page_handle.h" // for PageHandle
51
#include "storage/segment/page_pointer.h"
52
#include "storage/segment/parsed_page.h" // for ParsedPage
53
#include "storage/segment/row_ranges.h"
54
#include "storage/segment/segment_prefetcher.h"
55
#include "storage/segment/stream_reader.h"
56
#include "storage/tablet/tablet_schema.h"
57
#include "storage/types.h"
58
#include "storage/utils.h"
59
#include "util/once.h"
60
61
namespace doris {
62
63
class BlockCompressionCodec;
64
class AndBlockColumnPredicate;
65
class ColumnPredicate;
66
class TabletIndex;
67
class StorageReadOptions;
68
69
namespace io {
70
class FileReader;
71
} // namespace io
72
struct Slice;
73
struct StringRef;
74
75
using TColumnAccessPaths = std::vector<TColumnAccessPath>;
76
77
namespace segment_v2 {
78
class EncodingInfo;
79
class ColumnIterator;
80
class BloomFilterIndexReader;
81
class InvertedIndexIterator;
82
class InvertedIndexReader;
83
class IndexFileReader;
84
class PageDecoder;
85
class RowRanges;
86
class ZoneMapIndexReader;
87
class IndexIterator;
88
class ColumnMetaAccessor;
89
90
struct ColumnReaderOptions {
91
    // whether verify checksum when read page
92
    bool verify_checksum = true;
93
    // for in memory olap table, use DURABLE CachePriority in page cache
94
    bool kept_in_memory = false;
95
96
    int be_exec_version = -1;
97
98
    TabletSchemaSPtr tablet_schema = nullptr;
99
100
    // When set, ColumnReader::create returns a ConstantColumnReader carrying this value instead
101
    // of reading on-disk data. Used for read-time-filled constant columns (e.g.
102
    // __DORIS_COMMIT_TSO_COL__) on a single-version segment, whose on-disk value is only a
103
    // placeholder. The value is constant within a segment, so the resulting reader is cacheable.
104
};
105
106
struct ColumnIteratorOptions {
107
    bool use_page_cache = false;
108
    bool is_predicate_column = false;
109
    // for page cache allocation
110
    // page types are divided into DATA_PAGE & INDEX_PAGE
111
    // INDEX_PAGE including index_page, dict_page and short_key_page
112
    PageTypePB type = PageTypePB::UNKNOWN_PAGE_TYPE;
113
    io::FileReader* file_reader = nullptr; // Ref
114
    // reader statistics
115
    OlapReaderStatistics* stats = nullptr; // Ref
116
    io::IOContext io_ctx;
117
    bool only_read_offsets = false;
118
119
31.3k
    void sanity_check() const {
120
31.3k
        CHECK_NOTNULL(file_reader);
121
31.3k
        CHECK_NOTNULL(stats);
122
31.3k
    }
123
};
124
125
class ColumnIterator;
126
class OffsetFileColumnIterator;
127
class FileColumnIterator;
128
129
using ColumnIteratorUPtr = std::unique_ptr<ColumnIterator>;
130
using OffsetFileColumnIteratorUPtr = std::unique_ptr<OffsetFileColumnIterator>;
131
using FileColumnIteratorUPtr = std::unique_ptr<FileColumnIterator>;
132
using ColumnIteratorSPtr = std::shared_ptr<ColumnIterator>;
133
134
// There will be concurrent users to read the same column. So
135
// we should do our best to reduce resource usage through share
136
// same information, such as OrdinalPageIndex and Page data.
137
// This will cache data shared by all reader
138
class ColumnReader : public MetadataAdder<ColumnReader>,
139
                     public std::enable_shared_from_this<ColumnReader> {
140
public:
141
    ColumnReader();
142
    // Create an initialized ColumnReader in *reader.
143
    // This should be a lightweight operation without I/O.
144
    static Status create(const ColumnReaderOptions& opts, const ColumnMetaPB& meta,
145
                         uint64_t num_rows, const io::FileReaderSPtr& file_reader,
146
                         std::shared_ptr<ColumnReader>* reader);
147
148
    static Status create_array(const ColumnReaderOptions& opts, const ColumnMetaPB& meta,
149
                               const io::FileReaderSPtr& file_reader,
150
                               std::shared_ptr<ColumnReader>* reader);
151
    static Status create_map(const ColumnReaderOptions& opts, const ColumnMetaPB& meta,
152
                             const io::FileReaderSPtr& file_reader,
153
                             std::shared_ptr<ColumnReader>* reader);
154
    static Status create_struct(const ColumnReaderOptions& opts, const ColumnMetaPB& meta,
155
                                uint64_t num_rows, const io::FileReaderSPtr& file_reader,
156
                                std::shared_ptr<ColumnReader>* reader);
157
    static Status create_agg_state(const ColumnReaderOptions& opts, const ColumnMetaPB& meta,
158
                                   uint64_t num_rows, const io::FileReaderSPtr& file_reader,
159
                                   std::shared_ptr<ColumnReader>* reader);
160
161
    enum DictEncodingType { UNKNOWN_DICT_ENCODING, PARTIAL_DICT_ENCODING, ALL_DICT_ENCODING };
162
163
    static bool is_compaction_reader_type(ReaderType type);
164
165
    ~ColumnReader() override;
166
167
    // create a new column iterator. Client should delete returned iterator
168
    virtual Status new_iterator(ColumnIteratorUPtr* iterator, const TabletColumn* col,
169
                                const StorageReadOptions*);
170
    Status new_iterator(ColumnIteratorUPtr* iterator, const TabletColumn* tablet_column);
171
    Status new_array_iterator(ColumnIteratorUPtr* iterator, const TabletColumn* tablet_column);
172
    Status new_struct_iterator(ColumnIteratorUPtr* iterator, const TabletColumn* tablet_column);
173
    Status new_map_iterator(ColumnIteratorUPtr* iterator, const TabletColumn* tablet_column);
174
    Status new_agg_state_iterator(ColumnIteratorUPtr* iterator);
175
176
    Status new_index_iterator(const std::shared_ptr<IndexFileReader>& index_file_reader,
177
                              const TabletIndex* index_meta, const std::string& rowset_id,
178
                              uint32_t segment_id, size_t rows_of_segment,
179
                              std::unique_ptr<IndexIterator>* iterator);
180
181
    Status seek_at_or_before(ordinal_t ordinal, OrdinalPageIndexIterator* iter,
182
                             const ColumnIteratorOptions& iter_opts);
183
    Status get_ordinal_index_reader(OrdinalIndexReader*& reader,
184
                                    OlapReaderStatistics* index_load_stats);
185
186
    // read a page from file into a page handle
187
    Status read_page(const ColumnIteratorOptions& iter_opts, const PagePointer& pp,
188
                     PageHandle* handle, Slice* page_body, PageFooterPB* footer,
189
                     BlockCompressionCodec* codec) const;
190
191
5.83k
    bool is_nullable() const { return _meta_is_nullable; }
192
193
169k
    const EncodingInfo* encoding_info() const { return _encoding_info; }
194
195
8.71k
    virtual bool has_zone_map() const { return _zone_map_index != nullptr; }
196
    bool has_bloom_filter_index(bool ngram) const;
197
    Status next_batch_of_zone_map(size_t* n, MutableColumnPtr& dst) const;
198
199
    // How many page zone maps this column has, loading the indexes they need. Reports 0 when the
200
    // column has no zone map. Call this before get_page_zone_map().
201
    Status get_page_zone_map_count(const ColumnIteratorOptions& iter_opts, size_t* count);
202
203
    // One page: the rows it covers and its decoded zone map.
204
    Status get_page_zone_map(size_t page_index, RowRange* rows, segment_v2::ZoneMap* zone_map);
205
206
    // get row ranges with bloom filter index
207
    Status get_row_ranges_by_bloom_filter(const AndBlockColumnPredicate* col_predicates,
208
                                          RowRanges* row_ranges,
209
                                          const ColumnIteratorOptions& iter_opts);
210
211
8.43k
    PagePointer get_dict_page_pointer() const { return _meta_dict_page; }
212
213
131k
    bool is_empty() const { return _num_rows == 0; }
214
215
    // The one zone map that covers this whole segment. Callers judge it themselves.
216
    virtual Status get_segment_zone_map(segment_v2::ZoneMap* zone_map) const;
217
218
127k
    CompressionTypePB get_compression() const { return _meta_compression; }
219
220
6.57k
    uint64_t num_rows() const { return _num_rows; }
221
222
118
    void set_dict_encoding_type(DictEncodingType type) {
223
118
        static_cast<void>(_set_dict_encoding_type_once.call([&] {
224
118
            _dict_encoding_type = type;
225
118
            return Status::OK();
226
118
        }));
227
118
    }
228
229
69.8k
    DictEncodingType get_dict_encoding_type() { return _dict_encoding_type; }
230
231
127k
    void disable_index_meta_cache() { _use_index_page_cache = false; }
232
233
563
    DataTypePtr get_vec_data_type() { return _data_type; }
234
235
263k
    virtual FieldType get_meta_type() { return _meta_type; }
236
237
    int64_t get_metadata_size() const override;
238
239
#ifdef BE_TEST
240
    void check_data_by_zone_map_for_test(const MutableColumnPtr& dst) const;
241
#endif
242
243
private:
244
    friend class VariantColumnReader;
245
    friend class FileColumnIterator;
246
    friend class SegmentPrefetcher;
247
248
    ColumnReader(const ColumnReaderOptions& opts, const ColumnMetaPB& meta, uint64_t num_rows,
249
                 io::FileReaderSPtr file_reader);
250
    Status init(const ColumnMetaPB* meta);
251
252
    [[nodiscard]] Status _load_zone_map_index(bool use_page_cache, bool kept_in_memory,
253
                                              const ColumnIteratorOptions& iter_opts);
254
    [[nodiscard]] Status _load_ordinal_index(bool use_page_cache, bool kept_in_memory,
255
                                             const ColumnIteratorOptions& iter_opts);
256
257
    [[nodiscard]] Status _load_index(const std::shared_ptr<IndexFileReader>& index_file_reader,
258
                                     const TabletIndex* index_meta, const std::string& rowset_id,
259
                                     uint32_t segment_id, size_t rows_of_segment);
260
    [[nodiscard]] Status _load_bloom_filter_index(bool use_page_cache, bool kept_in_memory,
261
                                                  const ColumnIteratorOptions& iter_opts);
262
263
    int64_t _meta_length;
264
    FieldType _meta_type;
265
    FieldType _meta_children_column_type;
266
    bool _meta_is_nullable;
267
    bool _use_index_page_cache;
268
    int _be_exec_version = -1;
269
270
    PagePointer _meta_dict_page;
271
    CompressionTypePB _meta_compression;
272
273
    ColumnReaderOptions _opts;
274
    uint64_t _num_rows;
275
276
    io::FileReaderSPtr _file_reader;
277
278
    DictEncodingType _dict_encoding_type;
279
280
    DataTypePtr _data_type;
281
282
    FieldType _type =
283
            FieldType::OLAP_FIELD_TYPE_NONE; // initialized in init(), may changed by subclasses.
284
    const EncodingInfo* _encoding_info =
285
            nullptr; // initialized in init(), used for create PageDecoder
286
287
    // meta for various column indexes (null if the index is absent)
288
    std::unique_ptr<ZoneMapPB> _segment_zone_map;
289
290
    mutable std::shared_mutex _load_index_lock;
291
    std::unique_ptr<ZoneMapIndexReader> _zone_map_index;
292
    std::unique_ptr<OrdinalIndexReader> _ordinal_index;
293
    std::shared_ptr<BloomFilterIndexReader> _bloom_filter_index;
294
295
    std::unordered_map<int64_t, IndexReaderPtr> _index_readers;
296
297
    std::vector<std::shared_ptr<ColumnReader>> _sub_readers;
298
299
    DorisCallOnce<Status> _set_dict_encoding_type_once;
300
};
301
302
// Base iterator to read one column data
303
class ColumnIterator {
304
public:
305
132k
    ColumnIterator() = default;
306
133k
    virtual ~ColumnIterator() = default;
307
308
486
    virtual Status init(const ColumnIteratorOptions& opts) {
309
486
        _opts = opts;
310
486
        return Status::OK();
311
486
    }
312
313
    // Seek to the given ordinal entry in the column.
314
    // Entry 0 is the first entry written to the column.
315
    // If provided seek point is past the end of the file,
316
    // then returns false.
317
    virtual Status seek_to_ordinal(ordinal_t ord) = 0;
318
319
36.9k
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
320
36.9k
        bool has_null;
321
36.9k
        return next_batch(n, dst, &has_null);
322
36.9k
    }
323
324
0
    virtual Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) {
325
0
        return Status::NotSupported("next_batch not implement");
326
0
    }
327
328
0
    virtual Status next_batch_of_zone_map(size_t* n, MutableColumnPtr& dst) {
329
0
        return Status::NotSupported("next_batch_of_zone_map not implement");
330
0
    }
331
332
    virtual Status read_by_rowids(const rowid_t* rowids, const size_t count,
333
0
                                  MutableColumnPtr& dst) {
334
0
        return Status::NotSupported("read_by_rowids not implement");
335
0
    }
336
337
    virtual ordinal_t get_current_ordinal() const = 0;
338
339
    // Page zone maps of the column this iterator reads. Iterators that resolve to another
340
    // reader (variant subcolumns) forward to it, so callers always reach the real zone map.
341
4
    virtual Status get_page_zone_map_count(size_t* count) {
342
4
        *count = 0;
343
4
        return Status::OK();
344
4
    }
345
346
    virtual Status get_page_zone_map(size_t page_index, RowRange* rows,
347
0
                                     segment_v2::ZoneMap* zone_map) {
348
0
        return Status::NotSupported("get_page_zone_map is not implemented");
349
0
    }
350
351
    virtual Status get_row_ranges_by_bloom_filter(const AndBlockColumnPredicate* col_predicates,
352
0
                                                  RowRanges* row_ranges) {
353
0
        return Status::OK();
354
0
    }
355
356
    virtual Status get_row_ranges_by_dict(const AndBlockColumnPredicate* col_predicates,
357
0
                                          RowRanges* row_ranges) {
358
0
        return Status::OK();
359
0
    }
360
361
0
    virtual bool is_all_dict_encoding() const { return false; }
362
363
    virtual Status set_access_paths(const TColumnAccessPaths& all_access_paths,
364
41
                                    const TColumnAccessPaths& predicate_access_paths) {
365
41
        if (!predicate_access_paths.empty()) {
366
15
            set_read_requirement_self(ReadRequirement::PREDICATE);
367
15
        }
368
41
        return Status::OK();
369
41
    }
370
371
131k
    void set_column_name(const std::string& column_name) { _column_name = column_name; }
372
373
141
    const std::string& column_name() const { return _column_name; }
374
375
    // Per-iterator read requirement derived from nested access paths.
376
    //
377
    // The ordering is intentional and used by set_read_requirement_self(): requirements are
378
    // monotonic and a weaker requirement must not downgrade a stronger one.
379
    // - NORMAL: no pruning decision has been made yet.
380
    // - SKIP: this iterator should not be read.
381
    // - LAZY_OUTPUT: materialize this iterator in the lazy phase after predicate filtering.
382
    // - PREDICATE: read this iterator in the predicate phase. This must stay stronger than
383
    //   LAZY_OUTPUT because parents may mark children as LAZY_OUTPUT after child set_access_paths()
384
    //   has already promoted predicate-only children to PREDICATE.
385
    enum class ReadRequirement : int { NORMAL, SKIP, LAZY_OUTPUT, PREDICATE };
386
387
    // Set the read requirement on this iterator and all nested child iterators.
388
150
    virtual void set_read_requirement(ReadRequirement requirement) {
389
150
        set_read_requirement_self(requirement);
390
150
    }
391
392
74
    ReadRequirement read_requirement() const { return _read_requirement; }
393
394
42
    virtual void set_lazy_output_requirement() {
395
42
        set_read_requirement(ReadRequirement::LAZY_OUTPUT);
396
42
    }
397
398
4
    virtual void remove_pruned_sub_iterators() {};
399
400
0
    virtual Status init_prefetcher(const SegmentPrefetchParams& params) { return Status::OK(); }
401
402
    virtual void collect_prefetchers(
403
            std::map<PrefetcherInitMethod, std::vector<SegmentPrefetcher*>>& prefetchers,
404
0
            PrefetcherInitMethod init_method) {}
405
406
    static constexpr const char* ACCESS_OFFSET = "OFFSET";
407
    static constexpr const char* ACCESS_ALL = "*";
408
    static constexpr const char* ACCESS_MAP_KEYS = "KEYS";
409
    static constexpr const char* ACCESS_MAP_VALUES = "VALUES";
410
    static constexpr const char* ACCESS_NULL = "NULL";
411
412
    // Meta-only read modes:
413
    // - OFFSET_ONLY: read offsets while skipping actual child/string data. For nullable
414
    //   complex columns, the parent null map is still materialized when needed.
415
    // - NULL_MAP_ONLY: only read null map (e.g., for IS NULL / IS NOT NULL predicates)
416
    // When these modes are enabled, actual content data is skipped.
417
    enum class MetaReadMode : int { DEFAULT, OFFSET_ONLY, NULL_MAP_ONLY };
418
419
76.0k
    bool read_offset_only() const { return _meta_read_mode == MetaReadMode::OFFSET_ONLY; }
420
48.8k
    bool read_null_map_only() const { return _meta_read_mode == MetaReadMode::NULL_MAP_ONLY; }
421
422
    // The current scanner phase. This is intentionally separate from ReadRequirement
423
    // (why this iterator is needed) and MetaReadMode (what physical metadata to read).
424
    enum class ReadPhase : int {
425
        NORMAL,    // default full materialization without lazy read split
426
        PREDICATE, // predicate evaluation before row filtering
427
        LAZY       // post-filter lazy materialization
428
    };
429
430
264k
    virtual void set_read_phase(ReadPhase mode) {
431
264k
        _read_phase = mode;
432
264k
        if (mode == ReadPhase::PREDICATE) {
433
46
            _has_place_holder_column = false;
434
46
        }
435
264k
    }
436
437
96.3k
    virtual bool need_to_read() const {
438
96.3k
        switch (_read_phase) {
439
96.3k
        case ReadPhase::NORMAL:
440
96.3k
            return _read_requirement != ReadRequirement::SKIP;
441
19
        case ReadPhase::PREDICATE:
442
19
            return _read_requirement == ReadRequirement::PREDICATE;
443
23
        case ReadPhase::LAZY:
444
23
            return _read_requirement == ReadRequirement::LAZY_OUTPUT;
445
0
        default:
446
0
            return false;
447
96.3k
        }
448
96.3k
    }
449
450
    // Whether the current iterator itself should materialize meta columns, such as
451
    // the null-map column or the offset column, into the destination column.
452
    //
453
    // Do not use the virtual need_to_read() here. Complex iterators override
454
    // need_to_read() in LAZY mode to keep the parent iterator active when only a
455
    // nested child still has data to materialize. That parent-level control-flow
456
    // decision is different from materializing the parent's own offsets/null-map:
457
    // if the parent was already read for predicate evaluation, LAZY mode should
458
    // only fill the missing children and must not append parent meta again.
459
654
    bool need_to_read_meta_columns() const { return ColumnIterator::need_to_read(); }
460
461
5
    virtual void finalize_lazy_phase(MutableColumnPtr& dst) {
462
5
        _recovery_from_place_holder_column(dst);
463
5
    }
464
465
    // Set only this iterator's requirement without modifying requirements of any nested child
466
    // iterators. Use this when the parent/wrapper state must be updated while child requirements
467
    // are decided independently.
468
443
    virtual void set_read_requirement_self(ReadRequirement requirement) {
469
443
        if (static_cast<int>(requirement) > static_cast<int>(_read_requirement)) {
470
271
            _read_requirement = requirement;
471
271
        }
472
443
    }
473
474
    // Whether this iterator or any nested iterator has data that must be materialized
475
    // in lazy mode. Predicate-only branches are read before filtering and must not be
476
    // re-read in the lazy phase. Meta-only access paths still become lazy targets when
477
    // they appear only in all_access_paths, because OFFSET/NULL is the requested output.
478
76
    virtual bool has_lazy_read_target() const {
479
76
        return _read_requirement == ReadRequirement::LAZY_OUTPUT;
480
76
    }
481
482
protected:
483
    void _convert_to_place_holder_column(MutableColumnPtr& dst, size_t count);
484
485
    void _recovery_from_place_holder_column(MutableColumnPtr& dst);
486
487
    // Derive current-level meta-only read mode from access paths. Meta-only is valid only when
488
    // this iterator had no data-read requirement before applying the current paths, and every
489
    // visible path at this level is NULL/OFFSET metadata.
490
    void _check_and_set_meta_read_mode(ReadRequirement requirement_before_access_path,
491
                                       const TColumnAccessPaths& sub_all_access_paths);
492
493
    Result<TColumnAccessPaths> _get_sub_access_paths(TColumnAccessPaths access_paths,
494
                                                     bool is_predicate = false);
495
    ColumnIteratorOptions _opts;
496
497
    ReadRequirement _read_requirement {ReadRequirement::NORMAL};
498
    MetaReadMode _meta_read_mode = MetaReadMode::DEFAULT;
499
    ReadPhase _read_phase {ReadPhase::NORMAL};
500
    std::string _column_name;
501
502
    bool _has_place_holder_column {false};
503
};
504
505
// This iterator is used to read column data from file
506
// for scalar type
507
class FileColumnIterator : public ColumnIterator {
508
public:
509
    explicit FileColumnIterator(std::shared_ptr<ColumnReader> reader);
510
    ~FileColumnIterator() override;
511
512
    Status init(const ColumnIteratorOptions& opts) override;
513
514
    Status seek_to_ordinal(ordinal_t ord) override;
515
516
    Status seek_to_page_start();
517
518
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override;
519
520
    Status next_batch_of_zone_map(size_t* n, MutableColumnPtr& dst) override;
521
522
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
523
                          MutableColumnPtr& dst) override;
524
525
2
    ordinal_t get_current_ordinal() const override { return _current_ordinal; }
526
527
    Status get_page_zone_map_count(size_t* count) override;
528
529
    Status get_page_zone_map(size_t page_index, RowRange* rows,
530
                             segment_v2::ZoneMap* zone_map) override;
531
532
    Status get_row_ranges_by_bloom_filter(const AndBlockColumnPredicate* col_predicates,
533
                                          RowRanges* row_ranges) override;
534
535
    Status get_row_ranges_by_dict(const AndBlockColumnPredicate* col_predicates,
536
                                  RowRanges* row_ranges) override;
537
538
2.40k
    ParsedPage* get_current_page() { return &_page; }
539
540
0
    bool is_nullable() { return _reader->is_nullable(); }
541
542
23
    bool is_all_dict_encoding() const override { return _is_all_dict_encoding; }
543
544
    Status init_prefetcher(const SegmentPrefetchParams& params) override;
545
    void collect_prefetchers(
546
            std::map<PrefetcherInitMethod, std::vector<SegmentPrefetcher*>>& prefetchers,
547
            PrefetcherInitMethod init_method) override;
548
549
protected:
550
    // Exposed to derived iterators (e.g. StringFileColumnIterator) so they can
551
    // query column metadata such as the storage field type.
552
4
    const std::shared_ptr<ColumnReader>& get_reader() const { return _reader; }
553
554
private:
555
    Status _seek_to_pos_in_page(ParsedPage* page, ordinal_t offset_in_page) const;
556
    Status _load_next_page(bool* eos);
557
    Status _read_data_page(const OrdinalPageIndexIterator& iter);
558
    Status _read_dict_data();
559
    void _trigger_prefetch_if_eligible(ordinal_t ord);
560
561
    std::shared_ptr<ColumnReader> _reader = nullptr;
562
563
    BlockCompressionCodec* _compress_codec = nullptr;
564
565
    // 1. The _page represents current page.
566
    // 2. We define an operation is one seek and following read,
567
    //    If new seek is issued, the _page will be reset.
568
    ParsedPage _page;
569
570
    // keep dict page decoder
571
    std::unique_ptr<PageDecoder> _dict_decoder;
572
573
    // keep dict page handle to avoid released
574
    PageHandle _dict_page_handle;
575
576
    // page iterator used to get next page when current page is finished.
577
    // This value will be reset when a new seek is issued
578
    OrdinalPageIndexIterator _page_iter;
579
580
    // current value ordinal
581
    ordinal_t _current_ordinal = 0;
582
583
    bool _is_all_dict_encoding = false;
584
585
    std::unique_ptr<StringRef[]> _dict_word_info;
586
587
    bool _enable_prefetch {false};
588
    std::unique_ptr<SegmentPrefetcher> _prefetcher;
589
    std::shared_ptr<io::CachedRemoteFileReader> _cached_remote_file_reader {nullptr};
590
};
591
592
class EmptyFileColumnIterator final : public ColumnIterator {
593
public:
594
330
    Status seek_to_ordinal(ordinal_t ord) override { return Status::OK(); }
595
0
    ordinal_t get_current_ordinal() const override { return 0; }
596
};
597
598
// StringFileColumnIterator extends FileColumnIterator with meta-only reading
599
// support for string/binary column types. When the OFFSET path is detected in
600
// set_access_paths, it sets only_read_offsets on the ColumnIteratorOptions so
601
// that the BinaryPlainPageDecoder skips chars memcpy and only fills offsets.
602
class StringFileColumnIterator final : public FileColumnIterator {
603
public:
604
    explicit StringFileColumnIterator(std::shared_ptr<ColumnReader> reader);
605
    ~StringFileColumnIterator() override = default;
606
607
    Status init(const ColumnIteratorOptions& opts) override;
608
609
    Status set_access_paths(const TColumnAccessPaths& all_access_paths,
610
                            const TColumnAccessPaths& predicate_access_paths) override;
611
};
612
613
// This iterator make offset operation write once for
614
class OffsetFileColumnIterator final : public ColumnIterator {
615
public:
616
670
    explicit OffsetFileColumnIterator(FileColumnIteratorUPtr offset_reader) {
617
670
        _offset_iterator = std::move(offset_reader);
618
670
    }
619
620
670
    ~OffsetFileColumnIterator() override = default;
621
622
    Status init(const ColumnIteratorOptions& opts) override;
623
624
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override;
625
626
0
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
627
0
        bool has_null;
628
0
        return next_batch(n, dst, &has_null);
629
0
    }
630
631
0
    ordinal_t get_current_ordinal() const override {
632
0
        return _offset_iterator->get_current_ordinal();
633
0
    }
634
615
    Status seek_to_ordinal(ordinal_t ord) override {
635
615
        RETURN_IF_ERROR(_offset_iterator->seek_to_ordinal(ord));
636
615
        return Status::OK();
637
615
    }
638
639
    Status _peek_one_offset(ordinal_t* offset);
640
641
    Status _calculate_offsets(ssize_t start, ColumnArray::ColumnOffsets& column_offsets);
642
643
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
644
98
                          MutableColumnPtr& dst) override {
645
98
        return _offset_iterator->read_by_rowids(rowids, count, dst);
646
98
    }
647
648
0
    void set_read_requirement(ReadRequirement requirement) override {
649
0
        set_read_requirement_self(requirement);
650
0
        _offset_iterator->set_read_requirement(requirement);
651
0
    }
652
653
    Status init_prefetcher(const SegmentPrefetchParams& params) override;
654
    void collect_prefetchers(
655
            std::map<PrefetcherInitMethod, std::vector<SegmentPrefetcher*>>& prefetchers,
656
            PrefetcherInitMethod init_method) override;
657
658
private:
659
    std::unique_ptr<FileColumnIterator> _offset_iterator;
660
    // reuse a tiny column for peek to avoid frequent allocations
661
    MutableColumnPtr _peek_tmp_col;
662
};
663
664
// This iterator is used to read map value column
665
class MapFileColumnIterator final : public ColumnIterator {
666
public:
667
    explicit MapFileColumnIterator(std::shared_ptr<ColumnReader> reader,
668
                                   ColumnIteratorUPtr null_iterator,
669
                                   OffsetFileColumnIteratorUPtr offsets_iterator,
670
                                   ColumnIteratorUPtr key_iterator,
671
                                   ColumnIteratorUPtr val_iterator);
672
673
560
    ~MapFileColumnIterator() override = default;
674
675
    Status init(const ColumnIteratorOptions& opts) override;
676
677
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override;
678
679
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
680
                          MutableColumnPtr& dst) override;
681
682
    Status seek_to_ordinal(ordinal_t ord) override;
683
684
0
    ordinal_t get_current_ordinal() const override {
685
0
        if (read_null_map_only() && _null_iterator) {
686
0
            return _null_iterator->get_current_ordinal();
687
0
        }
688
0
        return _offsets_iterator->get_current_ordinal();
689
0
    }
690
    Status init_prefetcher(const SegmentPrefetchParams& params) override;
691
    void collect_prefetchers(
692
            std::map<PrefetcherInitMethod, std::vector<SegmentPrefetcher*>>& prefetchers,
693
            PrefetcherInitMethod init_method) override;
694
695
    Status set_access_paths(const TColumnAccessPaths& all_access_paths,
696
                            const TColumnAccessPaths& predicate_access_paths) override;
697
698
    void set_lazy_output_requirement() override;
699
700
    void remove_pruned_sub_iterators() override;
701
702
    void set_read_phase(ReadPhase mode) override;
703
704
1.04k
    bool need_to_read() const override {
705
1.04k
        switch (_read_phase) {
706
1.02k
        case ReadPhase::NORMAL:
707
1.02k
            return _read_requirement != ReadRequirement::SKIP;
708
4
        case ReadPhase::PREDICATE:
709
4
            return _read_requirement == ReadRequirement::PREDICATE;
710
8
        case ReadPhase::LAZY:
711
            // In lazy mode, read this map only when at least one key/value branch still
712
            // has non-predicate data to materialize.
713
8
            return has_lazy_read_target();
714
0
        default:
715
0
            return false;
716
1.04k
        }
717
1.04k
    }
718
719
    void finalize_lazy_phase(MutableColumnPtr& dst) override;
720
721
    void set_read_requirement(ReadRequirement requirement) override;
722
723
    bool has_lazy_read_target() const override;
724
725
private:
726
    std::shared_ptr<ColumnReader> _map_reader = nullptr;
727
    ColumnIteratorUPtr _null_iterator;
728
    OffsetFileColumnIteratorUPtr _offsets_iterator; //OffsetFileIterator
729
    ColumnIteratorUPtr _key_iterator;
730
    ColumnIteratorUPtr _val_iterator;
731
};
732
733
class StructFileColumnIterator final : public ColumnIterator {
734
public:
735
    explicit StructFileColumnIterator(std::shared_ptr<ColumnReader> reader,
736
                                      ColumnIteratorUPtr null_iterator,
737
                                      std::vector<ColumnIteratorUPtr>&& sub_column_iterators);
738
739
66
    ~StructFileColumnIterator() override = default;
740
741
    Status init(const ColumnIteratorOptions& opts) override;
742
743
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override;
744
745
4
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
746
4
        bool has_null;
747
4
        return next_batch(n, dst, &has_null);
748
4
    }
749
750
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
751
                          MutableColumnPtr& dst) override;
752
753
    Status seek_to_ordinal(ordinal_t ord) override;
754
755
0
    ordinal_t get_current_ordinal() const override {
756
0
        if (read_null_map_only() && _null_iterator) {
757
0
            return _null_iterator->get_current_ordinal();
758
0
        }
759
0
        return _sub_column_iterators[0]->get_current_ordinal();
760
0
    }
761
762
    Status set_access_paths(const TColumnAccessPaths& all_access_paths,
763
                            const TColumnAccessPaths& predicate_access_paths) override;
764
765
    void set_lazy_output_requirement() override;
766
767
    void remove_pruned_sub_iterators() override;
768
769
    Status init_prefetcher(const SegmentPrefetchParams& params) override;
770
    void collect_prefetchers(
771
            std::map<PrefetcherInitMethod, std::vector<SegmentPrefetcher*>>& prefetchers,
772
            PrefetcherInitMethod init_method) override;
773
774
    void set_read_phase(ReadPhase mode) override;
775
776
56
    bool need_to_read() const override {
777
56
        switch (_read_phase) {
778
34
        case ReadPhase::NORMAL:
779
34
            return _read_requirement != ReadRequirement::SKIP;
780
10
        case ReadPhase::PREDICATE:
781
10
            return _read_requirement == ReadRequirement::PREDICATE;
782
12
        case ReadPhase::LAZY:
783
            // In lazy mode, read this struct only when at least one nested branch still
784
            // has non-predicate data to materialize.
785
12
            return has_lazy_read_target();
786
0
        default:
787
0
            return false;
788
56
        }
789
56
    }
790
791
    void finalize_lazy_phase(MutableColumnPtr& dst) override;
792
    void set_read_requirement(ReadRequirement requirement) override;
793
    bool has_lazy_read_target() const override;
794
795
private:
796
    std::shared_ptr<ColumnReader> _struct_reader = nullptr;
797
    ColumnIteratorUPtr _null_iterator;
798
    std::vector<ColumnIteratorUPtr> _sub_column_iterators;
799
};
800
801
class ArrayFileColumnIterator final : public ColumnIterator {
802
public:
803
    explicit ArrayFileColumnIterator(std::shared_ptr<ColumnReader> reader,
804
                                     OffsetFileColumnIteratorUPtr offset_reader,
805
                                     ColumnIteratorUPtr item_iterator,
806
                                     ColumnIteratorUPtr null_iterator);
807
808
108
    ~ArrayFileColumnIterator() override = default;
809
810
    Status init(const ColumnIteratorOptions& opts) override;
811
812
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override;
813
814
38
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
815
38
        bool has_null;
816
38
        return next_batch(n, dst, &has_null);
817
38
    }
818
819
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
820
                          MutableColumnPtr& dst) override;
821
822
    Status seek_to_ordinal(ordinal_t ord) override;
823
824
0
    ordinal_t get_current_ordinal() const override {
825
0
        if (read_null_map_only() && _null_iterator) {
826
0
            return _null_iterator->get_current_ordinal();
827
0
        }
828
0
        return _offset_iterator->get_current_ordinal();
829
0
    }
830
831
    Status set_access_paths(const TColumnAccessPaths& all_access_paths,
832
                            const TColumnAccessPaths& predicate_access_paths) override;
833
    void set_lazy_output_requirement() override;
834
835
    void remove_pruned_sub_iterators() override;
836
837
    Status init_prefetcher(const SegmentPrefetchParams& params) override;
838
    void collect_prefetchers(
839
            std::map<PrefetcherInitMethod, std::vector<SegmentPrefetcher*>>& prefetchers,
840
            PrefetcherInitMethod init_method) override;
841
842
    void set_read_phase(ReadPhase mode) override;
843
844
229
    bool need_to_read() const override {
845
229
        switch (_read_phase) {
846
220
        case ReadPhase::NORMAL:
847
220
            return _read_requirement != ReadRequirement::SKIP;
848
4
        case ReadPhase::PREDICATE:
849
4
            return _read_requirement == ReadRequirement::PREDICATE;
850
5
        case ReadPhase::LAZY:
851
            // In lazy mode, read this array only when its item branch still has
852
            // non-predicate data to materialize.
853
5
            return has_lazy_read_target();
854
0
        default:
855
0
            return false;
856
229
        }
857
229
    }
858
859
    void finalize_lazy_phase(MutableColumnPtr& dst) override;
860
861
    void set_read_requirement(ReadRequirement requirement) override;
862
863
    bool has_lazy_read_target() const override;
864
865
private:
866
    std::shared_ptr<ColumnReader> _array_reader = nullptr;
867
    std::unique_ptr<OffsetFileColumnIterator> _offset_iterator;
868
    std::unique_ptr<ColumnIterator> _null_iterator;
869
    std::unique_ptr<ColumnIterator> _item_iterator;
870
871
    Status _seek_by_offsets(ordinal_t ord);
872
};
873
874
class RowIdColumnIteratorV2 : public ColumnIterator {
875
public:
876
    RowIdColumnIteratorV2(uint8_t version, int64_t backend_id, uint32_t file_id)
877
16
            : _version(version), _backend_id(backend_id), _file_id(file_id) {}
878
879
0
    Status seek_to_ordinal(ordinal_t ord_idx) override {
880
0
        _current_rowid = cast_set<uint32_t>(ord_idx);
881
0
        return Status::OK();
882
0
    }
883
884
0
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
885
0
        bool has_null;
886
0
        return next_batch(n, dst, &has_null);
887
0
    }
888
889
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override;
890
891
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
892
                          MutableColumnPtr& dst) override;
893
894
0
    ordinal_t get_current_ordinal() const override { return _current_rowid; }
895
896
private:
897
    uint32_t _current_rowid = 0;
898
    uint8_t _version;
899
    int64_t _backend_id;
900
    uint32_t _file_id;
901
};
902
903
// This iterator is used to read default value column
904
class DefaultValueColumnIterator : public ColumnIterator {
905
public:
906
    DefaultValueColumnIterator(bool has_default_value, std::string default_value, bool is_nullable,
907
                               FieldType type, int precision, int scale, int len)
908
26
            : _has_default_value(has_default_value),
909
26
              _default_value(std::move(default_value)),
910
26
              _is_nullable(is_nullable),
911
26
              _type(type),
912
26
              _precision(precision),
913
26
              _scale(scale),
914
26
              _len(len) {}
915
916
    Status init(const ColumnIteratorOptions& opts) override;
917
918
15
    Status seek_to_ordinal(ordinal_t ord_idx) override {
919
15
        _current_rowid = ord_idx;
920
15
        return Status::OK();
921
15
    }
922
923
0
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
924
0
        bool has_null;
925
0
        return next_batch(n, dst, &has_null);
926
0
    }
927
928
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override;
929
930
0
    Status next_batch_of_zone_map(size_t* n, MutableColumnPtr& dst) override {
931
0
        return next_batch(n, dst);
932
0
    }
933
934
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
935
                          MutableColumnPtr& dst) override;
936
937
0
    ordinal_t get_current_ordinal() const override { return _current_rowid; }
938
939
private:
940
    void _insert_many_default(MutableColumnPtr& dst, size_t n);
941
942
    bool _has_default_value;
943
    std::string _default_value;
944
    bool _is_nullable;
945
    FieldType _type;
946
    int _precision;
947
    int _scale;
948
    const int _len;
949
    Field _default_value_field;
950
951
    // current rowid
952
    ordinal_t _current_rowid = 0;
953
};
954
955
// Produces a column whose every row is the same constant Field value.
956
// Used for read-time-filled constant hidden columns (e.g. __DORIS_COMMIT_TSO_COL__),
957
// where the on-disk value is only a placeholder and the real value comes from the read
958
// context (StorageReadOptions).
959
class ConstantColumnIterator : public ColumnIterator {
960
public:
961
    ConstantColumnIterator() = delete;
962
107
    explicit ConstantColumnIterator(Field value) : _value(std::move(value)) {}
963
964
57
    Status seek_to_ordinal(ordinal_t ord_idx) override {
965
57
        _current_rowid = ord_idx;
966
57
        return Status::OK();
967
57
    }
968
969
1
    Status next_batch(size_t* n, MutableColumnPtr& dst) {
970
1
        bool has_null;
971
1
        return next_batch(n, dst, &has_null);
972
1
    }
973
974
62
    Status next_batch(size_t* n, MutableColumnPtr& dst, bool* has_null) override {
975
62
        *has_null = _value.is_null();
976
62
        Status st = _insert_many(dst, *n);
977
62
        if (!st.ok()) {
978
0
            return st;
979
0
        }
980
62
        _current_rowid += *n;
981
62
        return st;
982
62
    }
983
984
1
    Status next_batch_of_zone_map(size_t* n, MutableColumnPtr& dst) override {
985
1
        return next_batch(n, dst);
986
1
    }
987
988
    Status read_by_rowids(const rowid_t* rowids, const size_t count,
989
45
                          MutableColumnPtr& dst) override {
990
45
        return _insert_many(dst, count);
991
45
    }
992
993
3
    ordinal_t get_current_ordinal() const override { return _current_rowid; }
994
995
private:
996
107
    Status _insert_many(MutableColumnPtr& dst, size_t n) {
997
107
        if (_value.is_null()) {
998
1
            if (UNLIKELY(!dst->is_nullable())) {
999
0
                return Status::InternalError(
1000
0
                        "try to apply constant null value to not nullable target column");
1001
0
            }
1002
1
            dst->insert_many_defaults(n);
1003
1
            return Status::OK();
1004
1
        }
1005
106
        dst->insert_duplicate_fields(_value, n);
1006
106
        return Status::OK();
1007
107
    }
1008
1009
    Field _value;
1010
    ordinal_t _current_rowid = 0;
1011
};
1012
1013
// A ColumnReader that represents a single constant value for the whole segment instead of reading
1014
// on-disk data. Used for read-time-filled constant columns (e.g. __DORIS_COMMIT_TSO_COL__) on a
1015
// single-version segment, whose on-disk zonemap only reflects the placeholder. It advertises a
1016
// single-value [v, v] zonemap so segment-level pruning matches against the real value, and produces
1017
// a ConstantColumnIterator for data reads.
1018
class ConstantColumnReader : public ColumnReader {
1019
public:
1020
104
    explicit ConstantColumnReader(Field value) : _value(std::move(value)) {}
1021
1022
2
    bool has_zone_map() const override { return true; }
1023
1024
    // The base ColumnReader default-constructs without initializing its _meta_type. The data-read
1025
    // path (Segment::new_column_iterator) verifies tablet_column.type() == reader->get_meta_type()
1026
    // when config::enable_column_type_check is on (default true), so derive the real OLAP type from
1027
    // the constant value to avoid a spurious "different type between schema and column reader" error.
1028
203
    FieldType get_meta_type() override {
1029
203
        return primitive_type_to_storage_field_type(_value.get_type());
1030
203
    }
1031
1032
    Status new_iterator(ColumnIteratorUPtr* iterator, const TabletColumn* /*col*/,
1033
102
                        const StorageReadOptions* /*opt*/) override {
1034
102
        *iterator = std::make_unique<ConstantColumnIterator>(_value);
1035
102
        return Status::OK();
1036
102
    }
1037
1038
    Status get_segment_zone_map(segment_v2::ZoneMap* zone_map) const override;
1039
1040
private:
1041
    Field _value;
1042
};
1043
1044
} // namespace segment_v2
1045
} // namespace doris