Coverage Report

Created: 2026-07-14 13:56

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