Coverage Report

Created: 2026-10-14 20:29

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