Coverage Report

Created: 2026-10-15 20:44

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