Coverage Report

Created: 2026-07-06 12:17

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