Coverage Report

Created: 2026-11-03 19:03

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