Coverage Report

Created: 2026-07-03 17:03

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