Coverage Report

Created: 2026-10-29 15:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/format/table/iceberg_reader_mixin.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/ExternalTableSchema_types.h>
21
22
#include <algorithm>
23
#include <cstddef>
24
#include <cstdint>
25
#include <memory>
26
#include <string>
27
#include <unordered_map>
28
#include <vector>
29
30
#include "common/consts.h"
31
#include "common/status.h"
32
#include "core/block/block.h"
33
#include "core/column/column_dictionary.h"
34
#include "core/column/column_nullable.h"
35
#include "core/column/column_string.h"
36
#include "core/column/column_struct.h"
37
#include "core/data_type/data_type_number.h"
38
#include "core/data_type/data_type_string.h"
39
#include "core/data_type/data_type_struct.h"
40
#include "core/data_type/primitive_type.h"
41
#include "format/generic_reader.h"
42
#include "format/table/equality_delete.h"
43
#include "format/table/iceberg_default_value.h"
44
#include "format/table/iceberg_delete_file_reader_helper.h"
45
#include "format/table/iceberg_scan_semantics.h"
46
#include "format/table/table_schema_change_helper.h"
47
#include "runtime/runtime_profile.h"
48
#include "runtime/runtime_state.h"
49
#include "storage/olap_common.h"
50
#include "util/string_util.h"
51
52
namespace doris {
53
class TIcebergDeleteFileDesc;
54
} // namespace doris
55
56
namespace doris {
57
58
class ShardedKVCache;
59
60
// CRTP mixin for Iceberg reader functionality.
61
// BaseReader should be ParquetReader or OrcReader.
62
// Inherits BaseReader + TableSchemaChangeHelper, providing shared Iceberg logic
63
// (delete files, deletion vectors, equality delete, $row_id synthesis).
64
//
65
// Inheritance chain:
66
//   IcebergParquetReader -> IcebergReaderMixin<ParquetReader> -> ParquetReader -> GenericReader
67
//   IcebergOrcReader     -> IcebergReaderMixin<OrcReader>     -> OrcReader     -> GenericReader
68
template <typename BaseReader>
69
class IcebergReaderMixin : public BaseReader, public TableSchemaChangeHelper {
70
public:
71
    struct PositionDeleteRange {
72
        std::vector<std::string> data_file_path;
73
        std::vector<std::pair<int, int>> range;
74
    };
75
76
    // Forward BaseReader constructor arguments + Iceberg-specific kv_cache
77
    template <typename... Args>
78
    IcebergReaderMixin(ShardedKVCache* kv_cache, Args&&... args)
79
83
            : BaseReader(std::forward<Args>(args)...), _kv_cache(kv_cache) {
80
83
        static const char* iceberg_profile = "IcebergProfile";
81
83
        ADD_TIMER(this->get_profile(), iceberg_profile);
82
83
        _iceberg_profile.num_delete_files = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteFiles",
83
83
                                                              TUnit::UNIT, iceberg_profile);
84
83
        _iceberg_profile.num_delete_rows = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteRows",
85
83
                                                             TUnit::UNIT, iceberg_profile);
86
83
        _iceberg_profile.delete_files_read_time =
87
83
                ADD_CHILD_TIMER(this->get_profile(), "DeleteFileReadTime", iceberg_profile);
88
83
        _iceberg_profile.delete_rows_sort_time =
89
83
                ADD_CHILD_TIMER(this->get_profile(), "DeleteRowsSortTime", iceberg_profile);
90
83
        _iceberg_profile.parse_delete_file_time =
91
83
                ADD_CHILD_TIMER(this->get_profile(), "ParseDeleteFileTime", iceberg_profile);
92
83
        _iceberg_profile.decoded_cache_hit_count =
93
83
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheHitCount",
94
83
                                  TUnit::UNIT, iceberg_profile);
95
83
        _iceberg_profile.decoded_cache_miss_count =
96
83
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheMissCount",
97
83
                                  TUnit::UNIT, iceberg_profile);
98
83
        _iceberg_profile.file_cache_hit_count =
99
83
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheHitCount",
100
83
                                  TUnit::UNIT, iceberg_profile);
101
83
        _iceberg_profile.file_cache_miss_count =
102
83
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheMissCount",
103
83
                                  TUnit::UNIT, iceberg_profile);
104
83
        _iceberg_profile.file_cache_peer_read_count =
105
83
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCachePeerReadCount",
106
83
                                  TUnit::UNIT, iceberg_profile);
107
83
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEEC2IJRPNS_14RuntimeProfileERKNS_20TFileScanRangeParamsERKNS_14TFileRangeDescERmRPKN4cctz9time_zoneERPNS_2io9IOContextERPNS_12RuntimeStateERPNS_13FileMetaCacheEEEEPNS_14ShardedKVCacheEDpOT_
Line
Count
Source
79
52
            : BaseReader(std::forward<Args>(args)...), _kv_cache(kv_cache) {
80
52
        static const char* iceberg_profile = "IcebergProfile";
81
52
        ADD_TIMER(this->get_profile(), iceberg_profile);
82
52
        _iceberg_profile.num_delete_files = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteFiles",
83
52
                                                              TUnit::UNIT, iceberg_profile);
84
52
        _iceberg_profile.num_delete_rows = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteRows",
85
52
                                                             TUnit::UNIT, iceberg_profile);
86
52
        _iceberg_profile.delete_files_read_time =
87
52
                ADD_CHILD_TIMER(this->get_profile(), "DeleteFileReadTime", iceberg_profile);
88
52
        _iceberg_profile.delete_rows_sort_time =
89
52
                ADD_CHILD_TIMER(this->get_profile(), "DeleteRowsSortTime", iceberg_profile);
90
52
        _iceberg_profile.parse_delete_file_time =
91
52
                ADD_CHILD_TIMER(this->get_profile(), "ParseDeleteFileTime", iceberg_profile);
92
52
        _iceberg_profile.decoded_cache_hit_count =
93
52
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheHitCount",
94
52
                                  TUnit::UNIT, iceberg_profile);
95
52
        _iceberg_profile.decoded_cache_miss_count =
96
52
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheMissCount",
97
52
                                  TUnit::UNIT, iceberg_profile);
98
52
        _iceberg_profile.file_cache_hit_count =
99
52
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheHitCount",
100
52
                                  TUnit::UNIT, iceberg_profile);
101
52
        _iceberg_profile.file_cache_miss_count =
102
52
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheMissCount",
103
52
                                  TUnit::UNIT, iceberg_profile);
104
52
        _iceberg_profile.file_cache_peer_read_count =
105
52
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCachePeerReadCount",
106
52
                                  TUnit::UNIT, iceberg_profile);
107
52
    }
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEEC2IJRPNS_14RuntimeProfileERPNS_12RuntimeStateERKNS_20TFileScanRangeParamsERKNS_14TFileRangeDescERmRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERPNS_2io9IOContextERPNS_13FileMetaCacheEEEEPNS_14ShardedKVCacheEDpOT_
Line
Count
Source
79
30
            : BaseReader(std::forward<Args>(args)...), _kv_cache(kv_cache) {
80
30
        static const char* iceberg_profile = "IcebergProfile";
81
30
        ADD_TIMER(this->get_profile(), iceberg_profile);
82
30
        _iceberg_profile.num_delete_files = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteFiles",
83
30
                                                              TUnit::UNIT, iceberg_profile);
84
30
        _iceberg_profile.num_delete_rows = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteRows",
85
30
                                                             TUnit::UNIT, iceberg_profile);
86
30
        _iceberg_profile.delete_files_read_time =
87
30
                ADD_CHILD_TIMER(this->get_profile(), "DeleteFileReadTime", iceberg_profile);
88
30
        _iceberg_profile.delete_rows_sort_time =
89
30
                ADD_CHILD_TIMER(this->get_profile(), "DeleteRowsSortTime", iceberg_profile);
90
30
        _iceberg_profile.parse_delete_file_time =
91
30
                ADD_CHILD_TIMER(this->get_profile(), "ParseDeleteFileTime", iceberg_profile);
92
30
        _iceberg_profile.decoded_cache_hit_count =
93
30
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheHitCount",
94
30
                                  TUnit::UNIT, iceberg_profile);
95
30
        _iceberg_profile.decoded_cache_miss_count =
96
30
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheMissCount",
97
30
                                  TUnit::UNIT, iceberg_profile);
98
30
        _iceberg_profile.file_cache_hit_count =
99
30
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheHitCount",
100
30
                                  TUnit::UNIT, iceberg_profile);
101
30
        _iceberg_profile.file_cache_miss_count =
102
30
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheMissCount",
103
30
                                  TUnit::UNIT, iceberg_profile);
104
30
        _iceberg_profile.file_cache_peer_read_count =
105
30
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCachePeerReadCount",
106
30
                                  TUnit::UNIT, iceberg_profile);
107
30
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEEC2IJRPNS_14RuntimeProfileERKNS_20TFileScanRangeParamsERKNS_14TFileRangeDescERmRPKN4cctz9time_zoneESt10shared_ptrINS_2io9IOContextEERPNS_12RuntimeStateERPNS_13FileMetaCacheEEEEPNS_14ShardedKVCacheEDpOT_
Line
Count
Source
79
1
            : BaseReader(std::forward<Args>(args)...), _kv_cache(kv_cache) {
80
1
        static const char* iceberg_profile = "IcebergProfile";
81
1
        ADD_TIMER(this->get_profile(), iceberg_profile);
82
1
        _iceberg_profile.num_delete_files = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteFiles",
83
1
                                                              TUnit::UNIT, iceberg_profile);
84
1
        _iceberg_profile.num_delete_rows = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteRows",
85
1
                                                             TUnit::UNIT, iceberg_profile);
86
1
        _iceberg_profile.delete_files_read_time =
87
1
                ADD_CHILD_TIMER(this->get_profile(), "DeleteFileReadTime", iceberg_profile);
88
1
        _iceberg_profile.delete_rows_sort_time =
89
1
                ADD_CHILD_TIMER(this->get_profile(), "DeleteRowsSortTime", iceberg_profile);
90
1
        _iceberg_profile.parse_delete_file_time =
91
1
                ADD_CHILD_TIMER(this->get_profile(), "ParseDeleteFileTime", iceberg_profile);
92
1
        _iceberg_profile.decoded_cache_hit_count =
93
1
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheHitCount",
94
1
                                  TUnit::UNIT, iceberg_profile);
95
1
        _iceberg_profile.decoded_cache_miss_count =
96
1
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheMissCount",
97
1
                                  TUnit::UNIT, iceberg_profile);
98
1
        _iceberg_profile.file_cache_hit_count =
99
1
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheHitCount",
100
1
                                  TUnit::UNIT, iceberg_profile);
101
1
        _iceberg_profile.file_cache_miss_count =
102
1
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheMissCount",
103
1
                                  TUnit::UNIT, iceberg_profile);
104
1
        _iceberg_profile.file_cache_peer_read_count =
105
1
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCachePeerReadCount",
106
1
                                  TUnit::UNIT, iceberg_profile);
107
1
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEEC2IJRPNS_14RuntimeProfileERPNS_12RuntimeStateERKNS_20TFileScanRangeParamsERKNS_14TFileRangeDescERmRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt10shared_ptrINS_2io9IOContextEERPNS_13FileMetaCacheEEEEPNS_14ShardedKVCacheEDpOT_
108
109
83
    ~IcebergReaderMixin() override = default;
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEED2Ev
Line
Count
Source
109
53
    ~IcebergReaderMixin() override = default;
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEED2Ev
Line
Count
Source
109
30
    ~IcebergReaderMixin() override = default;
110
111
    void set_current_file_info(const std::string& file_path, int32_t partition_spec_id,
112
0
                               const std::string& partition_data_json) {
113
0
        _current_file_path = file_path;
114
0
        _partition_spec_id = partition_spec_id;
115
0
        _partition_data_json = partition_data_json;
116
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21set_current_file_infoERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiSA_
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21set_current_file_infoERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiSA_
117
118
    enum { DATA, POSITION_DELETE, EQUALITY_DELETE, DELETION_VECTOR };
119
    enum Fileformat { NONE, PARQUET, ORC, AVRO };
120
121
    virtual void set_delete_rows() = 0;
122
    virtual void set_deletion_vector() = 0;
123
124
    // Table-level COUNT(*) is handled by CountReader (created by FileScanner after
125
    // init_reader). If _do_get_next_block is called, COUNT must have been resolved.
126
61
    Status _do_get_next_block(Block* block, size_t* read_rows, bool* eof) override {
127
61
        DCHECK(this->_push_down_agg_type != TPushAggOp::type::COUNT);
128
61
        return BaseReader::_do_get_next_block(block, read_rows, eof);
129
61
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE18_do_get_next_blockEPNS_5BlockEPmPb
Line
Count
Source
126
37
    Status _do_get_next_block(Block* block, size_t* read_rows, bool* eof) override {
127
        DCHECK(this->_push_down_agg_type != TPushAggOp::type::COUNT);
128
37
        return BaseReader::_do_get_next_block(block, read_rows, eof);
129
37
    }
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE18_do_get_next_blockEPNS_5BlockEPmPb
Line
Count
Source
126
24
    Status _do_get_next_block(Block* block, size_t* read_rows, bool* eof) override {
127
        DCHECK(this->_push_down_agg_type != TPushAggOp::type::COUNT);
128
24
        return BaseReader::_do_get_next_block(block, read_rows, eof);
129
24
    }
130
131
    void set_create_row_id_column_iterator_func(
132
1
            std::function<std::shared_ptr<segment_v2::RowIdColumnIteratorV2>()> create_func) {
133
1
        _create_topn_row_id_column_iterator = create_func;
134
1
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE38set_create_row_id_column_iterator_funcESt8functionIFSt10shared_ptrINS_10segment_v221RowIdColumnIteratorV2EEvEE
Line
Count
Source
132
1
            std::function<std::shared_ptr<segment_v2::RowIdColumnIteratorV2>()> create_func) {
133
1
        _create_topn_row_id_column_iterator = create_func;
134
1
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE38set_create_row_id_column_iterator_funcESt8functionIFSt10shared_ptrINS_10segment_v221RowIdColumnIteratorV2EEvEE
135
136
    Status TEST_read_deletion_vector(const std::string& data_file_path,
137
1
                                     const TIcebergDeleteFileDesc& delete_file_desc) {
138
1
        return read_deletion_vector(data_file_path, delete_file_desc);
139
1
    }
140
141
    Status TEST_position_delete_base(const std::string& data_file_path,
142
2
                                     const std::vector<TIcebergDeleteFileDesc>& delete_files) {
143
2
        return _position_delete_base(data_file_path, delete_files);
144
2
    }
145
146
1
    Status TEST_read_equality_delete_file(const TIcebergDeleteFileDesc& delete_file) {
147
1
        return _read_equality_delete_file(delete_file);
148
1
    }
149
150
    void TEST_set_column_name_to_block_index(
151
5
            std::unordered_map<std::string, uint32_t>* column_name_to_block_index) {
152
5
        this->col_name_to_block_idx_ref() = column_name_to_block_index;
153
5
    }
154
155
    Status TEST_register_missing_equality_delete_column(int32_t field_id, const std::string& name,
156
6
                                                        const DataTypePtr& delete_key_type) {
157
6
        return _register_missing_equality_delete_column(field_id, name, delete_key_type);
158
6
    }
159
160
3
    Status TEST_materialize_missing_equality_delete_columns(Block* block, size_t rows) {
161
3
        return _materialize_missing_equality_delete_columns(block, rows);
162
3
    }
163
164
8
    const std::vector<int32_t>& TEST_expand_col_field_ids() const { return _expand_col_field_ids; }
_ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE25TEST_expand_col_field_idsEv
Line
Count
Source
164
4
    const std::vector<int32_t>& TEST_expand_col_field_ids() const { return _expand_col_field_ids; }
_ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE25TEST_expand_col_field_idsEv
Line
Count
Source
164
4
    const std::vector<int32_t>& TEST_expand_col_field_ids() const { return _expand_col_field_ids; }
165
166
protected:
167
    // ---- Hook implementations ----
168
169
    // Called before reading a block: expand block for equality delete columns + detect row_id
170
61
    Status on_before_read_block(Block* block) override {
171
61
        RETURN_IF_ERROR(_expand_block_if_need(block));
172
61
        return Status::OK();
173
61
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20on_before_read_blockEPNS_5BlockE
Line
Count
Source
170
37
    Status on_before_read_block(Block* block) override {
171
37
        RETURN_IF_ERROR(_expand_block_if_need(block));
172
37
        return Status::OK();
173
37
    }
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE20on_before_read_blockEPNS_5BlockE
Line
Count
Source
170
24
    Status on_before_read_block(Block* block) override {
171
24
        RETURN_IF_ERROR(_expand_block_if_need(block));
172
24
        return Status::OK();
173
24
    }
174
175
    // Iceberg initial defaults belong to the table schema, not to the generic FE slot default.
176
    // V1 keeps master's primitive-default behavior; V2 also materializes missing optional/required
177
    // fields and complex defaults through the recursive Iceberg schema metadata.
178
    Status on_fill_missing_columns(Block* block, size_t rows,
179
70
                                   const std::vector<std::string>& cols) override {
180
70
        if (!supports_iceberg_scan_semantics_v1(&this->get_scan_params())) {
181
5
            return BaseReader::on_fill_missing_columns(block, rows, cols);
182
5
        }
183
65
        const bool use_v2_semantics = supports_iceberg_scan_semantics_v2(&this->get_scan_params());
184
65
        std::vector<std::string> base_reader_columns;
185
65
        for (const auto& col_name : cols) {
186
5
            const auto* field = _find_current_schema_field(col_name);
187
5
            if (field == nullptr || (!use_v2_semantics && !field->__isset.initial_default_value)) {
188
0
                base_reader_columns.push_back(col_name);
189
0
                continue;
190
0
            }
191
192
5
            DORIS_CHECK(this->_fill_col_name_to_block_idx != nullptr);
193
5
            const auto position = this->_fill_col_name_to_block_idx->find(col_name);
194
5
            if (position == this->_fill_col_name_to_block_idx->end()) {
195
0
                return Status::InternalError("Missing column: {} not found in block {}", col_name,
196
0
                                             block->dump_structure());
197
0
            }
198
5
            DORIS_CHECK(position->second < block->columns());
199
200
5
            auto default_value = _missing_initial_default_values.find(col_name);
201
5
            if (default_value == _missing_initial_default_values.end()) {
202
4
                ColumnPtr value;
203
4
                RETURN_IF_ERROR(iceberg::create_initial_default_column(
204
4
                        *field, block->get_by_position(position->second).type, &value));
205
4
                default_value =
206
4
                        _missing_initial_default_values.emplace(col_name, std::move(value)).first;
207
4
            }
208
5
            auto column_guard = block->mutate_column_scoped(position->second);
209
5
            auto& mutable_column = column_guard.mutable_column();
210
5
            mutable_column->insert_many_from(*default_value->second, 0, rows);
211
5
        }
212
65
        return BaseReader::on_fill_missing_columns(block, rows, base_reader_columns);
213
65
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE23on_fill_missing_columnsEPNS_5BlockEmRKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISB_EE
Line
Count
Source
179
45
                                   const std::vector<std::string>& cols) override {
180
45
        if (!supports_iceberg_scan_semantics_v1(&this->get_scan_params())) {
181
4
            return BaseReader::on_fill_missing_columns(block, rows, cols);
182
4
        }
183
41
        const bool use_v2_semantics = supports_iceberg_scan_semantics_v2(&this->get_scan_params());
184
41
        std::vector<std::string> base_reader_columns;
185
41
        for (const auto& col_name : cols) {
186
4
            const auto* field = _find_current_schema_field(col_name);
187
4
            if (field == nullptr || (!use_v2_semantics && !field->__isset.initial_default_value)) {
188
0
                base_reader_columns.push_back(col_name);
189
0
                continue;
190
0
            }
191
192
4
            DORIS_CHECK(this->_fill_col_name_to_block_idx != nullptr);
193
4
            const auto position = this->_fill_col_name_to_block_idx->find(col_name);
194
4
            if (position == this->_fill_col_name_to_block_idx->end()) {
195
0
                return Status::InternalError("Missing column: {} not found in block {}", col_name,
196
0
                                             block->dump_structure());
197
0
            }
198
4
            DORIS_CHECK(position->second < block->columns());
199
200
4
            auto default_value = _missing_initial_default_values.find(col_name);
201
4
            if (default_value == _missing_initial_default_values.end()) {
202
3
                ColumnPtr value;
203
3
                RETURN_IF_ERROR(iceberg::create_initial_default_column(
204
3
                        *field, block->get_by_position(position->second).type, &value));
205
3
                default_value =
206
3
                        _missing_initial_default_values.emplace(col_name, std::move(value)).first;
207
3
            }
208
4
            auto column_guard = block->mutate_column_scoped(position->second);
209
4
            auto& mutable_column = column_guard.mutable_column();
210
4
            mutable_column->insert_many_from(*default_value->second, 0, rows);
211
4
        }
212
41
        return BaseReader::on_fill_missing_columns(block, rows, base_reader_columns);
213
41
    }
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE23on_fill_missing_columnsEPNS_5BlockEmRKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISB_EE
Line
Count
Source
179
25
                                   const std::vector<std::string>& cols) override {
180
25
        if (!supports_iceberg_scan_semantics_v1(&this->get_scan_params())) {
181
1
            return BaseReader::on_fill_missing_columns(block, rows, cols);
182
1
        }
183
24
        const bool use_v2_semantics = supports_iceberg_scan_semantics_v2(&this->get_scan_params());
184
24
        std::vector<std::string> base_reader_columns;
185
24
        for (const auto& col_name : cols) {
186
1
            const auto* field = _find_current_schema_field(col_name);
187
1
            if (field == nullptr || (!use_v2_semantics && !field->__isset.initial_default_value)) {
188
0
                base_reader_columns.push_back(col_name);
189
0
                continue;
190
0
            }
191
192
1
            DORIS_CHECK(this->_fill_col_name_to_block_idx != nullptr);
193
1
            const auto position = this->_fill_col_name_to_block_idx->find(col_name);
194
1
            if (position == this->_fill_col_name_to_block_idx->end()) {
195
0
                return Status::InternalError("Missing column: {} not found in block {}", col_name,
196
0
                                             block->dump_structure());
197
0
            }
198
1
            DORIS_CHECK(position->second < block->columns());
199
200
1
            auto default_value = _missing_initial_default_values.find(col_name);
201
1
            if (default_value == _missing_initial_default_values.end()) {
202
1
                ColumnPtr value;
203
1
                RETURN_IF_ERROR(iceberg::create_initial_default_column(
204
1
                        *field, block->get_by_position(position->second).type, &value));
205
1
                default_value =
206
1
                        _missing_initial_default_values.emplace(col_name, std::move(value)).first;
207
1
            }
208
1
            auto column_guard = block->mutate_column_scoped(position->second);
209
1
            auto& mutable_column = column_guard.mutable_column();
210
1
            mutable_column->insert_many_from(*default_value->second, 0, rows);
211
1
        }
212
24
        return BaseReader::on_fill_missing_columns(block, rows, base_reader_columns);
213
24
    }
214
215
    /// Fill Iceberg $row_id synthesized column. Registered as handler during init.
216
0
    Status _fill_iceberg_row_id(Block* block, size_t rows) {
217
0
        int row_id_pos = block->get_position_by_name(BeConsts::ICEBERG_ROWID_COL);
218
0
        DORIS_CHECK(row_id_pos >= 0);
219
220
        // Lazy-init file info: only set when $row_id is actually needed.
221
0
        const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
222
0
        std::string file_path = table_desc.original_file_path;
223
0
        int32_t partition_spec_id =
224
0
                table_desc.__isset.partition_spec_id ? table_desc.partition_spec_id : 0;
225
0
        std::string partition_data_json;
226
0
        if (table_desc.__isset.partition_data_json) {
227
0
            partition_data_json = table_desc.partition_data_json;
228
0
        }
229
0
        set_current_file_info(file_path, partition_spec_id, partition_data_json);
230
231
0
        const auto& row_ids = this->current_batch_row_positions();
232
0
        auto& col_with_type = block->get_by_position(static_cast<size_t>(row_id_pos));
233
0
        MutableColumnPtr row_id_column;
234
0
        RETURN_IF_ERROR(_build_iceberg_rowid_column(col_with_type.type, _current_file_path, row_ids,
235
0
                                                    _partition_spec_id, _partition_data_json,
236
0
                                                    &row_id_column));
237
0
        col_with_type.column = std::move(row_id_column);
238
0
        return Status::OK();
239
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20_fill_iceberg_row_idEPNS_5BlockEm
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE20_fill_iceberg_row_idEPNS_5BlockEm
240
241
0
    void _init_row_lineage_columns() {
242
0
        const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
243
0
        if (table_desc.__isset.first_row_id) {
244
0
            _row_lineage_columns.first_row_id = table_desc.first_row_id;
245
0
        }
246
0
        if (table_desc.__isset.last_updated_sequence_number) {
247
0
            _row_lineage_columns.last_updated_sequence_number =
248
0
                    table_desc.last_updated_sequence_number;
249
0
        }
250
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE25_init_row_lineage_columnsEv
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE25_init_row_lineage_columnsEv
251
252
0
    Status _fill_row_lineage_row_id(Block* block, size_t rows) {
253
0
        int col_pos = block->get_position_by_name(ROW_LINEAGE_ROW_ID);
254
0
        DORIS_CHECK(col_pos >= 0);
255
256
0
        if (_row_lineage_columns.first_row_id >= 0) {
257
0
            auto column_guard = block->mutate_column_scoped(col_pos);
258
0
            auto* nullable_column =
259
0
                    assert_cast<ColumnNullable*>(column_guard.mutable_column().get());
260
0
            auto& null_map = nullable_column->get_null_map_data();
261
0
            auto& data =
262
0
                    assert_cast<ColumnInt64&>(*nullable_column->get_nested_column_ptr()).get_data();
263
0
            const auto& row_ids = this->current_batch_row_positions();
264
0
            for (size_t i = 0; i < rows; ++i) {
265
0
                if (null_map[i] != 0) {
266
0
                    null_map[i] = 0;
267
0
                    data[i] = _row_lineage_columns.first_row_id + static_cast<int64_t>(row_ids[i]);
268
0
                }
269
0
            }
270
0
        }
271
0
        return Status::OK();
272
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE24_fill_row_lineage_row_idEPNS_5BlockEm
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE24_fill_row_lineage_row_idEPNS_5BlockEm
273
274
0
    Status _fill_row_lineage_last_updated_sequence_number(Block* block, size_t rows) {
275
0
        int col_pos = block->get_position_by_name(ROW_LINEAGE_LAST_UPDATED_SEQ_NUMBER);
276
0
        DORIS_CHECK(col_pos >= 0);
277
278
0
        if (_row_lineage_columns.last_updated_sequence_number >= 0) {
279
0
            auto column_guard = block->mutate_column_scoped(col_pos);
280
0
            auto* nullable_column =
281
0
                    assert_cast<ColumnNullable*>(column_guard.mutable_column().get());
282
0
            auto& null_map = nullable_column->get_null_map_data();
283
0
            auto& data =
284
0
                    assert_cast<ColumnInt64&>(*nullable_column->get_nested_column_ptr()).get_data();
285
0
            for (size_t i = 0; i < rows; ++i) {
286
0
                if (null_map[i] != 0) {
287
0
                    null_map[i] = 0;
288
0
                    data[i] = _row_lineage_columns.last_updated_sequence_number;
289
0
                }
290
0
            }
291
0
        }
292
0
        return Status::OK();
293
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE46_fill_row_lineage_last_updated_sequence_numberEPNS_5BlockEm
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE46_fill_row_lineage_last_updated_sequence_numberEPNS_5BlockEm
294
295
    // Called after reading a block: apply equality delete filter + shrink block
296
61
    Status on_after_read_block(Block* block, size_t* read_rows) override {
297
61
        RETURN_IF_ERROR(_materialize_missing_equality_delete_columns(block, block->rows()));
298
61
        RETURN_IF_ERROR(_materialize_nested_equality_delete_columns(block));
299
61
        if (!_equality_delete_impls.empty()) {
300
53
            std::unique_ptr<IColumn::Filter> filter =
301
53
                    std::make_unique<IColumn::Filter>(block->rows(), 1);
302
55
            for (auto& equality_delete_impl : _equality_delete_impls) {
303
55
                RETURN_IF_ERROR(equality_delete_impl->filter_data_block(
304
55
                        block, this->col_name_to_block_idx_ref(), _id_to_block_column_name,
305
55
                        *filter));
306
55
            }
307
53
            Block::filter_block_internal(block, *filter, block->columns());
308
53
            *read_rows = block->rows();
309
53
        }
310
61
        return _shrink_block_if_need(block);
311
61
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE19on_after_read_blockEPNS_5BlockEPm
Line
Count
Source
296
37
    Status on_after_read_block(Block* block, size_t* read_rows) override {
297
37
        RETURN_IF_ERROR(_materialize_missing_equality_delete_columns(block, block->rows()));
298
37
        RETURN_IF_ERROR(_materialize_nested_equality_delete_columns(block));
299
37
        if (!_equality_delete_impls.empty()) {
300
32
            std::unique_ptr<IColumn::Filter> filter =
301
32
                    std::make_unique<IColumn::Filter>(block->rows(), 1);
302
33
            for (auto& equality_delete_impl : _equality_delete_impls) {
303
33
                RETURN_IF_ERROR(equality_delete_impl->filter_data_block(
304
33
                        block, this->col_name_to_block_idx_ref(), _id_to_block_column_name,
305
33
                        *filter));
306
33
            }
307
32
            Block::filter_block_internal(block, *filter, block->columns());
308
32
            *read_rows = block->rows();
309
32
        }
310
37
        return _shrink_block_if_need(block);
311
37
    }
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE19on_after_read_blockEPNS_5BlockEPm
Line
Count
Source
296
24
    Status on_after_read_block(Block* block, size_t* read_rows) override {
297
24
        RETURN_IF_ERROR(_materialize_missing_equality_delete_columns(block, block->rows()));
298
24
        RETURN_IF_ERROR(_materialize_nested_equality_delete_columns(block));
299
24
        if (!_equality_delete_impls.empty()) {
300
21
            std::unique_ptr<IColumn::Filter> filter =
301
21
                    std::make_unique<IColumn::Filter>(block->rows(), 1);
302
22
            for (auto& equality_delete_impl : _equality_delete_impls) {
303
22
                RETURN_IF_ERROR(equality_delete_impl->filter_data_block(
304
22
                        block, this->col_name_to_block_idx_ref(), _id_to_block_column_name,
305
22
                        *filter));
306
22
            }
307
21
            Block::filter_block_internal(block, *filter, block->columns());
308
21
            *read_rows = block->rows();
309
21
        }
310
24
        return _shrink_block_if_need(block);
311
24
    }
312
313
    // ---- Shared Iceberg methods ----
314
315
    Status _init_row_filters();
316
    Status _position_delete_base(const std::string data_file_path,
317
                                 const std::vector<TIcebergDeleteFileDesc>& delete_files);
318
    Status _equality_delete_base(const std::vector<TIcebergDeleteFileDesc>& delete_files);
319
    Status read_deletion_vector(const std::string& data_file_path,
320
                                const TIcebergDeleteFileDesc& delete_file_desc);
321
322
    Status _expand_block_if_need(Block* block);
323
    Status _shrink_block_if_need(Block* block);
324
    const schema::external::TStructField* _current_schema_root() const;
325
    const schema::external::TField* _find_current_schema_field(const std::string& name) const;
326
    const schema::external::TField* _find_schema_field(int32_t field_id) const;
327
    static bool _find_schema_field_path_in_field(
328
            const schema::external::TField* field, int32_t field_id,
329
            std::vector<const schema::external::TField*>* path);
330
    static bool _find_schema_field_path_in_root(const schema::external::TStructField* root,
331
                                                int32_t field_id,
332
                                                std::vector<const schema::external::TField*>* path);
333
    std::vector<const schema::external::TField*> _find_schema_field_path(int32_t field_id) const;
334
    Status _create_missing_equality_delete_value(int32_t field_id,
335
                                                 const DataTypePtr& delete_key_type,
336
                                                 size_t physical_path_size,
337
                                                 ColumnPtr* const value) const;
338
    Status _register_missing_equality_delete_column(int32_t field_id, const std::string& name,
339
                                                    const DataTypePtr& delete_key_type);
340
    bool _is_derived_equality_delete_column(const std::string& name) const;
341
    Status _materialize_missing_equality_delete_column(Block* block, const std::string& name,
342
                                                       const ColumnPtr& value, size_t rows);
343
    Status _materialize_missing_equality_delete_columns(Block* block, size_t rows);
344
345
    // Type aliases — must be defined before member function declarations that use them.
346
    using DeleteRows = std::vector<int64_t>;
347
    using DeleteFile = phmap::parallel_flat_hash_map<
348
            std::string, std::unique_ptr<DeleteRows>, std::hash<std::string>, std::equal_to<>,
349
            std::allocator<std::pair<const std::string, std::unique_ptr<DeleteRows>>>, 8,
350
            std::mutex>;
351
352
    PositionDeleteRange _get_range(const ColumnDictI32& file_path_column);
353
    PositionDeleteRange _get_range(const ColumnString& file_path_column);
354
    static void _sort_delete_rows(const std::vector<std::vector<int64_t>*>& delete_rows_array,
355
                                  int64_t num_delete_rows, std::vector<int64_t>& result);
356
    Status _gen_position_delete_file_range(Block& block, DeleteFile* position_delete,
357
                                           size_t read_rows,
358
                                           bool file_path_column_dictionary_coded);
359
    void _generate_equality_delete_block(Block* block,
360
                                         const std::vector<std::string>& equality_delete_col_names,
361
                                         const std::vector<DataTypePtr>& equality_delete_col_types);
362
    struct NestedEqualityDeleteColumn {
363
        int32_t field_id = -1;
364
        std::string block_name;
365
        // The type the key is compared in (equality_delete_key_type).
366
        DataTypePtr leaf_type;
367
        // The type of the leaf in the column it is extracted from, widened to leaf_type afterwards.
368
        // A file written before a type promotion holds the old type: payload.existing promoted from
369
        // INT to BIGINT is still INT in the delete files and data files written before.
370
        DataTypePtr source_leaf_type;
371
        std::vector<size_t> child_indexes;
372
        ColumnPtr missing_value;
373
        // Block column holding the key's root struct. Empty when the key's own column reads the
374
        // root; otherwise the projected root, or the carrier that reads a shared physical root.
375
        std::string source_block_name {};
376
    };
377
    struct EqualityDeleteReadSpec {
378
        NestedEqualityDeleteColumn nested_field;
379
        std::string leaf_name;
380
        std::string root_name;
381
        DataTypePtr root_type;
382
    };
383
    static bool _find_parquet_equality_delete_path(const FieldSchema& field, int32_t field_id,
384
                                                   std::vector<const FieldSchema*>* path,
385
                                                   std::vector<size_t>* child_indexes);
386
    static bool _find_orc_equality_delete_path(const orc::Type* field,
387
                                               const std::string& field_name, int32_t field_id,
388
                                               std::vector<const orc::Type*>* path,
389
                                               std::vector<std::string>* names,
390
                                               std::vector<size_t>* child_indexes);
391
    Status _build_parquet_equality_delete_read_specs(
392
            ParquetReader* reader, const TIcebergDeleteFileDesc& delete_file,
393
            std::vector<EqualityDeleteReadSpec>* read_specs) const;
394
    Status _build_orc_equality_delete_read_specs(
395
            OrcReader* reader, const TIcebergDeleteFileDesc& delete_file,
396
            std::vector<EqualityDeleteReadSpec>* read_specs) const;
397
    Status _build_equality_delete_read_specs(GenericReader* reader,
398
                                             const TIcebergDeleteFileDesc& delete_file,
399
                                             std::vector<EqualityDeleteReadSpec>* read_specs) const;
400
    void _register_equality_delete_read_specs(
401
            const std::vector<EqualityDeleteReadSpec>& read_specs,
402
            std::vector<std::string>* delete_col_names, std::vector<DataTypePtr>* delete_col_types,
403
            std::vector<int>* delete_col_ids, std::vector<std::string>* read_root_names,
404
            std::vector<DataTypePtr>* read_root_types,
405
            std::unordered_map<std::string, uint32_t>* read_root_positions);
406
    static Status _initialize_equality_delete_reader(
407
            GenericReader* reader, const std::vector<std::string>& read_root_names,
408
            std::unordered_map<std::string, uint32_t>* read_root_positions);
409
    Status _merge_equality_delete_rows(
410
            GenericReader* reader, const std::vector<EqualityDeleteReadSpec>& read_specs,
411
            const std::vector<std::string>& read_root_names,
412
            const std::vector<DataTypePtr>& read_root_types,
413
            const std::unordered_map<std::string, uint32_t>& read_root_positions,
414
            Block* eq_file_block) const;
415
    Status _read_equality_delete_file(const TIcebergDeleteFileDesc& delete_file);
416
    Status _extract_nested_equality_delete_column(const ColumnPtr& root_column,
417
                                                  const NestedEqualityDeleteColumn& nested_field,
418
                                                  ColumnPtr* leaf_column) const;
419
    Status _materialize_nested_equality_delete_columns(Block* block);
420
421
    // Pure virtual: format-specific delete file reading
422
    virtual Status _read_position_delete_file(const TFileRangeDesc*, DeleteFile*) = 0;
423
    virtual std::unique_ptr<GenericReader> _create_equality_reader(
424
            const TFileRangeDesc& delete_desc) = 0;
425
426
2
    static std::string _delet_file_cache_key(const std::string& path) { return "delete_" + path; }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_delet_file_cache_keyERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Line
Count
Source
426
2
    static std::string _delet_file_cache_key(const std::string& path) { return "delete_" + path; }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_delet_file_cache_keyERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
427
428
    /// Build the Iceberg V2 row-id struct column.
429
    static Status _build_iceberg_rowid_column(const DataTypePtr& type, const std::string& file_path,
430
                                              const std::vector<rowid_t>& row_ids,
431
                                              int32_t partition_spec_id,
432
                                              const std::string& partition_data_json,
433
0
                                              MutableColumnPtr* column_out) {
434
0
        if (type == nullptr || column_out == nullptr) {
435
0
            return Status::InvalidArgument("Invalid iceberg rowid column type or output column");
436
0
        }
437
0
        MutableColumnPtr column = type->create_column();
438
0
        auto* nullable_col = check_and_get_column<ColumnNullable>(column.get());
439
0
        ColumnStruct* struct_col = nullptr;
440
0
        if (nullable_col != nullptr) {
441
0
            struct_col =
442
0
                    check_and_get_column<ColumnStruct>(nullable_col->get_nested_column_ptr().get());
443
0
        } else {
444
0
            struct_col = check_and_get_column<ColumnStruct>(column.get());
445
0
        }
446
0
        if (struct_col == nullptr || struct_col->tuple_size() < 4) {
447
0
            return Status::InternalError("Invalid iceberg rowid column structure");
448
0
        }
449
0
        size_t num_rows = row_ids.size();
450
0
        auto& file_path_col = struct_col->get_column(0);
451
0
        auto& row_pos_col = struct_col->get_column(1);
452
0
        auto& spec_id_col = struct_col->get_column(2);
453
0
        auto& partition_data_col = struct_col->get_column(3);
454
0
        file_path_col.reserve(num_rows);
455
0
        row_pos_col.reserve(num_rows);
456
0
        spec_id_col.reserve(num_rows);
457
0
        partition_data_col.reserve(num_rows);
458
0
        for (size_t i = 0; i < num_rows; ++i) {
459
0
            file_path_col.insert_data(file_path.data(), file_path.size());
460
0
        }
461
0
        for (size_t i = 0; i < num_rows; ++i) {
462
0
            auto row_pos = static_cast<int64_t>(row_ids[i]);
463
0
            row_pos_col.insert_data(reinterpret_cast<const char*>(&row_pos), sizeof(row_pos));
464
0
        }
465
0
        for (size_t i = 0; i < num_rows; ++i) {
466
0
            int32_t spec_id = partition_spec_id;
467
0
            spec_id_col.insert_data(reinterpret_cast<const char*>(&spec_id), sizeof(spec_id));
468
0
        }
469
0
        for (size_t i = 0; i < num_rows; ++i) {
470
0
            partition_data_col.insert_data(partition_data_json.data(), partition_data_json.size());
471
0
        }
472
0
        if (nullable_col != nullptr) {
473
0
            nullable_col->get_null_map_data().resize_fill(num_rows, 0);
474
0
        }
475
0
        *column_out = std::move(column);
476
0
        return Status::OK();
477
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE27_build_iceberg_rowid_columnERKSt10shared_ptrIKNS_9IDataTypeEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIjSaIjEEiSG_PNS_3COWINS_7IColumnEE11mutable_ptrISN_EE
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE27_build_iceberg_rowid_columnERKSt10shared_ptrIKNS_9IDataTypeEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIjSaIjEEiSG_PNS_3COWINS_7IColumnEE11mutable_ptrISN_EE
478
479
    struct IcebergProfile {
480
        RuntimeProfile::Counter* num_delete_files;
481
        RuntimeProfile::Counter* num_delete_rows;
482
        RuntimeProfile::Counter* delete_files_read_time;
483
        RuntimeProfile::Counter* delete_rows_sort_time;
484
        RuntimeProfile::Counter* parse_delete_file_time;
485
        RuntimeProfile::Counter* decoded_cache_hit_count;
486
        RuntimeProfile::Counter* decoded_cache_miss_count;
487
        RuntimeProfile::Counter* file_cache_hit_count;
488
        RuntimeProfile::Counter* file_cache_miss_count;
489
        RuntimeProfile::Counter* file_cache_peer_read_count;
490
    };
491
492
    bool _need_row_id_column = false;
493
    std::string _current_file_path;
494
    int32_t _partition_spec_id = 0;
495
    std::string _partition_data_json;
496
497
    ShardedKVCache* _kv_cache;
498
    IcebergProfile _iceberg_profile;
499
    const std::vector<int64_t>* _iceberg_delete_rows = nullptr;
500
    const DeletionVector* _iceberg_deletion_vector = nullptr;
501
    std::vector<std::string> _expand_col_names;
502
    std::vector<int32_t> _expand_col_field_ids;
503
    std::vector<ColumnWithTypeAndName> _expand_columns;
504
    std::unordered_map<std::string, ColumnPtr> _missing_initial_default_values;
505
    std::unordered_map<std::string, ColumnPtr> _missing_equality_delete_values;
506
    std::vector<NestedEqualityDeleteColumn> _nested_equality_delete_columns;
507
    std::vector<std::string> _all_required_col_names;
508
    Fileformat _file_format = Fileformat::NONE;
509
510
    const int64_t MIN_SUPPORT_DELETE_FILES_VERSION = 2;
511
    const std::string ICEBERG_FILE_PATH = "file_path";
512
    const std::string ICEBERG_ROW_POS = "pos";
513
    const std::vector<std::string> delete_file_col_names {ICEBERG_FILE_PATH, ICEBERG_ROW_POS};
514
    const std::unordered_map<std::string, uint32_t> DELETE_COL_NAME_TO_BLOCK_IDX = {
515
            {ICEBERG_FILE_PATH, 0}, {ICEBERG_ROW_POS, 1}};
516
    const int ICEBERG_FILE_PATH_INDEX = 0;
517
    const int ICEBERG_FILE_POS_INDEX = 1;
518
    const int READ_DELETE_FILE_BATCH_SIZE = 102400;
519
520
    // all ids that need read for eq delete (from all eq delete files)
521
    std::set<int> _equality_delete_col_ids;
522
    // eq delete column ids -> location of _equality_delete_blocks / _equality_delete_impls
523
    std::map<std::vector<int>, int> _equality_delete_block_map;
524
    // EqualityDeleteBase stores raw pointers to these blocks, so do not modify this vector after
525
    // creating entries in _equality_delete_impls.
526
    std::vector<Block> _equality_delete_blocks;
527
    std::vector<std::unique_ptr<EqualityDeleteBase>> _equality_delete_impls;
528
529
    // id -> block column name
530
    std::unordered_map<int, std::string> _id_to_block_column_name;
531
532
    std::function<std::shared_ptr<segment_v2::RowIdColumnIteratorV2>()>
533
            _create_topn_row_id_column_iterator;
534
535
    static constexpr const char* ROW_LINEAGE_ROW_ID = "_row_id";
536
    static constexpr const char* ROW_LINEAGE_LAST_UPDATED_SEQ_NUMBER =
537
            "_last_updated_sequence_number";
538
    struct RowLineageColumns {
539
        int64_t first_row_id = -1;
540
        int64_t last_updated_sequence_number = -1;
541
    };
542
    RowLineageColumns _row_lineage_columns;
543
};
544
545
// ============================================================================
546
// Template method implementations (must be in header for templates)
547
// ============================================================================
548
549
template <typename BaseReader>
550
61
Status IcebergReaderMixin<BaseReader>::_init_row_filters() {
551
    // COUNT(*) short-circuit. A table-level row count of 0 (an empty current snapshot) is still a
552
    // valid pushed-down count, so accept >= 0 -- matching FileScanner and the Paimon readers. FE sends
553
    // -1 when there is no table-level count; using > 0 here would drop a genuine 0 into the normal read
554
    // path below and never produce the intended CountReader(0).
555
61
    if (this->_push_down_agg_type == TPushAggOp::type::COUNT &&
556
61
        this->get_scan_range().table_format_params.__isset.table_level_row_count &&
557
61
        this->get_scan_range().table_format_params.table_level_row_count >= 0) {
558
0
        return Status::OK();
559
0
    }
560
561
61
    const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
562
61
    const auto& version = table_desc.format_version;
563
61
    if (version < MIN_SUPPORT_DELETE_FILES_VERSION) {
564
6
        return Status::OK();
565
6
    }
566
567
55
    std::vector<TIcebergDeleteFileDesc> position_delete_files;
568
55
    std::vector<TIcebergDeleteFileDesc> equality_delete_files;
569
55
    std::vector<TIcebergDeleteFileDesc> deletion_vector_files;
570
59
    for (const TIcebergDeleteFileDesc& desc : table_desc.delete_files) {
571
59
        if (desc.content == POSITION_DELETE) {
572
0
            position_delete_files.emplace_back(desc);
573
59
        } else if (desc.content == EQUALITY_DELETE) {
574
59
            equality_delete_files.emplace_back(desc);
575
59
        } else if (desc.content == DELETION_VECTOR) {
576
0
            deletion_vector_files.emplace_back(desc);
577
0
        }
578
59
    }
579
580
55
    if (!equality_delete_files.empty()) {
581
53
        RETURN_IF_ERROR(_equality_delete_base(equality_delete_files));
582
53
        this->set_push_down_agg_type(TPushAggOp::NONE);
583
53
    }
584
585
55
    if (!deletion_vector_files.empty()) {
586
0
        if (deletion_vector_files.size() != 1) [[unlikely]] {
587
            /*
588
             * Deletion vectors are a binary representation of deletes for a single data file that is more efficient
589
             * at execution time than position delete files. Unlike equality or position delete files, there can be
590
             * at most one deletion vector for a given data file in a snapshot.
591
             */
592
0
            return Status::DataQualityError("This iceberg data file has multiple DVs.");
593
0
        }
594
0
        RETURN_IF_ERROR(
595
0
                read_deletion_vector(table_desc.original_file_path, deletion_vector_files[0]));
596
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
597
55
    } else if (!position_delete_files.empty()) {
598
0
        RETURN_IF_ERROR(
599
0
                _position_delete_base(table_desc.original_file_path, position_delete_files));
600
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
601
0
    }
602
603
55
    COUNTER_UPDATE(_iceberg_profile.num_delete_files, table_desc.delete_files.size());
604
55
    return Status::OK();
605
55
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE17_init_row_filtersEv
Line
Count
Source
550
37
Status IcebergReaderMixin<BaseReader>::_init_row_filters() {
551
    // COUNT(*) short-circuit. A table-level row count of 0 (an empty current snapshot) is still a
552
    // valid pushed-down count, so accept >= 0 -- matching FileScanner and the Paimon readers. FE sends
553
    // -1 when there is no table-level count; using > 0 here would drop a genuine 0 into the normal read
554
    // path below and never produce the intended CountReader(0).
555
37
    if (this->_push_down_agg_type == TPushAggOp::type::COUNT &&
556
37
        this->get_scan_range().table_format_params.__isset.table_level_row_count &&
557
37
        this->get_scan_range().table_format_params.table_level_row_count >= 0) {
558
0
        return Status::OK();
559
0
    }
560
561
37
    const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
562
37
    const auto& version = table_desc.format_version;
563
37
    if (version < MIN_SUPPORT_DELETE_FILES_VERSION) {
564
4
        return Status::OK();
565
4
    }
566
567
33
    std::vector<TIcebergDeleteFileDesc> position_delete_files;
568
33
    std::vector<TIcebergDeleteFileDesc> equality_delete_files;
569
33
    std::vector<TIcebergDeleteFileDesc> deletion_vector_files;
570
35
    for (const TIcebergDeleteFileDesc& desc : table_desc.delete_files) {
571
35
        if (desc.content == POSITION_DELETE) {
572
0
            position_delete_files.emplace_back(desc);
573
35
        } else if (desc.content == EQUALITY_DELETE) {
574
35
            equality_delete_files.emplace_back(desc);
575
35
        } else if (desc.content == DELETION_VECTOR) {
576
0
            deletion_vector_files.emplace_back(desc);
577
0
        }
578
35
    }
579
580
33
    if (!equality_delete_files.empty()) {
581
32
        RETURN_IF_ERROR(_equality_delete_base(equality_delete_files));
582
32
        this->set_push_down_agg_type(TPushAggOp::NONE);
583
32
    }
584
585
33
    if (!deletion_vector_files.empty()) {
586
0
        if (deletion_vector_files.size() != 1) [[unlikely]] {
587
            /*
588
             * Deletion vectors are a binary representation of deletes for a single data file that is more efficient
589
             * at execution time than position delete files. Unlike equality or position delete files, there can be
590
             * at most one deletion vector for a given data file in a snapshot.
591
             */
592
0
            return Status::DataQualityError("This iceberg data file has multiple DVs.");
593
0
        }
594
0
        RETURN_IF_ERROR(
595
0
                read_deletion_vector(table_desc.original_file_path, deletion_vector_files[0]));
596
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
597
33
    } else if (!position_delete_files.empty()) {
598
0
        RETURN_IF_ERROR(
599
0
                _position_delete_base(table_desc.original_file_path, position_delete_files));
600
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
601
0
    }
602
603
33
    COUNTER_UPDATE(_iceberg_profile.num_delete_files, table_desc.delete_files.size());
604
33
    return Status::OK();
605
33
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE17_init_row_filtersEv
Line
Count
Source
550
24
Status IcebergReaderMixin<BaseReader>::_init_row_filters() {
551
    // COUNT(*) short-circuit. A table-level row count of 0 (an empty current snapshot) is still a
552
    // valid pushed-down count, so accept >= 0 -- matching FileScanner and the Paimon readers. FE sends
553
    // -1 when there is no table-level count; using > 0 here would drop a genuine 0 into the normal read
554
    // path below and never produce the intended CountReader(0).
555
24
    if (this->_push_down_agg_type == TPushAggOp::type::COUNT &&
556
24
        this->get_scan_range().table_format_params.__isset.table_level_row_count &&
557
24
        this->get_scan_range().table_format_params.table_level_row_count >= 0) {
558
0
        return Status::OK();
559
0
    }
560
561
24
    const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
562
24
    const auto& version = table_desc.format_version;
563
24
    if (version < MIN_SUPPORT_DELETE_FILES_VERSION) {
564
2
        return Status::OK();
565
2
    }
566
567
22
    std::vector<TIcebergDeleteFileDesc> position_delete_files;
568
22
    std::vector<TIcebergDeleteFileDesc> equality_delete_files;
569
22
    std::vector<TIcebergDeleteFileDesc> deletion_vector_files;
570
24
    for (const TIcebergDeleteFileDesc& desc : table_desc.delete_files) {
571
24
        if (desc.content == POSITION_DELETE) {
572
0
            position_delete_files.emplace_back(desc);
573
24
        } else if (desc.content == EQUALITY_DELETE) {
574
24
            equality_delete_files.emplace_back(desc);
575
24
        } else if (desc.content == DELETION_VECTOR) {
576
0
            deletion_vector_files.emplace_back(desc);
577
0
        }
578
24
    }
579
580
22
    if (!equality_delete_files.empty()) {
581
21
        RETURN_IF_ERROR(_equality_delete_base(equality_delete_files));
582
21
        this->set_push_down_agg_type(TPushAggOp::NONE);
583
21
    }
584
585
22
    if (!deletion_vector_files.empty()) {
586
0
        if (deletion_vector_files.size() != 1) [[unlikely]] {
587
            /*
588
             * Deletion vectors are a binary representation of deletes for a single data file that is more efficient
589
             * at execution time than position delete files. Unlike equality or position delete files, there can be
590
             * at most one deletion vector for a given data file in a snapshot.
591
             */
592
0
            return Status::DataQualityError("This iceberg data file has multiple DVs.");
593
0
        }
594
0
        RETURN_IF_ERROR(
595
0
                read_deletion_vector(table_desc.original_file_path, deletion_vector_files[0]));
596
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
597
22
    } else if (!position_delete_files.empty()) {
598
0
        RETURN_IF_ERROR(
599
0
                _position_delete_base(table_desc.original_file_path, position_delete_files));
600
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
601
0
    }
602
603
22
    COUNTER_UPDATE(_iceberg_profile.num_delete_files, table_desc.delete_files.size());
604
22
    return Status::OK();
605
22
}
606
607
template <typename BaseReader>
608
bool IcebergReaderMixin<BaseReader>::_find_parquet_equality_delete_path(
609
        const FieldSchema& field, int32_t field_id, std::vector<const FieldSchema*>* path,
610
75
        std::vector<size_t>* child_indexes) {
611
75
    DORIS_CHECK(path != nullptr);
612
75
    DORIS_CHECK(child_indexes != nullptr);
613
75
    path->push_back(&field);
614
75
    if (field.field_id == field_id) {
615
43
        return true;
616
43
    }
617
39
    for (size_t index = 0; index < field.children.size(); ++index) {
618
26
        child_indexes->push_back(index);
619
26
        if (_find_parquet_equality_delete_path(field.children[index], field_id, path,
620
26
                                               child_indexes)) {
621
19
            return true;
622
19
        }
623
7
        child_indexes->pop_back();
624
7
    }
625
13
    path->pop_back();
626
13
    return false;
627
32
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE34_find_parquet_equality_delete_pathERKNS_11FieldSchemaEiPSt6vectorIPS4_SaIS7_EEPS6_ImSaImEE
Line
Count
Source
610
75
        std::vector<size_t>* child_indexes) {
611
75
    DORIS_CHECK(path != nullptr);
612
75
    DORIS_CHECK(child_indexes != nullptr);
613
75
    path->push_back(&field);
614
75
    if (field.field_id == field_id) {
615
43
        return true;
616
43
    }
617
39
    for (size_t index = 0; index < field.children.size(); ++index) {
618
26
        child_indexes->push_back(index);
619
26
        if (_find_parquet_equality_delete_path(field.children[index], field_id, path,
620
26
                                               child_indexes)) {
621
19
            return true;
622
19
        }
623
7
        child_indexes->pop_back();
624
7
    }
625
13
    path->pop_back();
626
13
    return false;
627
32
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE34_find_parquet_equality_delete_pathERKNS_11FieldSchemaEiPSt6vectorIPS4_SaIS7_EEPS6_ImSaImEE
628
629
template <typename BaseReader>
630
bool IcebergReaderMixin<BaseReader>::_find_orc_equality_delete_path(
631
        const orc::Type* field, const std::string& field_name, int32_t field_id,
632
        std::vector<const orc::Type*>* path, std::vector<std::string>* names,
633
40
        std::vector<size_t>* child_indexes) {
634
40
    DORIS_CHECK(field != nullptr);
635
40
    DORIS_CHECK(path != nullptr);
636
40
    DORIS_CHECK(names != nullptr);
637
40
    DORIS_CHECK(child_indexes != nullptr);
638
40
    path->push_back(field);
639
40
    names->push_back(field_name);
640
40
    if (field->hasAttributeKey("iceberg.id") &&
641
40
        std::stoi(field->getAttributeValue("iceberg.id")) == field_id) {
642
28
        return true;
643
28
    }
644
12
    for (size_t index = 0; index < field->getSubtypeCount(); ++index) {
645
6
        child_indexes->push_back(index);
646
6
        if (_find_orc_equality_delete_path(field->getSubtype(index), field->getFieldName(index),
647
6
                                           field_id, path, names, child_indexes)) {
648
6
            return true;
649
6
        }
650
0
        child_indexes->pop_back();
651
0
    }
652
6
    path->pop_back();
653
6
    names->pop_back();
654
6
    return false;
655
12
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE30_find_orc_equality_delete_pathEPKN3orc4TypeERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiPSt6vectorIS6_SaIS6_EEPSF_ISC_SaISC_EEPSF_ImSaImEE
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE30_find_orc_equality_delete_pathEPKN3orc4TypeERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiPSt6vectorIS6_SaIS6_EEPSF_ISC_SaISC_EEPSF_ImSaImEE
Line
Count
Source
633
40
        std::vector<size_t>* child_indexes) {
634
40
    DORIS_CHECK(field != nullptr);
635
40
    DORIS_CHECK(path != nullptr);
636
40
    DORIS_CHECK(names != nullptr);
637
40
    DORIS_CHECK(child_indexes != nullptr);
638
40
    path->push_back(field);
639
40
    names->push_back(field_name);
640
40
    if (field->hasAttributeKey("iceberg.id") &&
641
40
        std::stoi(field->getAttributeValue("iceberg.id")) == field_id) {
642
28
        return true;
643
28
    }
644
12
    for (size_t index = 0; index < field->getSubtypeCount(); ++index) {
645
6
        child_indexes->push_back(index);
646
6
        if (_find_orc_equality_delete_path(field->getSubtype(index), field->getFieldName(index),
647
6
                                           field_id, path, names, child_indexes)) {
648
6
            return true;
649
6
        }
650
0
        child_indexes->pop_back();
651
0
    }
652
6
    path->pop_back();
653
6
    names->pop_back();
654
6
    return false;
655
12
}
656
657
template <typename BaseReader>
658
Status IcebergReaderMixin<BaseReader>::_build_parquet_equality_delete_read_specs(
659
        ParquetReader* reader, const TIcebergDeleteFileDesc& delete_file,
660
35
        std::vector<EqualityDeleteReadSpec>* read_specs) const {
661
35
    DORIS_CHECK(reader != nullptr);
662
35
    DORIS_CHECK(read_specs != nullptr);
663
35
    const FieldDescriptor* delete_field_desc = nullptr;
664
35
    RETURN_IF_ERROR(reader->get_file_metadata_schema(&delete_field_desc));
665
35
    DORIS_CHECK(delete_field_desc != nullptr);
666
43
    for (const auto field_id : delete_file.field_ids) {
667
43
        std::vector<const FieldSchema*> path;
668
43
        std::vector<size_t> child_indexes;
669
49
        for (const auto& root : delete_field_desc->get_fields_schema()) {
670
49
            if (_find_parquet_equality_delete_path(root, field_id, &path, &child_indexes)) {
671
43
                break;
672
43
            }
673
49
        }
674
43
        if (path.empty()) {
675
0
            return Status::DataQualityError(
676
0
                    "missing field id {} when reading equality delete file {}", field_id,
677
0
                    delete_file.path);
678
0
        }
679
43
        const auto* root = path.front();
680
43
        const auto* leaf = path.back();
681
43
        if (!leaf->children.empty()) {
682
0
            return Status::NotSupported(
683
0
                    "Iceberg equality delete does not support complex column {}", leaf->name);
684
0
        }
685
43
        const auto delete_key_type = make_nullable(leaf->data_type);
686
43
        read_specs->push_back({
687
43
                .nested_field =
688
43
                        {
689
43
                                .field_id = field_id,
690
43
                                .block_name = leaf->name,
691
43
                                .leaf_type = equality_delete_key_type(_find_schema_field(field_id),
692
43
                                                                      delete_key_type),
693
43
                                .source_leaf_type = delete_key_type,
694
43
                                .child_indexes = std::move(child_indexes),
695
43
                                .missing_value = nullptr,
696
43
                        },
697
43
                .leaf_name = leaf->name,
698
43
                .root_name = root->name,
699
43
                .root_type = make_nullable(root->data_type),
700
43
        });
701
43
    }
702
35
    return Status::OK();
703
35
}
_ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE41_build_parquet_equality_delete_read_specsEPS1_RKNS_22TIcebergDeleteFileDescEPSt6vectorINS2_22EqualityDeleteReadSpecESaIS8_EE
Line
Count
Source
660
35
        std::vector<EqualityDeleteReadSpec>* read_specs) const {
661
35
    DORIS_CHECK(reader != nullptr);
662
35
    DORIS_CHECK(read_specs != nullptr);
663
35
    const FieldDescriptor* delete_field_desc = nullptr;
664
35
    RETURN_IF_ERROR(reader->get_file_metadata_schema(&delete_field_desc));
665
35
    DORIS_CHECK(delete_field_desc != nullptr);
666
43
    for (const auto field_id : delete_file.field_ids) {
667
43
        std::vector<const FieldSchema*> path;
668
43
        std::vector<size_t> child_indexes;
669
49
        for (const auto& root : delete_field_desc->get_fields_schema()) {
670
49
            if (_find_parquet_equality_delete_path(root, field_id, &path, &child_indexes)) {
671
43
                break;
672
43
            }
673
49
        }
674
43
        if (path.empty()) {
675
0
            return Status::DataQualityError(
676
0
                    "missing field id {} when reading equality delete file {}", field_id,
677
0
                    delete_file.path);
678
0
        }
679
43
        const auto* root = path.front();
680
43
        const auto* leaf = path.back();
681
43
        if (!leaf->children.empty()) {
682
0
            return Status::NotSupported(
683
0
                    "Iceberg equality delete does not support complex column {}", leaf->name);
684
0
        }
685
43
        const auto delete_key_type = make_nullable(leaf->data_type);
686
43
        read_specs->push_back({
687
43
                .nested_field =
688
43
                        {
689
43
                                .field_id = field_id,
690
43
                                .block_name = leaf->name,
691
43
                                .leaf_type = equality_delete_key_type(_find_schema_field(field_id),
692
43
                                                                      delete_key_type),
693
43
                                .source_leaf_type = delete_key_type,
694
43
                                .child_indexes = std::move(child_indexes),
695
43
                                .missing_value = nullptr,
696
43
                        },
697
43
                .leaf_name = leaf->name,
698
43
                .root_name = root->name,
699
43
                .root_type = make_nullable(root->data_type),
700
43
        });
701
43
    }
702
35
    return Status::OK();
703
35
}
Unexecuted instantiation: _ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE41_build_parquet_equality_delete_read_specsEPNS_13ParquetReaderERKNS_22TIcebergDeleteFileDescEPSt6vectorINS2_22EqualityDeleteReadSpecESaIS9_EE
704
705
template <typename BaseReader>
706
Status IcebergReaderMixin<BaseReader>::_build_orc_equality_delete_read_specs(
707
        OrcReader* reader, const TIcebergDeleteFileDesc& delete_file,
708
24
        std::vector<EqualityDeleteReadSpec>* read_specs) const {
709
24
    DORIS_CHECK(reader != nullptr);
710
24
    DORIS_CHECK(read_specs != nullptr);
711
24
    const auto* delete_root = reader->get_file_root_type();
712
24
    DORIS_CHECK(delete_root != nullptr);
713
28
    for (const auto field_id : delete_file.field_ids) {
714
28
        std::vector<const orc::Type*> path;
715
28
        std::vector<std::string> names;
716
28
        std::vector<size_t> child_indexes;
717
34
        for (size_t root_index = 0; root_index < delete_root->getSubtypeCount(); ++root_index) {
718
34
            if (_find_orc_equality_delete_path(delete_root->getSubtype(root_index),
719
34
                                               delete_root->getFieldName(root_index), field_id,
720
34
                                               &path, &names, &child_indexes)) {
721
28
                break;
722
28
            }
723
34
        }
724
28
        if (path.empty()) {
725
0
            return Status::DataQualityError(
726
0
                    "missing field id {} when reading equality delete file {}", field_id,
727
0
                    delete_file.path);
728
0
        }
729
28
        const auto* root = path.front();
730
28
        const auto* leaf = path.back();
731
28
        if (leaf->getSubtypeCount() > 0) {
732
0
            return Status::NotSupported(
733
0
                    "Iceberg equality delete does not support complex column {}", names.back());
734
0
        }
735
28
        const auto delete_key_type = make_nullable(reader->convert_to_doris_type(leaf));
736
28
        read_specs->push_back({
737
28
                .nested_field =
738
28
                        {
739
28
                                .field_id = field_id,
740
28
                                .block_name = names.back(),
741
28
                                .leaf_type = equality_delete_key_type(_find_schema_field(field_id),
742
28
                                                                      delete_key_type),
743
28
                                .source_leaf_type = delete_key_type,
744
28
                                .child_indexes = std::move(child_indexes),
745
28
                                .missing_value = nullptr,
746
28
                        },
747
28
                .leaf_name = names.back(),
748
28
                .root_name = names.front(),
749
28
                .root_type = make_nullable(reader->convert_to_doris_type(root)),
750
28
        });
751
28
    }
752
24
    return Status::OK();
753
24
}
Unexecuted instantiation: _ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE37_build_orc_equality_delete_read_specsEPNS_9OrcReaderERKNS_22TIcebergDeleteFileDescEPSt6vectorINS2_22EqualityDeleteReadSpecESaIS9_EE
_ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE37_build_orc_equality_delete_read_specsEPS1_RKNS_22TIcebergDeleteFileDescEPSt6vectorINS2_22EqualityDeleteReadSpecESaIS8_EE
Line
Count
Source
708
24
        std::vector<EqualityDeleteReadSpec>* read_specs) const {
709
24
    DORIS_CHECK(reader != nullptr);
710
24
    DORIS_CHECK(read_specs != nullptr);
711
24
    const auto* delete_root = reader->get_file_root_type();
712
24
    DORIS_CHECK(delete_root != nullptr);
713
28
    for (const auto field_id : delete_file.field_ids) {
714
28
        std::vector<const orc::Type*> path;
715
28
        std::vector<std::string> names;
716
28
        std::vector<size_t> child_indexes;
717
34
        for (size_t root_index = 0; root_index < delete_root->getSubtypeCount(); ++root_index) {
718
34
            if (_find_orc_equality_delete_path(delete_root->getSubtype(root_index),
719
34
                                               delete_root->getFieldName(root_index), field_id,
720
34
                                               &path, &names, &child_indexes)) {
721
28
                break;
722
28
            }
723
34
        }
724
28
        if (path.empty()) {
725
0
            return Status::DataQualityError(
726
0
                    "missing field id {} when reading equality delete file {}", field_id,
727
0
                    delete_file.path);
728
0
        }
729
28
        const auto* root = path.front();
730
28
        const auto* leaf = path.back();
731
28
        if (leaf->getSubtypeCount() > 0) {
732
0
            return Status::NotSupported(
733
0
                    "Iceberg equality delete does not support complex column {}", names.back());
734
0
        }
735
28
        const auto delete_key_type = make_nullable(reader->convert_to_doris_type(leaf));
736
28
        read_specs->push_back({
737
28
                .nested_field =
738
28
                        {
739
28
                                .field_id = field_id,
740
28
                                .block_name = names.back(),
741
28
                                .leaf_type = equality_delete_key_type(_find_schema_field(field_id),
742
28
                                                                      delete_key_type),
743
28
                                .source_leaf_type = delete_key_type,
744
28
                                .child_indexes = std::move(child_indexes),
745
28
                                .missing_value = nullptr,
746
28
                        },
747
28
                .leaf_name = names.back(),
748
28
                .root_name = names.front(),
749
28
                .root_type = make_nullable(reader->convert_to_doris_type(root)),
750
28
        });
751
28
    }
752
24
    return Status::OK();
753
24
}
754
755
template <typename BaseReader>
756
Status IcebergReaderMixin<BaseReader>::_build_equality_delete_read_specs(
757
        GenericReader* reader, const TIcebergDeleteFileDesc& delete_file,
758
59
        std::vector<EqualityDeleteReadSpec>* read_specs) const {
759
59
    DORIS_CHECK(reader != nullptr);
760
59
    DORIS_CHECK(read_specs != nullptr);
761
59
    if (auto* parquet_reader = typeid_cast<ParquetReader*>(reader)) {
762
35
        return _build_parquet_equality_delete_read_specs(parquet_reader, delete_file, read_specs);
763
35
    }
764
24
    if (auto* orc_reader = typeid_cast<OrcReader*>(reader)) {
765
24
        return _build_orc_equality_delete_read_specs(orc_reader, delete_file, read_specs);
766
24
    }
767
0
    return Status::InternalError("Unsupported format of delete file");
768
24
}
_ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE33_build_equality_delete_read_specsEPNS_13GenericReaderERKNS_22TIcebergDeleteFileDescEPSt6vectorINS2_22EqualityDeleteReadSpecESaIS9_EE
Line
Count
Source
758
35
        std::vector<EqualityDeleteReadSpec>* read_specs) const {
759
35
    DORIS_CHECK(reader != nullptr);
760
35
    DORIS_CHECK(read_specs != nullptr);
761
35
    if (auto* parquet_reader = typeid_cast<ParquetReader*>(reader)) {
762
35
        return _build_parquet_equality_delete_read_specs(parquet_reader, delete_file, read_specs);
763
35
    }
764
0
    if (auto* orc_reader = typeid_cast<OrcReader*>(reader)) {
765
0
        return _build_orc_equality_delete_read_specs(orc_reader, delete_file, read_specs);
766
0
    }
767
0
    return Status::InternalError("Unsupported format of delete file");
768
0
}
_ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE33_build_equality_delete_read_specsEPNS_13GenericReaderERKNS_22TIcebergDeleteFileDescEPSt6vectorINS2_22EqualityDeleteReadSpecESaIS9_EE
Line
Count
Source
758
24
        std::vector<EqualityDeleteReadSpec>* read_specs) const {
759
24
    DORIS_CHECK(reader != nullptr);
760
24
    DORIS_CHECK(read_specs != nullptr);
761
24
    if (auto* parquet_reader = typeid_cast<ParquetReader*>(reader)) {
762
0
        return _build_parquet_equality_delete_read_specs(parquet_reader, delete_file, read_specs);
763
0
    }
764
24
    if (auto* orc_reader = typeid_cast<OrcReader*>(reader)) {
765
24
        return _build_orc_equality_delete_read_specs(orc_reader, delete_file, read_specs);
766
24
    }
767
0
    return Status::InternalError("Unsupported format of delete file");
768
24
}
769
770
template <typename BaseReader>
771
void IcebergReaderMixin<BaseReader>::_register_equality_delete_read_specs(
772
        const std::vector<EqualityDeleteReadSpec>& read_specs,
773
        std::vector<std::string>* delete_col_names, std::vector<DataTypePtr>* delete_col_types,
774
        std::vector<int>* delete_col_ids, std::vector<std::string>* read_root_names,
775
        std::vector<DataTypePtr>* read_root_types,
776
59
        std::unordered_map<std::string, uint32_t>* read_root_positions) {
777
59
    DORIS_CHECK(delete_col_names != nullptr);
778
59
    DORIS_CHECK(delete_col_types != nullptr);
779
59
    DORIS_CHECK(delete_col_ids != nullptr);
780
59
    DORIS_CHECK(read_root_names != nullptr);
781
59
    DORIS_CHECK(read_root_types != nullptr);
782
59
    DORIS_CHECK(read_root_positions != nullptr);
783
71
    for (const auto& spec : read_specs) {
784
71
        delete_col_ids->push_back(spec.nested_field.field_id);
785
71
        delete_col_names->push_back(spec.leaf_name);
786
71
        delete_col_types->push_back(spec.nested_field.leaf_type);
787
71
        if (!_id_to_block_column_name.contains(spec.nested_field.field_id)) {
788
54
            _id_to_block_column_name.emplace(spec.nested_field.field_id, spec.leaf_name);
789
54
            _expand_col_names.push_back(spec.leaf_name);
790
54
            _expand_col_field_ids.push_back(spec.nested_field.field_id);
791
54
            _expand_columns.emplace_back(spec.nested_field.leaf_type->create_column(),
792
54
                                         spec.nested_field.leaf_type, spec.leaf_name);
793
54
        }
794
71
        if (!read_root_positions->contains(spec.root_name)) {
795
67
            read_root_positions->emplace(spec.root_name, read_root_names->size());
796
67
            read_root_names->push_back(spec.root_name);
797
67
            read_root_types->push_back(spec.root_type);
798
67
        }
799
71
    }
800
59
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE36_register_equality_delete_read_specsERKSt6vectorINS2_22EqualityDeleteReadSpecESaIS4_EEPS3_INSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISE_EEPS3_ISt10shared_ptrIKNS_9IDataTypeEESaISL_EEPS3_IiSaIiEESH_SO_PSt13unordered_mapISE_jSt4hashISE_ESt8equal_toISE_ESaISt4pairIKSE_jEEE
Line
Count
Source
776
35
        std::unordered_map<std::string, uint32_t>* read_root_positions) {
777
35
    DORIS_CHECK(delete_col_names != nullptr);
778
35
    DORIS_CHECK(delete_col_types != nullptr);
779
35
    DORIS_CHECK(delete_col_ids != nullptr);
780
35
    DORIS_CHECK(read_root_names != nullptr);
781
35
    DORIS_CHECK(read_root_types != nullptr);
782
35
    DORIS_CHECK(read_root_positions != nullptr);
783
43
    for (const auto& spec : read_specs) {
784
43
        delete_col_ids->push_back(spec.nested_field.field_id);
785
43
        delete_col_names->push_back(spec.leaf_name);
786
43
        delete_col_types->push_back(spec.nested_field.leaf_type);
787
43
        if (!_id_to_block_column_name.contains(spec.nested_field.field_id)) {
788
34
            _id_to_block_column_name.emplace(spec.nested_field.field_id, spec.leaf_name);
789
34
            _expand_col_names.push_back(spec.leaf_name);
790
34
            _expand_col_field_ids.push_back(spec.nested_field.field_id);
791
34
            _expand_columns.emplace_back(spec.nested_field.leaf_type->create_column(),
792
34
                                         spec.nested_field.leaf_type, spec.leaf_name);
793
34
        }
794
43
        if (!read_root_positions->contains(spec.root_name)) {
795
39
            read_root_positions->emplace(spec.root_name, read_root_names->size());
796
39
            read_root_names->push_back(spec.root_name);
797
39
            read_root_types->push_back(spec.root_type);
798
39
        }
799
43
    }
800
35
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE36_register_equality_delete_read_specsERKSt6vectorINS2_22EqualityDeleteReadSpecESaIS4_EEPS3_INSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISE_EEPS3_ISt10shared_ptrIKNS_9IDataTypeEESaISL_EEPS3_IiSaIiEESH_SO_PSt13unordered_mapISE_jSt4hashISE_ESt8equal_toISE_ESaISt4pairIKSE_jEEE
Line
Count
Source
776
24
        std::unordered_map<std::string, uint32_t>* read_root_positions) {
777
24
    DORIS_CHECK(delete_col_names != nullptr);
778
24
    DORIS_CHECK(delete_col_types != nullptr);
779
24
    DORIS_CHECK(delete_col_ids != nullptr);
780
24
    DORIS_CHECK(read_root_names != nullptr);
781
24
    DORIS_CHECK(read_root_types != nullptr);
782
24
    DORIS_CHECK(read_root_positions != nullptr);
783
28
    for (const auto& spec : read_specs) {
784
28
        delete_col_ids->push_back(spec.nested_field.field_id);
785
28
        delete_col_names->push_back(spec.leaf_name);
786
28
        delete_col_types->push_back(spec.nested_field.leaf_type);
787
28
        if (!_id_to_block_column_name.contains(spec.nested_field.field_id)) {
788
20
            _id_to_block_column_name.emplace(spec.nested_field.field_id, spec.leaf_name);
789
20
            _expand_col_names.push_back(spec.leaf_name);
790
20
            _expand_col_field_ids.push_back(spec.nested_field.field_id);
791
20
            _expand_columns.emplace_back(spec.nested_field.leaf_type->create_column(),
792
20
                                         spec.nested_field.leaf_type, spec.leaf_name);
793
20
        }
794
28
        if (!read_root_positions->contains(spec.root_name)) {
795
28
            read_root_positions->emplace(spec.root_name, read_root_names->size());
796
28
            read_root_names->push_back(spec.root_name);
797
28
            read_root_types->push_back(spec.root_type);
798
28
        }
799
28
    }
800
24
}
801
802
template <typename BaseReader>
803
Status IcebergReaderMixin<BaseReader>::_initialize_equality_delete_reader(
804
        GenericReader* reader, const std::vector<std::string>& read_root_names,
805
59
        std::unordered_map<std::string, uint32_t>* read_root_positions) {
806
59
    DORIS_CHECK(reader != nullptr);
807
59
    DORIS_CHECK(read_root_positions != nullptr);
808
59
    if (auto* parquet_reader = typeid_cast<ParquetReader*>(reader)) {
809
        // Delete files have TFileRangeDesc.size=-1, which would cause
810
        // set_fill_columns to return EndOfFile("No row group to read") when filtering is enabled.
811
35
        ParquetInitContext context;
812
35
        context.filter_groups = false;
813
35
        context.column_names = read_root_names;
814
35
        context.col_name_to_block_idx = read_root_positions;
815
35
        return parquet_reader->init_reader(&context);
816
35
    }
817
24
    auto* orc_reader = typeid_cast<OrcReader*>(reader);
818
24
    DORIS_CHECK(orc_reader != nullptr);
819
24
    OrcInitContext context;
820
24
    context.column_names = read_root_names;
821
24
    context.col_name_to_block_idx = read_root_positions;
822
24
    return orc_reader->init_reader(&context);
823
59
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE34_initialize_equality_delete_readerEPNS_13GenericReaderERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISB_EEPSt13unordered_mapISB_jSt4hashISB_ESt8equal_toISB_ESaISt4pairIKSB_jEEE
Line
Count
Source
805
35
        std::unordered_map<std::string, uint32_t>* read_root_positions) {
806
35
    DORIS_CHECK(reader != nullptr);
807
35
    DORIS_CHECK(read_root_positions != nullptr);
808
35
    if (auto* parquet_reader = typeid_cast<ParquetReader*>(reader)) {
809
        // Delete files have TFileRangeDesc.size=-1, which would cause
810
        // set_fill_columns to return EndOfFile("No row group to read") when filtering is enabled.
811
35
        ParquetInitContext context;
812
35
        context.filter_groups = false;
813
35
        context.column_names = read_root_names;
814
35
        context.col_name_to_block_idx = read_root_positions;
815
35
        return parquet_reader->init_reader(&context);
816
35
    }
817
0
    auto* orc_reader = typeid_cast<OrcReader*>(reader);
818
0
    DORIS_CHECK(orc_reader != nullptr);
819
0
    OrcInitContext context;
820
0
    context.column_names = read_root_names;
821
0
    context.col_name_to_block_idx = read_root_positions;
822
0
    return orc_reader->init_reader(&context);
823
35
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE34_initialize_equality_delete_readerEPNS_13GenericReaderERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISB_EEPSt13unordered_mapISB_jSt4hashISB_ESt8equal_toISB_ESaISt4pairIKSB_jEEE
Line
Count
Source
805
24
        std::unordered_map<std::string, uint32_t>* read_root_positions) {
806
24
    DORIS_CHECK(reader != nullptr);
807
24
    DORIS_CHECK(read_root_positions != nullptr);
808
24
    if (auto* parquet_reader = typeid_cast<ParquetReader*>(reader)) {
809
        // Delete files have TFileRangeDesc.size=-1, which would cause
810
        // set_fill_columns to return EndOfFile("No row group to read") when filtering is enabled.
811
0
        ParquetInitContext context;
812
0
        context.filter_groups = false;
813
0
        context.column_names = read_root_names;
814
0
        context.col_name_to_block_idx = read_root_positions;
815
0
        return parquet_reader->init_reader(&context);
816
0
    }
817
24
    auto* orc_reader = typeid_cast<OrcReader*>(reader);
818
24
    DORIS_CHECK(orc_reader != nullptr);
819
24
    OrcInitContext context;
820
24
    context.column_names = read_root_names;
821
24
    context.col_name_to_block_idx = read_root_positions;
822
24
    return orc_reader->init_reader(&context);
823
24
}
824
825
template <typename BaseReader>
826
Status IcebergReaderMixin<BaseReader>::_merge_equality_delete_rows(
827
        GenericReader* reader, const std::vector<EqualityDeleteReadSpec>& read_specs,
828
        const std::vector<std::string>& read_root_names,
829
        const std::vector<DataTypePtr>& read_root_types,
830
        const std::unordered_map<std::string, uint32_t>& read_root_positions,
831
59
        Block* eq_file_block) const {
832
59
    DORIS_CHECK(reader != nullptr);
833
59
    DORIS_CHECK(eq_file_block != nullptr);
834
59
    bool eof = false;
835
142
    while (!eof) {
836
83
        Block raw_block;
837
178
        for (size_t index = 0; index < read_root_names.size(); ++index) {
838
95
            raw_block.insert({read_root_types[index]->create_column(), read_root_types[index],
839
95
                              read_root_names[index]});
840
95
        }
841
83
        size_t read_rows = 0;
842
83
        RETURN_IF_ERROR(reader->get_next_block(&raw_block, &read_rows, &eof));
843
83
        if (read_rows == 0) {
844
24
            continue;
845
24
        }
846
59
        Block key_block;
847
71
        for (const auto& spec : read_specs) {
848
71
            ColumnPtr key_column;
849
71
            RETURN_IF_ERROR(_extract_nested_equality_delete_column(
850
71
                    raw_block.get_by_position(read_root_positions.at(spec.root_name)).column,
851
71
                    spec.nested_field, &key_column));
852
71
            key_block.insert({std::move(key_column), spec.nested_field.leaf_type, spec.leaf_name});
853
71
        }
854
59
        ScopedMutableBlock scoped_mutable_block(eq_file_block);
855
59
        RETURN_IF_ERROR(scoped_mutable_block.mutable_block().merge(key_block));
856
59
    }
857
59
    return Status::OK();
858
59
}
_ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE27_merge_equality_delete_rowsEPNS_13GenericReaderERKSt6vectorINS2_22EqualityDeleteReadSpecESaIS6_EERKS5_INSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISG_EERKS5_ISt10shared_ptrIKNS_9IDataTypeEESaISO_EERKSt13unordered_mapISG_jSt4hashISG_ESt8equal_toISG_ESaISt4pairIKSG_jEEEPNS_5BlockE
Line
Count
Source
831
35
        Block* eq_file_block) const {
832
35
    DORIS_CHECK(reader != nullptr);
833
35
    DORIS_CHECK(eq_file_block != nullptr);
834
35
    bool eof = false;
835
70
    while (!eof) {
836
35
        Block raw_block;
837
74
        for (size_t index = 0; index < read_root_names.size(); ++index) {
838
39
            raw_block.insert({read_root_types[index]->create_column(), read_root_types[index],
839
39
                              read_root_names[index]});
840
39
        }
841
35
        size_t read_rows = 0;
842
35
        RETURN_IF_ERROR(reader->get_next_block(&raw_block, &read_rows, &eof));
843
35
        if (read_rows == 0) {
844
0
            continue;
845
0
        }
846
35
        Block key_block;
847
43
        for (const auto& spec : read_specs) {
848
43
            ColumnPtr key_column;
849
43
            RETURN_IF_ERROR(_extract_nested_equality_delete_column(
850
43
                    raw_block.get_by_position(read_root_positions.at(spec.root_name)).column,
851
43
                    spec.nested_field, &key_column));
852
43
            key_block.insert({std::move(key_column), spec.nested_field.leaf_type, spec.leaf_name});
853
43
        }
854
35
        ScopedMutableBlock scoped_mutable_block(eq_file_block);
855
35
        RETURN_IF_ERROR(scoped_mutable_block.mutable_block().merge(key_block));
856
35
    }
857
35
    return Status::OK();
858
35
}
_ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE27_merge_equality_delete_rowsEPNS_13GenericReaderERKSt6vectorINS2_22EqualityDeleteReadSpecESaIS6_EERKS5_INSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISG_EERKS5_ISt10shared_ptrIKNS_9IDataTypeEESaISO_EERKSt13unordered_mapISG_jSt4hashISG_ESt8equal_toISG_ESaISt4pairIKSG_jEEEPNS_5BlockE
Line
Count
Source
831
24
        Block* eq_file_block) const {
832
24
    DORIS_CHECK(reader != nullptr);
833
24
    DORIS_CHECK(eq_file_block != nullptr);
834
24
    bool eof = false;
835
72
    while (!eof) {
836
48
        Block raw_block;
837
104
        for (size_t index = 0; index < read_root_names.size(); ++index) {
838
56
            raw_block.insert({read_root_types[index]->create_column(), read_root_types[index],
839
56
                              read_root_names[index]});
840
56
        }
841
48
        size_t read_rows = 0;
842
48
        RETURN_IF_ERROR(reader->get_next_block(&raw_block, &read_rows, &eof));
843
48
        if (read_rows == 0) {
844
24
            continue;
845
24
        }
846
24
        Block key_block;
847
28
        for (const auto& spec : read_specs) {
848
28
            ColumnPtr key_column;
849
28
            RETURN_IF_ERROR(_extract_nested_equality_delete_column(
850
28
                    raw_block.get_by_position(read_root_positions.at(spec.root_name)).column,
851
28
                    spec.nested_field, &key_column));
852
28
            key_block.insert({std::move(key_column), spec.nested_field.leaf_type, spec.leaf_name});
853
28
        }
854
24
        ScopedMutableBlock scoped_mutable_block(eq_file_block);
855
24
        RETURN_IF_ERROR(scoped_mutable_block.mutable_block().merge(key_block));
856
24
    }
857
24
    return Status::OK();
858
24
}
859
860
template <typename BaseReader>
861
Status IcebergReaderMixin<BaseReader>::_read_equality_delete_file(
862
60
        const TIcebergDeleteFileDesc& delete_file) {
863
60
    if (!delete_file.__isset.field_ids) [[unlikely]] {
864
0
        return Status::InternalError("missing delete field ids when reading equality delete file");
865
0
    }
866
60
    TFileRangeDesc delete_desc;
867
60
    delete_desc.__set_fs_name(this->get_scan_range().fs_name);
868
60
    delete_desc.path = delete_file.path;
869
60
    delete_desc.start_offset = 0;
870
60
    delete_desc.size = -1;
871
60
    delete_desc.file_size = delete_file.__isset.file_size ? delete_file.file_size : -1;
872
873
60
    std::unique_ptr<GenericReader> reader = _create_equality_reader(delete_desc);
874
60
    RETURN_IF_ERROR(reader->init_schema_reader());
875
59
    std::vector<EqualityDeleteReadSpec> read_specs;
876
59
    RETURN_IF_ERROR(_build_equality_delete_read_specs(reader.get(), delete_file, &read_specs));
877
878
59
    std::vector<std::string> delete_col_names;
879
59
    std::vector<DataTypePtr> delete_col_types;
880
59
    std::vector<int> delete_col_ids;
881
59
    std::vector<std::string> read_root_names;
882
59
    std::vector<DataTypePtr> read_root_types;
883
59
    std::unordered_map<std::string, uint32_t> read_root_positions;
884
59
    _register_equality_delete_read_specs(read_specs, &delete_col_names, &delete_col_types,
885
59
                                         &delete_col_ids, &read_root_names, &read_root_types,
886
59
                                         &read_root_positions);
887
59
    RETURN_IF_ERROR(_initialize_equality_delete_reader(reader.get(), read_root_names,
888
59
                                                       &read_root_positions));
889
890
59
    if (!_equality_delete_block_map.contains(delete_col_ids)) {
891
55
        _equality_delete_block_map.emplace(delete_col_ids, _equality_delete_blocks.size());
892
55
        Block block;
893
55
        _generate_equality_delete_block(&block, delete_col_names, delete_col_types);
894
55
        _equality_delete_blocks.emplace_back(std::move(block));
895
55
    }
896
59
    Block& eq_file_block = _equality_delete_blocks[_equality_delete_block_map[delete_col_ids]];
897
59
    return _merge_equality_delete_rows(reader.get(), read_specs, read_root_names, read_root_types,
898
59
                                       read_root_positions, &eq_file_block);
899
59
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE26_read_equality_delete_fileERKNS_22TIcebergDeleteFileDescE
Line
Count
Source
862
36
        const TIcebergDeleteFileDesc& delete_file) {
863
36
    if (!delete_file.__isset.field_ids) [[unlikely]] {
864
0
        return Status::InternalError("missing delete field ids when reading equality delete file");
865
0
    }
866
36
    TFileRangeDesc delete_desc;
867
36
    delete_desc.__set_fs_name(this->get_scan_range().fs_name);
868
36
    delete_desc.path = delete_file.path;
869
36
    delete_desc.start_offset = 0;
870
36
    delete_desc.size = -1;
871
36
    delete_desc.file_size = delete_file.__isset.file_size ? delete_file.file_size : -1;
872
873
36
    std::unique_ptr<GenericReader> reader = _create_equality_reader(delete_desc);
874
36
    RETURN_IF_ERROR(reader->init_schema_reader());
875
35
    std::vector<EqualityDeleteReadSpec> read_specs;
876
35
    RETURN_IF_ERROR(_build_equality_delete_read_specs(reader.get(), delete_file, &read_specs));
877
878
35
    std::vector<std::string> delete_col_names;
879
35
    std::vector<DataTypePtr> delete_col_types;
880
35
    std::vector<int> delete_col_ids;
881
35
    std::vector<std::string> read_root_names;
882
35
    std::vector<DataTypePtr> read_root_types;
883
35
    std::unordered_map<std::string, uint32_t> read_root_positions;
884
35
    _register_equality_delete_read_specs(read_specs, &delete_col_names, &delete_col_types,
885
35
                                         &delete_col_ids, &read_root_names, &read_root_types,
886
35
                                         &read_root_positions);
887
35
    RETURN_IF_ERROR(_initialize_equality_delete_reader(reader.get(), read_root_names,
888
35
                                                       &read_root_positions));
889
890
35
    if (!_equality_delete_block_map.contains(delete_col_ids)) {
891
33
        _equality_delete_block_map.emplace(delete_col_ids, _equality_delete_blocks.size());
892
33
        Block block;
893
33
        _generate_equality_delete_block(&block, delete_col_names, delete_col_types);
894
33
        _equality_delete_blocks.emplace_back(std::move(block));
895
33
    }
896
35
    Block& eq_file_block = _equality_delete_blocks[_equality_delete_block_map[delete_col_ids]];
897
35
    return _merge_equality_delete_rows(reader.get(), read_specs, read_root_names, read_root_types,
898
35
                                       read_root_positions, &eq_file_block);
899
35
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE26_read_equality_delete_fileERKNS_22TIcebergDeleteFileDescE
Line
Count
Source
862
24
        const TIcebergDeleteFileDesc& delete_file) {
863
24
    if (!delete_file.__isset.field_ids) [[unlikely]] {
864
0
        return Status::InternalError("missing delete field ids when reading equality delete file");
865
0
    }
866
24
    TFileRangeDesc delete_desc;
867
24
    delete_desc.__set_fs_name(this->get_scan_range().fs_name);
868
24
    delete_desc.path = delete_file.path;
869
24
    delete_desc.start_offset = 0;
870
24
    delete_desc.size = -1;
871
24
    delete_desc.file_size = delete_file.__isset.file_size ? delete_file.file_size : -1;
872
873
24
    std::unique_ptr<GenericReader> reader = _create_equality_reader(delete_desc);
874
24
    RETURN_IF_ERROR(reader->init_schema_reader());
875
24
    std::vector<EqualityDeleteReadSpec> read_specs;
876
24
    RETURN_IF_ERROR(_build_equality_delete_read_specs(reader.get(), delete_file, &read_specs));
877
878
24
    std::vector<std::string> delete_col_names;
879
24
    std::vector<DataTypePtr> delete_col_types;
880
24
    std::vector<int> delete_col_ids;
881
24
    std::vector<std::string> read_root_names;
882
24
    std::vector<DataTypePtr> read_root_types;
883
24
    std::unordered_map<std::string, uint32_t> read_root_positions;
884
24
    _register_equality_delete_read_specs(read_specs, &delete_col_names, &delete_col_types,
885
24
                                         &delete_col_ids, &read_root_names, &read_root_types,
886
24
                                         &read_root_positions);
887
24
    RETURN_IF_ERROR(_initialize_equality_delete_reader(reader.get(), read_root_names,
888
24
                                                       &read_root_positions));
889
890
24
    if (!_equality_delete_block_map.contains(delete_col_ids)) {
891
22
        _equality_delete_block_map.emplace(delete_col_ids, _equality_delete_blocks.size());
892
22
        Block block;
893
22
        _generate_equality_delete_block(&block, delete_col_names, delete_col_types);
894
22
        _equality_delete_blocks.emplace_back(std::move(block));
895
22
    }
896
24
    Block& eq_file_block = _equality_delete_blocks[_equality_delete_block_map[delete_col_ids]];
897
24
    return _merge_equality_delete_rows(reader.get(), read_specs, read_root_names, read_root_types,
898
24
                                       read_root_positions, &eq_file_block);
899
24
}
900
901
template <typename BaseReader>
902
Status IcebergReaderMixin<BaseReader>::_equality_delete_base(
903
53
        const std::vector<TIcebergDeleteFileDesc>& delete_files) {
904
59
    for (const auto& delete_file : delete_files) {
905
59
        RETURN_IF_ERROR(_read_equality_delete_file(delete_file));
906
71
        for (const auto field_id : delete_file.field_ids) {
907
71
            _equality_delete_col_ids.insert(field_id);
908
71
        }
909
59
    }
910
55
    for (const auto& [delete_col_ids, block_idx] : _equality_delete_block_map) {
911
55
        auto& eq_file_block = _equality_delete_blocks[block_idx];
912
55
        auto equality_delete_impl =
913
55
                EqualityDeleteBase::get_delete_impl(&eq_file_block, delete_col_ids);
914
55
        RETURN_IF_ERROR(equality_delete_impl->init(this->get_profile()));
915
55
        _equality_delete_impls.emplace_back(std::move(equality_delete_impl));
916
55
    }
917
53
    return Status::OK();
918
53
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_equality_delete_baseERKSt6vectorINS_22TIcebergDeleteFileDescESaIS4_EE
Line
Count
Source
903
32
        const std::vector<TIcebergDeleteFileDesc>& delete_files) {
904
35
    for (const auto& delete_file : delete_files) {
905
35
        RETURN_IF_ERROR(_read_equality_delete_file(delete_file));
906
43
        for (const auto field_id : delete_file.field_ids) {
907
43
            _equality_delete_col_ids.insert(field_id);
908
43
        }
909
35
    }
910
33
    for (const auto& [delete_col_ids, block_idx] : _equality_delete_block_map) {
911
33
        auto& eq_file_block = _equality_delete_blocks[block_idx];
912
33
        auto equality_delete_impl =
913
33
                EqualityDeleteBase::get_delete_impl(&eq_file_block, delete_col_ids);
914
33
        RETURN_IF_ERROR(equality_delete_impl->init(this->get_profile()));
915
33
        _equality_delete_impls.emplace_back(std::move(equality_delete_impl));
916
33
    }
917
32
    return Status::OK();
918
32
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_equality_delete_baseERKSt6vectorINS_22TIcebergDeleteFileDescESaIS4_EE
Line
Count
Source
903
21
        const std::vector<TIcebergDeleteFileDesc>& delete_files) {
904
24
    for (const auto& delete_file : delete_files) {
905
24
        RETURN_IF_ERROR(_read_equality_delete_file(delete_file));
906
28
        for (const auto field_id : delete_file.field_ids) {
907
28
            _equality_delete_col_ids.insert(field_id);
908
28
        }
909
24
    }
910
22
    for (const auto& [delete_col_ids, block_idx] : _equality_delete_block_map) {
911
22
        auto& eq_file_block = _equality_delete_blocks[block_idx];
912
22
        auto equality_delete_impl =
913
22
                EqualityDeleteBase::get_delete_impl(&eq_file_block, delete_col_ids);
914
22
        RETURN_IF_ERROR(equality_delete_impl->init(this->get_profile()));
915
22
        _equality_delete_impls.emplace_back(std::move(equality_delete_impl));
916
22
    }
917
21
    return Status::OK();
918
21
}
919
920
template <typename BaseReader>
921
void IcebergReaderMixin<BaseReader>::_generate_equality_delete_block(
922
        Block* block, const std::vector<std::string>& equality_delete_col_names,
923
55
        const std::vector<DataTypePtr>& equality_delete_col_types) {
924
122
    for (int i = 0; i < equality_delete_col_names.size(); ++i) {
925
67
        DataTypePtr data_type = make_nullable(equality_delete_col_types[i]);
926
67
        MutableColumnPtr data_column = data_type->create_column();
927
67
        block->insert(ColumnWithTypeAndName(std::move(data_column), data_type,
928
67
                                            equality_delete_col_names[i]));
929
67
    }
930
55
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE31_generate_equality_delete_blockEPNS_5BlockERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISB_EERKS5_ISt10shared_ptrIKNS_9IDataTypeEESaISJ_EE
Line
Count
Source
923
33
        const std::vector<DataTypePtr>& equality_delete_col_types) {
924
74
    for (int i = 0; i < equality_delete_col_names.size(); ++i) {
925
41
        DataTypePtr data_type = make_nullable(equality_delete_col_types[i]);
926
41
        MutableColumnPtr data_column = data_type->create_column();
927
41
        block->insert(ColumnWithTypeAndName(std::move(data_column), data_type,
928
41
                                            equality_delete_col_names[i]));
929
41
    }
930
33
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE31_generate_equality_delete_blockEPNS_5BlockERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISB_EERKS5_ISt10shared_ptrIKNS_9IDataTypeEESaISJ_EE
Line
Count
Source
923
22
        const std::vector<DataTypePtr>& equality_delete_col_types) {
924
48
    for (int i = 0; i < equality_delete_col_names.size(); ++i) {
925
26
        DataTypePtr data_type = make_nullable(equality_delete_col_types[i]);
926
26
        MutableColumnPtr data_column = data_type->create_column();
927
26
        block->insert(ColumnWithTypeAndName(std::move(data_column), data_type,
928
26
                                            equality_delete_col_names[i]));
929
26
    }
930
22
}
931
932
template <typename BaseReader>
933
61
Status IcebergReaderMixin<BaseReader>::_expand_block_if_need(Block* block) {
934
61
    std::set<std::string> names;
935
61
    auto block_names = block->get_names();
936
61
    names.insert(block_names.begin(), block_names.end());
937
61
    for (auto& col : _expand_columns) {
938
54
        if (_missing_equality_delete_values.contains(col.name) ||
939
54
            _is_derived_equality_delete_column(col.name)) {
940
            // The reader has no column for a key that is missing from the file or extracted from
941
            // another column; on_after_read_block appends it at the batch's final row count.
942
24
            continue;
943
24
        }
944
30
        if (names.contains(col.name)) {
945
0
            return Status::InternalError("Wrong expand column '{}'", col.name);
946
0
        }
947
30
        names.insert(col.name);
948
30
        (*this->col_name_to_block_idx_ref())[col.name] = block->columns();
949
30
        block->insert({col.type->create_column(), col.type, col.name});
950
30
    }
951
61
    return Status::OK();
952
61
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_expand_block_if_needEPNS_5BlockE
Line
Count
Source
933
37
Status IcebergReaderMixin<BaseReader>::_expand_block_if_need(Block* block) {
934
37
    std::set<std::string> names;
935
37
    auto block_names = block->get_names();
936
37
    names.insert(block_names.begin(), block_names.end());
937
37
    for (auto& col : _expand_columns) {
938
34
        if (_missing_equality_delete_values.contains(col.name) ||
939
34
            _is_derived_equality_delete_column(col.name)) {
940
            // The reader has no column for a key that is missing from the file or extracted from
941
            // another column; on_after_read_block appends it at the batch's final row count.
942
17
            continue;
943
17
        }
944
17
        if (names.contains(col.name)) {
945
0
            return Status::InternalError("Wrong expand column '{}'", col.name);
946
0
        }
947
17
        names.insert(col.name);
948
17
        (*this->col_name_to_block_idx_ref())[col.name] = block->columns();
949
17
        block->insert({col.type->create_column(), col.type, col.name});
950
17
    }
951
37
    return Status::OK();
952
37
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_expand_block_if_needEPNS_5BlockE
Line
Count
Source
933
24
Status IcebergReaderMixin<BaseReader>::_expand_block_if_need(Block* block) {
934
24
    std::set<std::string> names;
935
24
    auto block_names = block->get_names();
936
24
    names.insert(block_names.begin(), block_names.end());
937
24
    for (auto& col : _expand_columns) {
938
20
        if (_missing_equality_delete_values.contains(col.name) ||
939
20
            _is_derived_equality_delete_column(col.name)) {
940
            // The reader has no column for a key that is missing from the file or extracted from
941
            // another column; on_after_read_block appends it at the batch's final row count.
942
7
            continue;
943
7
        }
944
13
        if (names.contains(col.name)) {
945
0
            return Status::InternalError("Wrong expand column '{}'", col.name);
946
0
        }
947
13
        names.insert(col.name);
948
13
        (*this->col_name_to_block_idx_ref())[col.name] = block->columns();
949
13
        block->insert({col.type->create_column(), col.type, col.name});
950
13
    }
951
24
    return Status::OK();
952
24
}
953
954
template <typename BaseReader>
955
156
const schema::external::TStructField* IcebergReaderMixin<BaseReader>::_current_schema_root() const {
956
156
    const auto& scan_params = this->get_scan_params();
957
156
    if (!scan_params.__isset.history_schema_info || scan_params.history_schema_info.empty()) {
958
0
        return nullptr;
959
0
    }
960
156
    const schema::external::TSchema* current_schema = &scan_params.history_schema_info.front();
961
156
    if (scan_params.__isset.current_schema_id) {
962
156
        const auto schema_it = std::ranges::find_if(
963
156
                scan_params.history_schema_info, [&](const schema::external::TSchema& schema) {
964
156
                    return schema.__isset.schema_id &&
965
156
                           schema.schema_id == scan_params.current_schema_id;
966
156
                });
_ZZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE20_current_schema_rootEvENKUlRKNS_6schema8external7TSchemaEE_clES7_
Line
Count
Source
963
107
                scan_params.history_schema_info, [&](const schema::external::TSchema& schema) {
964
107
                    return schema.__isset.schema_id &&
965
107
                           schema.schema_id == scan_params.current_schema_id;
966
107
                });
_ZZNK5doris18IcebergReaderMixinINS_9OrcReaderEE20_current_schema_rootEvENKUlRKNS_6schema8external7TSchemaEE_clES7_
Line
Count
Source
963
49
                scan_params.history_schema_info, [&](const schema::external::TSchema& schema) {
964
49
                    return schema.__isset.schema_id &&
965
49
                           schema.schema_id == scan_params.current_schema_id;
966
49
                });
967
156
        if (schema_it == scan_params.history_schema_info.end()) {
968
0
            return nullptr;
969
0
        }
970
156
        current_schema = &*schema_it;
971
156
    }
972
156
    return current_schema->__isset.root_field ? &current_schema->root_field : nullptr;
973
156
}
_ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE20_current_schema_rootEv
Line
Count
Source
955
107
const schema::external::TStructField* IcebergReaderMixin<BaseReader>::_current_schema_root() const {
956
107
    const auto& scan_params = this->get_scan_params();
957
107
    if (!scan_params.__isset.history_schema_info || scan_params.history_schema_info.empty()) {
958
0
        return nullptr;
959
0
    }
960
107
    const schema::external::TSchema* current_schema = &scan_params.history_schema_info.front();
961
107
    if (scan_params.__isset.current_schema_id) {
962
107
        const auto schema_it = std::ranges::find_if(
963
107
                scan_params.history_schema_info, [&](const schema::external::TSchema& schema) {
964
107
                    return schema.__isset.schema_id &&
965
107
                           schema.schema_id == scan_params.current_schema_id;
966
107
                });
967
107
        if (schema_it == scan_params.history_schema_info.end()) {
968
0
            return nullptr;
969
0
        }
970
107
        current_schema = &*schema_it;
971
107
    }
972
107
    return current_schema->__isset.root_field ? &current_schema->root_field : nullptr;
973
107
}
_ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE20_current_schema_rootEv
Line
Count
Source
955
49
const schema::external::TStructField* IcebergReaderMixin<BaseReader>::_current_schema_root() const {
956
49
    const auto& scan_params = this->get_scan_params();
957
49
    if (!scan_params.__isset.history_schema_info || scan_params.history_schema_info.empty()) {
958
0
        return nullptr;
959
0
    }
960
49
    const schema::external::TSchema* current_schema = &scan_params.history_schema_info.front();
961
49
    if (scan_params.__isset.current_schema_id) {
962
49
        const auto schema_it = std::ranges::find_if(
963
49
                scan_params.history_schema_info, [&](const schema::external::TSchema& schema) {
964
49
                    return schema.__isset.schema_id &&
965
49
                           schema.schema_id == scan_params.current_schema_id;
966
49
                });
967
49
        if (schema_it == scan_params.history_schema_info.end()) {
968
0
            return nullptr;
969
0
        }
970
49
        current_schema = &*schema_it;
971
49
    }
972
49
    return current_schema->__isset.root_field ? &current_schema->root_field : nullptr;
973
49
}
974
975
template <typename BaseReader>
976
const schema::external::TField* IcebergReaderMixin<BaseReader>::_find_current_schema_field(
977
5
        const std::string& name) const {
978
5
    const auto* root = _current_schema_root();
979
5
    if (root == nullptr) {
980
0
        return nullptr;
981
0
    }
982
10
    const auto field = std::ranges::find_if(root->fields, [&](const auto& field_ptr) {
983
10
        return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr &&
984
10
               field_ptr.field_ptr->__isset.name && iequal(field_ptr.field_ptr->name, name);
985
10
    });
_ZZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE26_find_current_schema_fieldERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEENKUlRKT_E_clINS_6schema8external9TFieldPtrEEEDaSD_
Line
Count
Source
982
8
    const auto field = std::ranges::find_if(root->fields, [&](const auto& field_ptr) {
983
8
        return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr &&
984
8
               field_ptr.field_ptr->__isset.name && iequal(field_ptr.field_ptr->name, name);
985
8
    });
_ZZNK5doris18IcebergReaderMixinINS_9OrcReaderEE26_find_current_schema_fieldERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEENKUlRKT_E_clINS_6schema8external9TFieldPtrEEEDaSD_
Line
Count
Source
982
2
    const auto field = std::ranges::find_if(root->fields, [&](const auto& field_ptr) {
983
2
        return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr &&
984
2
               field_ptr.field_ptr->__isset.name && iequal(field_ptr.field_ptr->name, name);
985
2
    });
986
5
    return field == root->fields.end() ? nullptr : field->field_ptr.get();
987
5
}
_ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE26_find_current_schema_fieldERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Line
Count
Source
977
4
        const std::string& name) const {
978
4
    const auto* root = _current_schema_root();
979
4
    if (root == nullptr) {
980
0
        return nullptr;
981
0
    }
982
4
    const auto field = std::ranges::find_if(root->fields, [&](const auto& field_ptr) {
983
4
        return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr &&
984
4
               field_ptr.field_ptr->__isset.name && iequal(field_ptr.field_ptr->name, name);
985
4
    });
986
4
    return field == root->fields.end() ? nullptr : field->field_ptr.get();
987
4
}
_ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE26_find_current_schema_fieldERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Line
Count
Source
977
1
        const std::string& name) const {
978
1
    const auto* root = _current_schema_root();
979
1
    if (root == nullptr) {
980
0
        return nullptr;
981
0
    }
982
1
    const auto field = std::ranges::find_if(root->fields, [&](const auto& field_ptr) {
983
1
        return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr &&
984
1
               field_ptr.field_ptr->__isset.name && iequal(field_ptr.field_ptr->name, name);
985
1
    });
986
1
    return field == root->fields.end() ? nullptr : field->field_ptr.get();
987
1
}
988
989
template <typename BaseReader>
990
const schema::external::TField* IcebergReaderMixin<BaseReader>::_find_schema_field(
991
71
        int32_t field_id) const {
992
71
    auto path = _find_schema_field_path(field_id);
993
71
    return path.empty() ? nullptr : path.back();
994
71
}
_ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE18_find_schema_fieldEi
Line
Count
Source
991
43
        int32_t field_id) const {
992
43
    auto path = _find_schema_field_path(field_id);
993
43
    return path.empty() ? nullptr : path.back();
994
43
}
_ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE18_find_schema_fieldEi
Line
Count
Source
991
28
        int32_t field_id) const {
992
28
    auto path = _find_schema_field_path(field_id);
993
28
    return path.empty() ? nullptr : path.back();
994
28
}
995
996
template <typename BaseReader>
997
bool IcebergReaderMixin<BaseReader>::_find_schema_field_path_in_field(
998
        const schema::external::TField* field, int32_t field_id,
999
466
        std::vector<const schema::external::TField*>* path) {
1000
466
    DORIS_CHECK(path != nullptr);
1001
466
    if (field == nullptr) {
1002
0
        return false;
1003
0
    }
1004
466
    path->push_back(field);
1005
466
    if (field->__isset.id && field->id == field_id) {
1006
150
        return true;
1007
150
    }
1008
316
    if (field->__isset.nestedField) {
1009
89
        if (field->nestedField.__isset.struct_field &&
1010
89
            field->nestedField.struct_field.__isset.fields) {
1011
89
            for (const auto& child_ptr : field->nestedField.struct_field.fields) {
1012
89
                if (child_ptr.__isset.field_ptr && child_ptr.field_ptr != nullptr &&
1013
89
                    _find_schema_field_path_in_field(child_ptr.field_ptr.get(), field_id, path)) {
1014
69
                    return true;
1015
69
                }
1016
89
            }
1017
89
        } else if (field->nestedField.__isset.array_field &&
1018
0
                   field->nestedField.array_field.__isset.item_field) {
1019
0
            const auto& child_ptr = field->nestedField.array_field.item_field;
1020
0
            if (child_ptr.__isset.field_ptr && child_ptr.field_ptr != nullptr &&
1021
0
                _find_schema_field_path_in_field(child_ptr.field_ptr.get(), field_id, path)) {
1022
0
                return true;
1023
0
            }
1024
0
        } else if (field->nestedField.__isset.map_field) {
1025
0
            const auto& map = field->nestedField.map_field;
1026
0
            if (map.__isset.key_field && map.key_field.__isset.field_ptr &&
1027
0
                map.key_field.field_ptr != nullptr &&
1028
0
                _find_schema_field_path_in_field(map.key_field.field_ptr.get(), field_id, path)) {
1029
0
                return true;
1030
0
            }
1031
0
            if (map.__isset.value_field && map.value_field.__isset.field_ptr &&
1032
0
                map.value_field.field_ptr != nullptr &&
1033
0
                _find_schema_field_path_in_field(map.value_field.field_ptr.get(), field_id, path)) {
1034
0
                return true;
1035
0
            }
1036
0
        }
1037
89
    }
1038
247
    path->pop_back();
1039
247
    return false;
1040
316
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE32_find_schema_field_path_in_fieldEPKNS_6schema8external6TFieldEiPSt6vectorIS7_SaIS7_EE
Line
Count
Source
999
319
        std::vector<const schema::external::TField*>* path) {
1000
319
    DORIS_CHECK(path != nullptr);
1001
319
    if (field == nullptr) {
1002
0
        return false;
1003
0
    }
1004
319
    path->push_back(field);
1005
319
    if (field->__isset.id && field->id == field_id) {
1006
102
        return true;
1007
102
    }
1008
217
    if (field->__isset.nestedField) {
1009
65
        if (field->nestedField.__isset.struct_field &&
1010
65
            field->nestedField.struct_field.__isset.fields) {
1011
70
            for (const auto& child_ptr : field->nestedField.struct_field.fields) {
1012
70
                if (child_ptr.__isset.field_ptr && child_ptr.field_ptr != nullptr &&
1013
70
                    _find_schema_field_path_in_field(child_ptr.field_ptr.get(), field_id, path)) {
1014
53
                    return true;
1015
53
                }
1016
70
            }
1017
65
        } else if (field->nestedField.__isset.array_field &&
1018
0
                   field->nestedField.array_field.__isset.item_field) {
1019
0
            const auto& child_ptr = field->nestedField.array_field.item_field;
1020
0
            if (child_ptr.__isset.field_ptr && child_ptr.field_ptr != nullptr &&
1021
0
                _find_schema_field_path_in_field(child_ptr.field_ptr.get(), field_id, path)) {
1022
0
                return true;
1023
0
            }
1024
0
        } else if (field->nestedField.__isset.map_field) {
1025
0
            const auto& map = field->nestedField.map_field;
1026
0
            if (map.__isset.key_field && map.key_field.__isset.field_ptr &&
1027
0
                map.key_field.field_ptr != nullptr &&
1028
0
                _find_schema_field_path_in_field(map.key_field.field_ptr.get(), field_id, path)) {
1029
0
                return true;
1030
0
            }
1031
0
            if (map.__isset.value_field && map.value_field.__isset.field_ptr &&
1032
0
                map.value_field.field_ptr != nullptr &&
1033
0
                _find_schema_field_path_in_field(map.value_field.field_ptr.get(), field_id, path)) {
1034
0
                return true;
1035
0
            }
1036
0
        }
1037
65
    }
1038
164
    path->pop_back();
1039
164
    return false;
1040
217
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE32_find_schema_field_path_in_fieldEPKNS_6schema8external6TFieldEiPSt6vectorIS7_SaIS7_EE
Line
Count
Source
999
147
        std::vector<const schema::external::TField*>* path) {
1000
147
    DORIS_CHECK(path != nullptr);
1001
147
    if (field == nullptr) {
1002
0
        return false;
1003
0
    }
1004
147
    path->push_back(field);
1005
147
    if (field->__isset.id && field->id == field_id) {
1006
48
        return true;
1007
48
    }
1008
99
    if (field->__isset.nestedField) {
1009
24
        if (field->nestedField.__isset.struct_field &&
1010
24
            field->nestedField.struct_field.__isset.fields) {
1011
24
            for (const auto& child_ptr : field->nestedField.struct_field.fields) {
1012
19
                if (child_ptr.__isset.field_ptr && child_ptr.field_ptr != nullptr &&
1013
19
                    _find_schema_field_path_in_field(child_ptr.field_ptr.get(), field_id, path)) {
1014
16
                    return true;
1015
16
                }
1016
19
            }
1017
24
        } else if (field->nestedField.__isset.array_field &&
1018
0
                   field->nestedField.array_field.__isset.item_field) {
1019
0
            const auto& child_ptr = field->nestedField.array_field.item_field;
1020
0
            if (child_ptr.__isset.field_ptr && child_ptr.field_ptr != nullptr &&
1021
0
                _find_schema_field_path_in_field(child_ptr.field_ptr.get(), field_id, path)) {
1022
0
                return true;
1023
0
            }
1024
0
        } else if (field->nestedField.__isset.map_field) {
1025
0
            const auto& map = field->nestedField.map_field;
1026
0
            if (map.__isset.key_field && map.key_field.__isset.field_ptr &&
1027
0
                map.key_field.field_ptr != nullptr &&
1028
0
                _find_schema_field_path_in_field(map.key_field.field_ptr.get(), field_id, path)) {
1029
0
                return true;
1030
0
            }
1031
0
            if (map.__isset.value_field && map.value_field.__isset.field_ptr &&
1032
0
                map.value_field.field_ptr != nullptr &&
1033
0
                _find_schema_field_path_in_field(map.value_field.field_ptr.get(), field_id, path)) {
1034
0
                return true;
1035
0
            }
1036
0
        }
1037
24
    }
1038
83
    path->pop_back();
1039
83
    return false;
1040
99
}
1041
1042
template <typename BaseReader>
1043
bool IcebergReaderMixin<BaseReader>::_find_schema_field_path_in_root(
1044
        const schema::external::TStructField* root, int32_t field_id,
1045
180
        std::vector<const schema::external::TField*>* path) {
1046
180
    DORIS_CHECK(path != nullptr);
1047
180
    if (root == nullptr || !root->__isset.fields) {
1048
0
        return false;
1049
0
    }
1050
377
    return std::ranges::any_of(root->fields, [&](const auto& field_ptr) {
1051
377
        return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr &&
1052
377
               _find_schema_field_path_in_field(field_ptr.field_ptr.get(), field_id, path);
1053
377
    });
_ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE31_find_schema_field_path_in_rootEPKNS_6schema8external12TStructFieldEiPSt6vectorIPKNS4_6TFieldESaISB_EEENKUlRKT_E_clINS4_9TFieldPtrEEEDaSH_
Line
Count
Source
1050
249
    return std::ranges::any_of(root->fields, [&](const auto& field_ptr) {
1051
249
        return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr &&
1052
249
               _find_schema_field_path_in_field(field_ptr.field_ptr.get(), field_id, path);
1053
249
    });
_ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE31_find_schema_field_path_in_rootEPKNS_6schema8external12TStructFieldEiPSt6vectorIPKNS4_6TFieldESaISB_EEENKUlRKT_E_clINS4_9TFieldPtrEEEDaSH_
Line
Count
Source
1050
128
    return std::ranges::any_of(root->fields, [&](const auto& field_ptr) {
1051
128
        return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr &&
1052
128
               _find_schema_field_path_in_field(field_ptr.field_ptr.get(), field_id, path);
1053
128
    });
1054
180
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE31_find_schema_field_path_in_rootEPKNS_6schema8external12TStructFieldEiPSt6vectorIPKNS4_6TFieldESaISB_EE
Line
Count
Source
1045
122
        std::vector<const schema::external::TField*>* path) {
1046
122
    DORIS_CHECK(path != nullptr);
1047
122
    if (root == nullptr || !root->__isset.fields) {
1048
0
        return false;
1049
0
    }
1050
122
    return std::ranges::any_of(root->fields, [&](const auto& field_ptr) {
1051
122
        return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr &&
1052
122
               _find_schema_field_path_in_field(field_ptr.field_ptr.get(), field_id, path);
1053
122
    });
1054
122
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE31_find_schema_field_path_in_rootEPKNS_6schema8external12TStructFieldEiPSt6vectorIPKNS4_6TFieldESaISB_EE
Line
Count
Source
1045
58
        std::vector<const schema::external::TField*>* path) {
1046
58
    DORIS_CHECK(path != nullptr);
1047
58
    if (root == nullptr || !root->__isset.fields) {
1048
0
        return false;
1049
0
    }
1050
58
    return std::ranges::any_of(root->fields, [&](const auto& field_ptr) {
1051
58
        return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr &&
1052
58
               _find_schema_field_path_in_field(field_ptr.field_ptr.get(), field_id, path);
1053
58
    });
1054
58
}
1055
1056
template <typename BaseReader>
1057
std::vector<const schema::external::TField*>
1058
140
IcebergReaderMixin<BaseReader>::_find_schema_field_path(int32_t field_id) const {
1059
140
    std::vector<const schema::external::TField*> path;
1060
140
    if (_find_schema_field_path_in_root(_current_schema_root(), field_id, &path)) {
1061
125
        return path;
1062
125
    }
1063
1064
    // Equality deletes remain applicable after their key is dropped from the current schema.
1065
    // FE can retain that field's metadata in history_schema_info; field IDs are stable, so recover
1066
    // the original initial-default/required semantics from any historical schema that contains it.
1067
15
    const auto& scan_params = this->get_scan_params();
1068
15
    if (!scan_params.__isset.history_schema_info) {
1069
0
        return {};
1070
0
    }
1071
29
    for (const auto& schema : scan_params.history_schema_info) {
1072
29
        if (!schema.__isset.root_field) {
1073
0
            continue;
1074
0
        }
1075
29
        path.clear();
1076
29
        if (_find_schema_field_path_in_root(&schema.root_field, field_id, &path)) {
1077
14
            return path;
1078
14
        }
1079
29
    }
1080
1
    return {};
1081
15
}
_ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE23_find_schema_field_pathEi
Line
Count
Source
1058
92
IcebergReaderMixin<BaseReader>::_find_schema_field_path(int32_t field_id) const {
1059
92
    std::vector<const schema::external::TField*> path;
1060
92
    if (_find_schema_field_path_in_root(_current_schema_root(), field_id, &path)) {
1061
82
        return path;
1062
82
    }
1063
1064
    // Equality deletes remain applicable after their key is dropped from the current schema.
1065
    // FE can retain that field's metadata in history_schema_info; field IDs are stable, so recover
1066
    // the original initial-default/required semantics from any historical schema that contains it.
1067
10
    const auto& scan_params = this->get_scan_params();
1068
10
    if (!scan_params.__isset.history_schema_info) {
1069
0
        return {};
1070
0
    }
1071
19
    for (const auto& schema : scan_params.history_schema_info) {
1072
19
        if (!schema.__isset.root_field) {
1073
0
            continue;
1074
0
        }
1075
19
        path.clear();
1076
19
        if (_find_schema_field_path_in_root(&schema.root_field, field_id, &path)) {
1077
9
            return path;
1078
9
        }
1079
19
    }
1080
1
    return {};
1081
10
}
_ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE23_find_schema_field_pathEi
Line
Count
Source
1058
48
IcebergReaderMixin<BaseReader>::_find_schema_field_path(int32_t field_id) const {
1059
48
    std::vector<const schema::external::TField*> path;
1060
48
    if (_find_schema_field_path_in_root(_current_schema_root(), field_id, &path)) {
1061
43
        return path;
1062
43
    }
1063
1064
    // Equality deletes remain applicable after their key is dropped from the current schema.
1065
    // FE can retain that field's metadata in history_schema_info; field IDs are stable, so recover
1066
    // the original initial-default/required semantics from any historical schema that contains it.
1067
5
    const auto& scan_params = this->get_scan_params();
1068
5
    if (!scan_params.__isset.history_schema_info) {
1069
0
        return {};
1070
0
    }
1071
10
    for (const auto& schema : scan_params.history_schema_info) {
1072
10
        if (!schema.__isset.root_field) {
1073
0
            continue;
1074
0
        }
1075
10
        path.clear();
1076
10
        if (_find_schema_field_path_in_root(&schema.root_field, field_id, &path)) {
1077
5
            return path;
1078
5
        }
1079
10
    }
1080
0
    return {};
1081
5
}
1082
1083
template <typename BaseReader>
1084
Status IcebergReaderMixin<BaseReader>::_extract_nested_equality_delete_column(
1085
        const ColumnPtr& root_column, const NestedEqualityDeleteColumn& nested_field,
1086
105
        ColumnPtr* leaf_column) const {
1087
105
    DORIS_CHECK(static_cast<bool>(root_column));
1088
105
    DORIS_CHECK(nested_field.leaf_type != nullptr);
1089
105
    DORIS_CHECK(leaf_column != nullptr);
1090
105
    const IColumn* current = root_column.get();
1091
105
    std::vector<const NullMap*> ancestor_null_maps;
1092
105
    for (size_t child_index : nested_field.child_indexes) {
1093
57
        if (const auto* nullable = check_and_get_column<ColumnNullable>(*current);
1094
57
            nullable != nullptr) {
1095
57
            ancestor_null_maps.push_back(&nullable->get_null_map_data());
1096
57
            current = &nullable->get_nested_column();
1097
57
        }
1098
57
        const auto* struct_column = check_and_get_column<ColumnStruct>(*current);
1099
57
        if (struct_column == nullptr || child_index >= struct_column->tuple_size()) {
1100
0
            return Status::InternalError(
1101
0
                    "Iceberg equality delete path for field id {} is absent from column {}",
1102
0
                    nested_field.field_id, root_column->get_name());
1103
0
        }
1104
57
        current = &struct_column->get_column(child_index);
1105
57
    }
1106
105
    if (const auto* nullable = check_and_get_column<ColumnNullable>(*current);
1107
105
        nullable != nullptr) {
1108
105
        ancestor_null_maps.push_back(&nullable->get_null_map_data());
1109
105
        current = &nullable->get_nested_column();
1110
105
    }
1111
105
    ColumnPtr repeated_missing_value;
1112
105
    if (static_cast<bool>(nested_field.missing_value)) {
1113
2
        repeated_missing_value = iceberg::repeat_initial_default_column(nested_field.missing_value,
1114
2
                                                                        root_column->size());
1115
2
        current = repeated_missing_value.get();
1116
2
        if (const auto* nullable = check_and_get_column<ColumnNullable>(*current);
1117
2
            nullable != nullptr) {
1118
2
            ancestor_null_maps.push_back(&nullable->get_null_map_data());
1119
2
            current = &nullable->get_nested_column();
1120
2
        }
1121
2
    }
1122
1123
105
    DORIS_CHECK(nested_field.source_leaf_type != nullptr);
1124
105
    auto result = ColumnNullable::create(
1125
105
            remove_nullable(nested_field.source_leaf_type)->create_column(), ColumnUInt8::create());
1126
105
    auto& result_data = result->get_nested_column();
1127
105
    auto& result_null_map = result->get_null_map_data();
1128
105
    result_data.reserve(root_column->size());
1129
105
    result_null_map.reserve(root_column->size());
1130
272
    for (size_t row = 0; row < root_column->size(); ++row) {
1131
167
        bool is_null = false;
1132
278
        for (const auto* null_map : ancestor_null_maps) {
1133
278
            if ((*null_map)[row] != 0) {
1134
11
                is_null = true;
1135
11
                break;
1136
11
            }
1137
278
        }
1138
167
        if (is_null) {
1139
11
            result_data.insert_default();
1140
11
            result_null_map.push_back(1);
1141
156
        } else {
1142
156
            result_data.insert_from(*current, row);
1143
156
            result_null_map.push_back(0);
1144
156
        }
1145
167
    }
1146
105
    return widen_equality_delete_key(std::move(result),
1147
105
                                     make_nullable(nested_field.source_leaf_type),
1148
105
                                     make_nullable(nested_field.leaf_type), leaf_column);
1149
105
}
_ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE38_extract_nested_equality_delete_columnERKNS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS2_26NestedEqualityDeleteColumnEPS7_
Line
Count
Source
1086
67
        ColumnPtr* leaf_column) const {
1087
67
    DORIS_CHECK(static_cast<bool>(root_column));
1088
67
    DORIS_CHECK(nested_field.leaf_type != nullptr);
1089
67
    DORIS_CHECK(leaf_column != nullptr);
1090
67
    const IColumn* current = root_column.get();
1091
67
    std::vector<const NullMap*> ancestor_null_maps;
1092
67
    for (size_t child_index : nested_field.child_indexes) {
1093
42
        if (const auto* nullable = check_and_get_column<ColumnNullable>(*current);
1094
42
            nullable != nullptr) {
1095
42
            ancestor_null_maps.push_back(&nullable->get_null_map_data());
1096
42
            current = &nullable->get_nested_column();
1097
42
        }
1098
42
        const auto* struct_column = check_and_get_column<ColumnStruct>(*current);
1099
42
        if (struct_column == nullptr || child_index >= struct_column->tuple_size()) {
1100
0
            return Status::InternalError(
1101
0
                    "Iceberg equality delete path for field id {} is absent from column {}",
1102
0
                    nested_field.field_id, root_column->get_name());
1103
0
        }
1104
42
        current = &struct_column->get_column(child_index);
1105
42
    }
1106
67
    if (const auto* nullable = check_and_get_column<ColumnNullable>(*current);
1107
67
        nullable != nullptr) {
1108
67
        ancestor_null_maps.push_back(&nullable->get_null_map_data());
1109
67
        current = &nullable->get_nested_column();
1110
67
    }
1111
67
    ColumnPtr repeated_missing_value;
1112
67
    if (static_cast<bool>(nested_field.missing_value)) {
1113
1
        repeated_missing_value = iceberg::repeat_initial_default_column(nested_field.missing_value,
1114
1
                                                                        root_column->size());
1115
1
        current = repeated_missing_value.get();
1116
1
        if (const auto* nullable = check_and_get_column<ColumnNullable>(*current);
1117
1
            nullable != nullptr) {
1118
1
            ancestor_null_maps.push_back(&nullable->get_null_map_data());
1119
1
            current = &nullable->get_nested_column();
1120
1
        }
1121
1
    }
1122
1123
67
    DORIS_CHECK(nested_field.source_leaf_type != nullptr);
1124
67
    auto result = ColumnNullable::create(
1125
67
            remove_nullable(nested_field.source_leaf_type)->create_column(), ColumnUInt8::create());
1126
67
    auto& result_data = result->get_nested_column();
1127
67
    auto& result_null_map = result->get_null_map_data();
1128
67
    result_data.reserve(root_column->size());
1129
67
    result_null_map.reserve(root_column->size());
1130
176
    for (size_t row = 0; row < root_column->size(); ++row) {
1131
109
        bool is_null = false;
1132
189
        for (const auto* null_map : ancestor_null_maps) {
1133
189
            if ((*null_map)[row] != 0) {
1134
6
                is_null = true;
1135
6
                break;
1136
6
            }
1137
189
        }
1138
109
        if (is_null) {
1139
6
            result_data.insert_default();
1140
6
            result_null_map.push_back(1);
1141
103
        } else {
1142
103
            result_data.insert_from(*current, row);
1143
103
            result_null_map.push_back(0);
1144
103
        }
1145
109
    }
1146
67
    return widen_equality_delete_key(std::move(result),
1147
67
                                     make_nullable(nested_field.source_leaf_type),
1148
67
                                     make_nullable(nested_field.leaf_type), leaf_column);
1149
67
}
_ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE38_extract_nested_equality_delete_columnERKNS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS2_26NestedEqualityDeleteColumnEPS7_
Line
Count
Source
1086
38
        ColumnPtr* leaf_column) const {
1087
38
    DORIS_CHECK(static_cast<bool>(root_column));
1088
38
    DORIS_CHECK(nested_field.leaf_type != nullptr);
1089
38
    DORIS_CHECK(leaf_column != nullptr);
1090
38
    const IColumn* current = root_column.get();
1091
38
    std::vector<const NullMap*> ancestor_null_maps;
1092
38
    for (size_t child_index : nested_field.child_indexes) {
1093
15
        if (const auto* nullable = check_and_get_column<ColumnNullable>(*current);
1094
15
            nullable != nullptr) {
1095
15
            ancestor_null_maps.push_back(&nullable->get_null_map_data());
1096
15
            current = &nullable->get_nested_column();
1097
15
        }
1098
15
        const auto* struct_column = check_and_get_column<ColumnStruct>(*current);
1099
15
        if (struct_column == nullptr || child_index >= struct_column->tuple_size()) {
1100
0
            return Status::InternalError(
1101
0
                    "Iceberg equality delete path for field id {} is absent from column {}",
1102
0
                    nested_field.field_id, root_column->get_name());
1103
0
        }
1104
15
        current = &struct_column->get_column(child_index);
1105
15
    }
1106
38
    if (const auto* nullable = check_and_get_column<ColumnNullable>(*current);
1107
38
        nullable != nullptr) {
1108
38
        ancestor_null_maps.push_back(&nullable->get_null_map_data());
1109
38
        current = &nullable->get_nested_column();
1110
38
    }
1111
38
    ColumnPtr repeated_missing_value;
1112
38
    if (static_cast<bool>(nested_field.missing_value)) {
1113
1
        repeated_missing_value = iceberg::repeat_initial_default_column(nested_field.missing_value,
1114
1
                                                                        root_column->size());
1115
1
        current = repeated_missing_value.get();
1116
1
        if (const auto* nullable = check_and_get_column<ColumnNullable>(*current);
1117
1
            nullable != nullptr) {
1118
1
            ancestor_null_maps.push_back(&nullable->get_null_map_data());
1119
1
            current = &nullable->get_nested_column();
1120
1
        }
1121
1
    }
1122
1123
38
    DORIS_CHECK(nested_field.source_leaf_type != nullptr);
1124
38
    auto result = ColumnNullable::create(
1125
38
            remove_nullable(nested_field.source_leaf_type)->create_column(), ColumnUInt8::create());
1126
38
    auto& result_data = result->get_nested_column();
1127
38
    auto& result_null_map = result->get_null_map_data();
1128
38
    result_data.reserve(root_column->size());
1129
38
    result_null_map.reserve(root_column->size());
1130
96
    for (size_t row = 0; row < root_column->size(); ++row) {
1131
58
        bool is_null = false;
1132
89
        for (const auto* null_map : ancestor_null_maps) {
1133
89
            if ((*null_map)[row] != 0) {
1134
5
                is_null = true;
1135
5
                break;
1136
5
            }
1137
89
        }
1138
58
        if (is_null) {
1139
5
            result_data.insert_default();
1140
5
            result_null_map.push_back(1);
1141
53
        } else {
1142
53
            result_data.insert_from(*current, row);
1143
53
            result_null_map.push_back(0);
1144
53
        }
1145
58
    }
1146
38
    return widen_equality_delete_key(std::move(result),
1147
38
                                     make_nullable(nested_field.source_leaf_type),
1148
38
                                     make_nullable(nested_field.leaf_type), leaf_column);
1149
38
}
1150
1151
template <typename BaseReader>
1152
61
Status IcebergReaderMixin<BaseReader>::_materialize_nested_equality_delete_columns(Block* block) {
1153
61
    DORIS_CHECK(block != nullptr);
1154
    // A carrier may be the source of other keys under the same physical root, so extract every
1155
    // leaf before replacing any carrier column with its own leaf.
1156
61
    std::vector<ColumnPtr> leaves;
1157
61
    leaves.reserve(_nested_equality_delete_columns.size());
1158
61
    for (const auto& nested_field : _nested_equality_delete_columns) {
1159
34
        const auto& source_name = nested_field.source_block_name.empty()
1160
34
                                          ? nested_field.block_name
1161
34
                                          : nested_field.source_block_name;
1162
34
        const auto source = this->col_name_to_block_idx_ref()->find(source_name);
1163
34
        DORIS_CHECK(source != this->col_name_to_block_idx_ref()->end());
1164
34
        DORIS_CHECK(source->second < block->columns());
1165
34
        ColumnPtr leaf;
1166
34
        RETURN_IF_ERROR(_extract_nested_equality_delete_column(
1167
34
                block->get_by_position(source->second).column, nested_field, &leaf));
1168
34
        leaves.push_back(std::move(leaf));
1169
34
    }
1170
95
    for (size_t index = 0; index < leaves.size(); ++index) {
1171
34
        const auto& nested_field = _nested_equality_delete_columns[index];
1172
34
        const auto type = make_nullable(nested_field.leaf_type);
1173
34
        auto& positions = *this->col_name_to_block_idx_ref();
1174
34
        if (!nested_field.source_block_name.empty()) {
1175
            // A key extracted from a projected root or another key's carrier is not read, so the
1176
            // block gets its column only now.
1177
11
            DORIS_CHECK(!positions.contains(nested_field.block_name));
1178
11
            positions[nested_field.block_name] = block->columns();
1179
11
            block->insert({std::move(leaves[index]), type, nested_field.block_name});
1180
11
            continue;
1181
11
        }
1182
23
        const auto target = positions.find(nested_field.block_name);
1183
23
        DORIS_CHECK(target != positions.end());
1184
23
        DORIS_CHECK(target->second < block->columns());
1185
23
        auto& column = block->get_by_position(target->second);
1186
23
        column.column = std::move(leaves[index]);
1187
23
        column.type = type;
1188
23
    }
1189
61
    return Status::OK();
1190
61
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE43_materialize_nested_equality_delete_columnsEPNS_5BlockE
Line
Count
Source
1152
37
Status IcebergReaderMixin<BaseReader>::_materialize_nested_equality_delete_columns(Block* block) {
1153
37
    DORIS_CHECK(block != nullptr);
1154
    // A carrier may be the source of other keys under the same physical root, so extract every
1155
    // leaf before replacing any carrier column with its own leaf.
1156
37
    std::vector<ColumnPtr> leaves;
1157
37
    leaves.reserve(_nested_equality_delete_columns.size());
1158
37
    for (const auto& nested_field : _nested_equality_delete_columns) {
1159
24
        const auto& source_name = nested_field.source_block_name.empty()
1160
24
                                          ? nested_field.block_name
1161
24
                                          : nested_field.source_block_name;
1162
24
        const auto source = this->col_name_to_block_idx_ref()->find(source_name);
1163
24
        DORIS_CHECK(source != this->col_name_to_block_idx_ref()->end());
1164
24
        DORIS_CHECK(source->second < block->columns());
1165
24
        ColumnPtr leaf;
1166
24
        RETURN_IF_ERROR(_extract_nested_equality_delete_column(
1167
24
                block->get_by_position(source->second).column, nested_field, &leaf));
1168
24
        leaves.push_back(std::move(leaf));
1169
24
    }
1170
61
    for (size_t index = 0; index < leaves.size(); ++index) {
1171
24
        const auto& nested_field = _nested_equality_delete_columns[index];
1172
24
        const auto type = make_nullable(nested_field.leaf_type);
1173
24
        auto& positions = *this->col_name_to_block_idx_ref();
1174
24
        if (!nested_field.source_block_name.empty()) {
1175
            // A key extracted from a projected root or another key's carrier is not read, so the
1176
            // block gets its column only now.
1177
11
            DORIS_CHECK(!positions.contains(nested_field.block_name));
1178
11
            positions[nested_field.block_name] = block->columns();
1179
11
            block->insert({std::move(leaves[index]), type, nested_field.block_name});
1180
11
            continue;
1181
11
        }
1182
13
        const auto target = positions.find(nested_field.block_name);
1183
13
        DORIS_CHECK(target != positions.end());
1184
13
        DORIS_CHECK(target->second < block->columns());
1185
13
        auto& column = block->get_by_position(target->second);
1186
13
        column.column = std::move(leaves[index]);
1187
13
        column.type = type;
1188
13
    }
1189
37
    return Status::OK();
1190
37
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE43_materialize_nested_equality_delete_columnsEPNS_5BlockE
Line
Count
Source
1152
24
Status IcebergReaderMixin<BaseReader>::_materialize_nested_equality_delete_columns(Block* block) {
1153
24
    DORIS_CHECK(block != nullptr);
1154
    // A carrier may be the source of other keys under the same physical root, so extract every
1155
    // leaf before replacing any carrier column with its own leaf.
1156
24
    std::vector<ColumnPtr> leaves;
1157
24
    leaves.reserve(_nested_equality_delete_columns.size());
1158
24
    for (const auto& nested_field : _nested_equality_delete_columns) {
1159
10
        const auto& source_name = nested_field.source_block_name.empty()
1160
10
                                          ? nested_field.block_name
1161
10
                                          : nested_field.source_block_name;
1162
10
        const auto source = this->col_name_to_block_idx_ref()->find(source_name);
1163
10
        DORIS_CHECK(source != this->col_name_to_block_idx_ref()->end());
1164
10
        DORIS_CHECK(source->second < block->columns());
1165
10
        ColumnPtr leaf;
1166
10
        RETURN_IF_ERROR(_extract_nested_equality_delete_column(
1167
10
                block->get_by_position(source->second).column, nested_field, &leaf));
1168
10
        leaves.push_back(std::move(leaf));
1169
10
    }
1170
34
    for (size_t index = 0; index < leaves.size(); ++index) {
1171
10
        const auto& nested_field = _nested_equality_delete_columns[index];
1172
10
        const auto type = make_nullable(nested_field.leaf_type);
1173
10
        auto& positions = *this->col_name_to_block_idx_ref();
1174
10
        if (!nested_field.source_block_name.empty()) {
1175
            // A key extracted from a projected root or another key's carrier is not read, so the
1176
            // block gets its column only now.
1177
0
            DORIS_CHECK(!positions.contains(nested_field.block_name));
1178
0
            positions[nested_field.block_name] = block->columns();
1179
0
            block->insert({std::move(leaves[index]), type, nested_field.block_name});
1180
0
            continue;
1181
0
        }
1182
10
        const auto target = positions.find(nested_field.block_name);
1183
10
        DORIS_CHECK(target != positions.end());
1184
10
        DORIS_CHECK(target->second < block->columns());
1185
10
        auto& column = block->get_by_position(target->second);
1186
10
        column.column = std::move(leaves[index]);
1187
10
        column.type = type;
1188
10
    }
1189
24
    return Status::OK();
1190
24
}
1191
1192
template <typename BaseReader>
1193
Status IcebergReaderMixin<BaseReader>::_create_missing_equality_delete_value(
1194
        int32_t field_id, const DataTypePtr& delete_key_type, size_t physical_path_size,
1195
21
        ColumnPtr* const value) const {
1196
21
    DORIS_CHECK(delete_key_type != nullptr);
1197
21
    DORIS_CHECK(value != nullptr);
1198
21
    const auto table_path = _find_schema_field_path(field_id);
1199
21
    if (table_path.empty()) {
1200
        // Without field-id-bound current or historical metadata BE cannot distinguish a true NULL
1201
        // initial default from a non-NULL default, so continuing would risk silently keeping or
1202
        // deleting wrong rows.
1203
1
        return Status::InternalError(
1204
1
                "Missing Iceberg schema metadata for equality-delete field id {}", field_id);
1205
1
    }
1206
20
    const size_t missing_index =
1207
20
            physical_path_size < table_path.size() ? physical_path_size : table_path.size() - 1;
1208
20
    const auto* missing_field = table_path[missing_index];
1209
20
    DORIS_CHECK(missing_field != nullptr);
1210
1211
20
    if (!supports_iceberg_scan_semantics_v2(&this->get_scan_params()) &&
1212
20
        !missing_field->__isset.initial_default_value) {
1213
0
        *value = delete_key_type->create_column_const(1, Field());
1214
0
        return Status::OK();
1215
0
    }
1216
1217
20
    DataTypePtr missing_type = delete_key_type;
1218
20
    for (size_t index = table_path.size(); index > missing_index + 1; --index) {
1219
0
        const auto* parent = table_path[index - 2];
1220
0
        const auto* child = table_path[index - 1];
1221
0
        DORIS_CHECK(parent != nullptr);
1222
0
        DORIS_CHECK(child != nullptr);
1223
0
        DORIS_CHECK(child->__isset.name);
1224
0
        if (!parent->__isset.nestedField || !parent->nestedField.__isset.struct_field) {
1225
0
            return Status::NotSupported(
1226
0
                    "Iceberg equality delete field id {} has a non-struct missing ancestor",
1227
0
                    field_id);
1228
0
        }
1229
0
        missing_type = std::make_shared<DataTypeStruct>(DataTypes {std::move(missing_type)},
1230
0
                                                        Strings {child->name});
1231
0
        if (parent->__isset.is_optional && parent->is_optional) {
1232
0
            missing_type = make_nullable(missing_type);
1233
0
        }
1234
0
    }
1235
1236
20
    ColumnPtr missing_root_value;
1237
20
    RETURN_IF_ERROR(iceberg::create_initial_default_column(*missing_field, missing_type,
1238
20
                                                           &missing_root_value));
1239
20
    if (missing_index + 1 == table_path.size()) {
1240
20
        *value = std::move(missing_root_value);
1241
20
        return Status::OK();
1242
20
    }
1243
1244
0
    NestedEqualityDeleteColumn missing_path {
1245
0
            .field_id = field_id,
1246
0
            .block_name = "",
1247
0
            .leaf_type = delete_key_type,
1248
0
            .source_leaf_type = delete_key_type,
1249
0
            .child_indexes = std::vector<size_t>(table_path.size() - missing_index - 1, 0),
1250
0
            .missing_value = nullptr,
1251
0
    };
1252
0
    return _extract_nested_equality_delete_column(missing_root_value, missing_path, value);
1253
20
}
_ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE37_create_missing_equality_delete_valueEiRKSt10shared_ptrIKNS_9IDataTypeEEmPNS_3COWINS_7IColumnEE13immutable_ptrISA_EE
Line
Count
Source
1195
13
        ColumnPtr* const value) const {
1196
13
    DORIS_CHECK(delete_key_type != nullptr);
1197
13
    DORIS_CHECK(value != nullptr);
1198
13
    const auto table_path = _find_schema_field_path(field_id);
1199
13
    if (table_path.empty()) {
1200
        // Without field-id-bound current or historical metadata BE cannot distinguish a true NULL
1201
        // initial default from a non-NULL default, so continuing would risk silently keeping or
1202
        // deleting wrong rows.
1203
1
        return Status::InternalError(
1204
1
                "Missing Iceberg schema metadata for equality-delete field id {}", field_id);
1205
1
    }
1206
12
    const size_t missing_index =
1207
12
            physical_path_size < table_path.size() ? physical_path_size : table_path.size() - 1;
1208
12
    const auto* missing_field = table_path[missing_index];
1209
12
    DORIS_CHECK(missing_field != nullptr);
1210
1211
12
    if (!supports_iceberg_scan_semantics_v2(&this->get_scan_params()) &&
1212
12
        !missing_field->__isset.initial_default_value) {
1213
0
        *value = delete_key_type->create_column_const(1, Field());
1214
0
        return Status::OK();
1215
0
    }
1216
1217
12
    DataTypePtr missing_type = delete_key_type;
1218
12
    for (size_t index = table_path.size(); index > missing_index + 1; --index) {
1219
0
        const auto* parent = table_path[index - 2];
1220
0
        const auto* child = table_path[index - 1];
1221
0
        DORIS_CHECK(parent != nullptr);
1222
0
        DORIS_CHECK(child != nullptr);
1223
0
        DORIS_CHECK(child->__isset.name);
1224
0
        if (!parent->__isset.nestedField || !parent->nestedField.__isset.struct_field) {
1225
0
            return Status::NotSupported(
1226
0
                    "Iceberg equality delete field id {} has a non-struct missing ancestor",
1227
0
                    field_id);
1228
0
        }
1229
0
        missing_type = std::make_shared<DataTypeStruct>(DataTypes {std::move(missing_type)},
1230
0
                                                        Strings {child->name});
1231
0
        if (parent->__isset.is_optional && parent->is_optional) {
1232
0
            missing_type = make_nullable(missing_type);
1233
0
        }
1234
0
    }
1235
1236
12
    ColumnPtr missing_root_value;
1237
12
    RETURN_IF_ERROR(iceberg::create_initial_default_column(*missing_field, missing_type,
1238
12
                                                           &missing_root_value));
1239
12
    if (missing_index + 1 == table_path.size()) {
1240
12
        *value = std::move(missing_root_value);
1241
12
        return Status::OK();
1242
12
    }
1243
1244
0
    NestedEqualityDeleteColumn missing_path {
1245
0
            .field_id = field_id,
1246
0
            .block_name = "",
1247
0
            .leaf_type = delete_key_type,
1248
0
            .source_leaf_type = delete_key_type,
1249
0
            .child_indexes = std::vector<size_t>(table_path.size() - missing_index - 1, 0),
1250
0
            .missing_value = nullptr,
1251
0
    };
1252
0
    return _extract_nested_equality_delete_column(missing_root_value, missing_path, value);
1253
12
}
_ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE37_create_missing_equality_delete_valueEiRKSt10shared_ptrIKNS_9IDataTypeEEmPNS_3COWINS_7IColumnEE13immutable_ptrISA_EE
Line
Count
Source
1195
8
        ColumnPtr* const value) const {
1196
8
    DORIS_CHECK(delete_key_type != nullptr);
1197
8
    DORIS_CHECK(value != nullptr);
1198
8
    const auto table_path = _find_schema_field_path(field_id);
1199
8
    if (table_path.empty()) {
1200
        // Without field-id-bound current or historical metadata BE cannot distinguish a true NULL
1201
        // initial default from a non-NULL default, so continuing would risk silently keeping or
1202
        // deleting wrong rows.
1203
0
        return Status::InternalError(
1204
0
                "Missing Iceberg schema metadata for equality-delete field id {}", field_id);
1205
0
    }
1206
8
    const size_t missing_index =
1207
8
            physical_path_size < table_path.size() ? physical_path_size : table_path.size() - 1;
1208
8
    const auto* missing_field = table_path[missing_index];
1209
8
    DORIS_CHECK(missing_field != nullptr);
1210
1211
8
    if (!supports_iceberg_scan_semantics_v2(&this->get_scan_params()) &&
1212
8
        !missing_field->__isset.initial_default_value) {
1213
0
        *value = delete_key_type->create_column_const(1, Field());
1214
0
        return Status::OK();
1215
0
    }
1216
1217
8
    DataTypePtr missing_type = delete_key_type;
1218
8
    for (size_t index = table_path.size(); index > missing_index + 1; --index) {
1219
0
        const auto* parent = table_path[index - 2];
1220
0
        const auto* child = table_path[index - 1];
1221
0
        DORIS_CHECK(parent != nullptr);
1222
0
        DORIS_CHECK(child != nullptr);
1223
0
        DORIS_CHECK(child->__isset.name);
1224
0
        if (!parent->__isset.nestedField || !parent->nestedField.__isset.struct_field) {
1225
0
            return Status::NotSupported(
1226
0
                    "Iceberg equality delete field id {} has a non-struct missing ancestor",
1227
0
                    field_id);
1228
0
        }
1229
0
        missing_type = std::make_shared<DataTypeStruct>(DataTypes {std::move(missing_type)},
1230
0
                                                        Strings {child->name});
1231
0
        if (parent->__isset.is_optional && parent->is_optional) {
1232
0
            missing_type = make_nullable(missing_type);
1233
0
        }
1234
0
    }
1235
1236
8
    ColumnPtr missing_root_value;
1237
8
    RETURN_IF_ERROR(iceberg::create_initial_default_column(*missing_field, missing_type,
1238
8
                                                           &missing_root_value));
1239
8
    if (missing_index + 1 == table_path.size()) {
1240
8
        *value = std::move(missing_root_value);
1241
8
        return Status::OK();
1242
8
    }
1243
1244
0
    NestedEqualityDeleteColumn missing_path {
1245
0
            .field_id = field_id,
1246
0
            .block_name = "",
1247
0
            .leaf_type = delete_key_type,
1248
0
            .source_leaf_type = delete_key_type,
1249
0
            .child_indexes = std::vector<size_t>(table_path.size() - missing_index - 1, 0),
1250
0
            .missing_value = nullptr,
1251
0
    };
1252
0
    return _extract_nested_equality_delete_column(missing_root_value, missing_path, value);
1253
8
}
1254
1255
template <typename BaseReader>
1256
Status IcebergReaderMixin<BaseReader>::_register_missing_equality_delete_column(
1257
19
        int32_t field_id, const std::string& name, const DataTypePtr& delete_key_type) {
1258
19
    DORIS_CHECK(delete_key_type != nullptr);
1259
19
    ColumnPtr default_column;
1260
19
    RETURN_IF_ERROR(
1261
19
            _create_missing_equality_delete_value(field_id, delete_key_type, 0, &default_column));
1262
    // The key is appended after the read (on_after_read_block), not by a synthesized-column
1263
    // handler: the reader filters only the columns its block had before the read, and Parquet's
1264
    // lazy read also looks up a tuple slot for every synthesized column, which this hidden key
1265
    // does not have.
1266
18
    const bool inserted =
1267
18
            _missing_equality_delete_values.emplace(name, std::move(default_column)).second;
1268
18
    DORIS_CHECK(inserted);
1269
18
    return Status::OK();
1270
19
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE40_register_missing_equality_delete_columnEiRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
1257
12
        int32_t field_id, const std::string& name, const DataTypePtr& delete_key_type) {
1258
12
    DORIS_CHECK(delete_key_type != nullptr);
1259
12
    ColumnPtr default_column;
1260
12
    RETURN_IF_ERROR(
1261
12
            _create_missing_equality_delete_value(field_id, delete_key_type, 0, &default_column));
1262
    // The key is appended after the read (on_after_read_block), not by a synthesized-column
1263
    // handler: the reader filters only the columns its block had before the read, and Parquet's
1264
    // lazy read also looks up a tuple slot for every synthesized column, which this hidden key
1265
    // does not have.
1266
11
    const bool inserted =
1267
11
            _missing_equality_delete_values.emplace(name, std::move(default_column)).second;
1268
11
    DORIS_CHECK(inserted);
1269
11
    return Status::OK();
1270
12
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE40_register_missing_equality_delete_columnEiRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
1257
7
        int32_t field_id, const std::string& name, const DataTypePtr& delete_key_type) {
1258
7
    DORIS_CHECK(delete_key_type != nullptr);
1259
7
    ColumnPtr default_column;
1260
7
    RETURN_IF_ERROR(
1261
7
            _create_missing_equality_delete_value(field_id, delete_key_type, 0, &default_column));
1262
    // The key is appended after the read (on_after_read_block), not by a synthesized-column
1263
    // handler: the reader filters only the columns its block had before the read, and Parquet's
1264
    // lazy read also looks up a tuple slot for every synthesized column, which this hidden key
1265
    // does not have.
1266
7
    const bool inserted =
1267
7
            _missing_equality_delete_values.emplace(name, std::move(default_column)).second;
1268
7
    DORIS_CHECK(inserted);
1269
7
    return Status::OK();
1270
7
}
1271
1272
template <typename BaseReader>
1273
bool IcebergReaderMixin<BaseReader>::_is_derived_equality_delete_column(
1274
41
        const std::string& name) const {
1275
41
    return std::ranges::any_of(_nested_equality_delete_columns, [&](const auto& nested_field) {
1276
40
        return nested_field.block_name == name && !nested_field.source_block_name.empty();
1277
40
    });
_ZZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE34_is_derived_equality_delete_columnERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEENKUlRKT_E_clINS2_26NestedEqualityDeleteColumnEEEDaSD_
Line
Count
Source
1275
30
    return std::ranges::any_of(_nested_equality_delete_columns, [&](const auto& nested_field) {
1276
30
        return nested_field.block_name == name && !nested_field.source_block_name.empty();
1277
30
    });
_ZZNK5doris18IcebergReaderMixinINS_9OrcReaderEE34_is_derived_equality_delete_columnERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEENKUlRKT_E_clINS2_26NestedEqualityDeleteColumnEEEDaSD_
Line
Count
Source
1275
10
    return std::ranges::any_of(_nested_equality_delete_columns, [&](const auto& nested_field) {
1276
10
        return nested_field.block_name == name && !nested_field.source_block_name.empty();
1277
10
    });
1278
41
}
_ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE34_is_derived_equality_delete_columnERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Line
Count
Source
1274
28
        const std::string& name) const {
1275
28
    return std::ranges::any_of(_nested_equality_delete_columns, [&](const auto& nested_field) {
1276
28
        return nested_field.block_name == name && !nested_field.source_block_name.empty();
1277
28
    });
1278
28
}
_ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE34_is_derived_equality_delete_columnERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Line
Count
Source
1274
13
        const std::string& name) const {
1275
13
    return std::ranges::any_of(_nested_equality_delete_columns, [&](const auto& nested_field) {
1276
13
        return nested_field.block_name == name && !nested_field.source_block_name.empty();
1277
13
    });
1278
13
}
1279
1280
template <typename BaseReader>
1281
Status IcebergReaderMixin<BaseReader>::_materialize_missing_equality_delete_column(
1282
18
        Block* block, const std::string& name, const ColumnPtr& value, size_t rows) {
1283
18
    if (!this->col_name_to_block_idx_ref()->contains(name)) {
1284
        // A key that is absent from the file is not a physical child of the reader, so the block
1285
        // has no column for it: append one before equality-delete filtering. MultiEqualityDelete
1286
        // requires a full, batch-sized column.
1287
13
        const auto expand_col = std::ranges::find_if(
1288
13
                _expand_columns,
1289
15
                [&](const ColumnWithTypeAndName& col) { return col.name == name; });
_ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE43_materialize_missing_equality_delete_columnEPNS_5BlockERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_3COWINS_7IColumnEE13immutable_ptrISE_EEmENKUlRKNS_21ColumnWithTypeAndNameEE_clESM_
Line
Count
Source
1289
7
                [&](const ColumnWithTypeAndName& col) { return col.name == name; });
_ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE43_materialize_missing_equality_delete_columnEPNS_5BlockERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_3COWINS_7IColumnEE13immutable_ptrISE_EEmENKUlRKNS_21ColumnWithTypeAndNameEE_clESM_
Line
Count
Source
1289
8
                [&](const ColumnWithTypeAndName& col) { return col.name == name; });
1290
13
        DORIS_CHECK(expand_col != _expand_columns.end());
1291
13
        (*this->col_name_to_block_idx_ref())[name] = block->columns();
1292
13
        block->insert(
1293
13
                {iceberg::repeat_initial_default_column(value, rows), expand_col->type, name});
1294
13
        return Status::OK();
1295
13
    }
1296
5
    const auto position = this->col_name_to_block_idx_ref()->at(name);
1297
5
    DORIS_CHECK(position < block->columns());
1298
5
    DORIS_CHECK(block->get_by_position(position).column->empty());
1299
    // MultiEqualityDelete hashes each key column directly. Materialize the repeated default so
1300
    // every key has the batch row count; a ColumnConst keeps only one nested value and therefore
1301
    // cannot participate in the row-wise multi-column hash contract.
1302
5
    block->get_by_position(position).column = iceberg::repeat_initial_default_column(value, rows);
1303
5
    return Status::OK();
1304
18
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE43_materialize_missing_equality_delete_columnEPNS_5BlockERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_3COWINS_7IColumnEE13immutable_ptrISE_EEm
Line
Count
Source
1282
11
        Block* block, const std::string& name, const ColumnPtr& value, size_t rows) {
1283
11
    if (!this->col_name_to_block_idx_ref()->contains(name)) {
1284
        // A key that is absent from the file is not a physical child of the reader, so the block
1285
        // has no column for it: append one before equality-delete filtering. MultiEqualityDelete
1286
        // requires a full, batch-sized column.
1287
6
        const auto expand_col = std::ranges::find_if(
1288
6
                _expand_columns,
1289
6
                [&](const ColumnWithTypeAndName& col) { return col.name == name; });
1290
6
        DORIS_CHECK(expand_col != _expand_columns.end());
1291
6
        (*this->col_name_to_block_idx_ref())[name] = block->columns();
1292
6
        block->insert(
1293
6
                {iceberg::repeat_initial_default_column(value, rows), expand_col->type, name});
1294
6
        return Status::OK();
1295
6
    }
1296
5
    const auto position = this->col_name_to_block_idx_ref()->at(name);
1297
5
    DORIS_CHECK(position < block->columns());
1298
5
    DORIS_CHECK(block->get_by_position(position).column->empty());
1299
    // MultiEqualityDelete hashes each key column directly. Materialize the repeated default so
1300
    // every key has the batch row count; a ColumnConst keeps only one nested value and therefore
1301
    // cannot participate in the row-wise multi-column hash contract.
1302
5
    block->get_by_position(position).column = iceberg::repeat_initial_default_column(value, rows);
1303
5
    return Status::OK();
1304
11
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE43_materialize_missing_equality_delete_columnEPNS_5BlockERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_3COWINS_7IColumnEE13immutable_ptrISE_EEm
Line
Count
Source
1282
7
        Block* block, const std::string& name, const ColumnPtr& value, size_t rows) {
1283
7
    if (!this->col_name_to_block_idx_ref()->contains(name)) {
1284
        // A key that is absent from the file is not a physical child of the reader, so the block
1285
        // has no column for it: append one before equality-delete filtering. MultiEqualityDelete
1286
        // requires a full, batch-sized column.
1287
7
        const auto expand_col = std::ranges::find_if(
1288
7
                _expand_columns,
1289
7
                [&](const ColumnWithTypeAndName& col) { return col.name == name; });
1290
7
        DORIS_CHECK(expand_col != _expand_columns.end());
1291
7
        (*this->col_name_to_block_idx_ref())[name] = block->columns();
1292
7
        block->insert(
1293
7
                {iceberg::repeat_initial_default_column(value, rows), expand_col->type, name});
1294
7
        return Status::OK();
1295
7
    }
1296
0
    const auto position = this->col_name_to_block_idx_ref()->at(name);
1297
0
    DORIS_CHECK(position < block->columns());
1298
0
    DORIS_CHECK(block->get_by_position(position).column->empty());
1299
    // MultiEqualityDelete hashes each key column directly. Materialize the repeated default so
1300
    // every key has the batch row count; a ColumnConst keeps only one nested value and therefore
1301
    // cannot participate in the row-wise multi-column hash contract.
1302
0
    block->get_by_position(position).column = iceberg::repeat_initial_default_column(value, rows);
1303
0
    return Status::OK();
1304
7
}
1305
1306
template <typename BaseReader>
1307
Status IcebergReaderMixin<BaseReader>::_materialize_missing_equality_delete_columns(Block* block,
1308
64
                                                                                    size_t rows) {
1309
64
    for (const auto& [name, value] : _missing_equality_delete_values) {
1310
18
        RETURN_IF_ERROR(_materialize_missing_equality_delete_column(block, name, value, rows));
1311
18
    }
1312
64
    return Status::OK();
1313
64
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE44_materialize_missing_equality_delete_columnsEPNS_5BlockEm
Line
Count
Source
1308
40
                                                                                    size_t rows) {
1309
40
    for (const auto& [name, value] : _missing_equality_delete_values) {
1310
11
        RETURN_IF_ERROR(_materialize_missing_equality_delete_column(block, name, value, rows));
1311
11
    }
1312
40
    return Status::OK();
1313
40
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE44_materialize_missing_equality_delete_columnsEPNS_5BlockEm
Line
Count
Source
1308
24
                                                                                    size_t rows) {
1309
24
    for (const auto& [name, value] : _missing_equality_delete_values) {
1310
7
        RETURN_IF_ERROR(_materialize_missing_equality_delete_column(block, name, value, rows));
1311
7
    }
1312
24
    return Status::OK();
1313
24
}
1314
1315
template <typename BaseReader>
1316
61
Status IcebergReaderMixin<BaseReader>::_shrink_block_if_need(Block* block) {
1317
61
    std::set<size_t> positions_to_erase;
1318
61
    for (const std::string& expand_col : _expand_col_names) {
1319
54
        if (!this->col_name_to_block_idx_ref()->contains(expand_col)) {
1320
0
            return Status::InternalError("Wrong erase column '{}', block: {}", expand_col,
1321
0
                                         block->dump_names());
1322
0
        }
1323
54
        positions_to_erase.emplace((*this->col_name_to_block_idx_ref())[expand_col]);
1324
54
    }
1325
61
    block->erase(positions_to_erase);
1326
61
    for (const std::string& expand_col : _expand_col_names) {
1327
54
        this->col_name_to_block_idx_ref()->erase(expand_col);
1328
54
    }
1329
61
    return Status::OK();
1330
61
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_shrink_block_if_needEPNS_5BlockE
Line
Count
Source
1316
37
Status IcebergReaderMixin<BaseReader>::_shrink_block_if_need(Block* block) {
1317
37
    std::set<size_t> positions_to_erase;
1318
37
    for (const std::string& expand_col : _expand_col_names) {
1319
34
        if (!this->col_name_to_block_idx_ref()->contains(expand_col)) {
1320
0
            return Status::InternalError("Wrong erase column '{}', block: {}", expand_col,
1321
0
                                         block->dump_names());
1322
0
        }
1323
34
        positions_to_erase.emplace((*this->col_name_to_block_idx_ref())[expand_col]);
1324
34
    }
1325
37
    block->erase(positions_to_erase);
1326
37
    for (const std::string& expand_col : _expand_col_names) {
1327
34
        this->col_name_to_block_idx_ref()->erase(expand_col);
1328
34
    }
1329
37
    return Status::OK();
1330
37
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_shrink_block_if_needEPNS_5BlockE
Line
Count
Source
1316
24
Status IcebergReaderMixin<BaseReader>::_shrink_block_if_need(Block* block) {
1317
24
    std::set<size_t> positions_to_erase;
1318
24
    for (const std::string& expand_col : _expand_col_names) {
1319
20
        if (!this->col_name_to_block_idx_ref()->contains(expand_col)) {
1320
0
            return Status::InternalError("Wrong erase column '{}', block: {}", expand_col,
1321
0
                                         block->dump_names());
1322
0
        }
1323
20
        positions_to_erase.emplace((*this->col_name_to_block_idx_ref())[expand_col]);
1324
20
    }
1325
24
    block->erase(positions_to_erase);
1326
24
    for (const std::string& expand_col : _expand_col_names) {
1327
20
        this->col_name_to_block_idx_ref()->erase(expand_col);
1328
20
    }
1329
24
    return Status::OK();
1330
24
}
1331
1332
template <typename BaseReader>
1333
Status IcebergReaderMixin<BaseReader>::_position_delete_base(
1334
2
        const std::string data_file_path, const std::vector<TIcebergDeleteFileDesc>& delete_files) {
1335
2
    std::vector<DeleteRows*> delete_rows_array;
1336
2
    int64_t num_delete_rows = 0;
1337
2
    for (const auto& delete_file : delete_files) {
1338
2
        SCOPED_TIMER(_iceberg_profile.delete_files_read_time);
1339
2
        Status create_status = Status::OK();
1340
2
        auto* delete_file_cache = _kv_cache->template get<DeleteFile>(
1341
2
                _delet_file_cache_key(delete_file.path), [&]() -> DeleteFile* {
1342
2
                    auto position_delete = std::make_unique<DeleteFile>();
1343
2
                    TFileRangeDesc delete_file_range;
1344
2
                    delete_file_range.__set_fs_name(this->get_scan_range().fs_name);
1345
2
                    delete_file_range.path = delete_file.path;
1346
2
                    delete_file_range.start_offset = 0;
1347
2
                    delete_file_range.size = -1;
1348
2
                    delete_file_range.file_size =
1349
2
                            delete_file.__isset.file_size ? delete_file.file_size : -1;
1350
2
                    create_status =
1351
2
                            _read_position_delete_file(&delete_file_range, position_delete.get());
1352
2
                    if (!create_status) {
1353
2
                        return nullptr;
1354
2
                    }
1355
0
                    return position_delete.release();
1356
2
                });
_ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlvE_clB5cxx11Ev
Line
Count
Source
1341
2
                _delet_file_cache_key(delete_file.path), [&]() -> DeleteFile* {
1342
2
                    auto position_delete = std::make_unique<DeleteFile>();
1343
2
                    TFileRangeDesc delete_file_range;
1344
2
                    delete_file_range.__set_fs_name(this->get_scan_range().fs_name);
1345
2
                    delete_file_range.path = delete_file.path;
1346
2
                    delete_file_range.start_offset = 0;
1347
2
                    delete_file_range.size = -1;
1348
2
                    delete_file_range.file_size =
1349
2
                            delete_file.__isset.file_size ? delete_file.file_size : -1;
1350
2
                    create_status =
1351
2
                            _read_position_delete_file(&delete_file_range, position_delete.get());
1352
2
                    if (!create_status) {
1353
2
                        return nullptr;
1354
2
                    }
1355
0
                    return position_delete.release();
1356
2
                });
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlvE_clB5cxx11Ev
1357
2
        if (create_status.is<ErrorCode::END_OF_FILE>()) {
1358
0
            continue;
1359
2
        } else if (!create_status.ok()) {
1360
2
            return create_status;
1361
2
        }
1362
1363
0
        DeleteFile& delete_file_map = *((DeleteFile*)delete_file_cache);
1364
0
        auto get_value = [&](const auto& v) {
1365
0
            DeleteRows* row_ids = v.second.get();
1366
0
            if (!row_ids->empty()) {
1367
0
                delete_rows_array.emplace_back(row_ids);
1368
0
                num_delete_rows += row_ids->size();
1369
0
            }
1370
0
        };
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlRKT_E_clISt4pairIKS8_St10unique_ptrIS9_IlSaIlEESt14default_deleteISO_EEEEEDaSH_
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlRKT_E_clISt4pairIKS8_St10unique_ptrIS9_IlSaIlEESt14default_deleteISO_EEEEEDaSH_
1371
0
        delete_file_map.if_contains(data_file_path, get_value);
1372
0
    }
1373
0
    if (num_delete_rows > 0) {
1374
0
        SCOPED_TIMER(_iceberg_profile.delete_rows_sort_time);
1375
0
        _iceberg_delete_rows =
1376
0
                _kv_cache->template get<DeleteRows>(data_file_path, [&]() -> DeleteRows* {
1377
0
                    auto data_file_position_delete = std::make_unique<DeleteRows>();
1378
0
                    _sort_delete_rows(delete_rows_array, num_delete_rows,
1379
0
                                      *data_file_position_delete);
1380
0
                    return data_file_position_delete.release();
1381
0
                });
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlvE0_clEv
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlvE0_clEv
1382
0
        set_delete_rows();
1383
0
        COUNTER_UPDATE(_iceberg_profile.num_delete_rows, num_delete_rows);
1384
0
    }
1385
0
    return Status::OK();
1386
2
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EE
Line
Count
Source
1334
2
        const std::string data_file_path, const std::vector<TIcebergDeleteFileDesc>& delete_files) {
1335
2
    std::vector<DeleteRows*> delete_rows_array;
1336
2
    int64_t num_delete_rows = 0;
1337
2
    for (const auto& delete_file : delete_files) {
1338
2
        SCOPED_TIMER(_iceberg_profile.delete_files_read_time);
1339
2
        Status create_status = Status::OK();
1340
2
        auto* delete_file_cache = _kv_cache->template get<DeleteFile>(
1341
2
                _delet_file_cache_key(delete_file.path), [&]() -> DeleteFile* {
1342
2
                    auto position_delete = std::make_unique<DeleteFile>();
1343
2
                    TFileRangeDesc delete_file_range;
1344
2
                    delete_file_range.__set_fs_name(this->get_scan_range().fs_name);
1345
2
                    delete_file_range.path = delete_file.path;
1346
2
                    delete_file_range.start_offset = 0;
1347
2
                    delete_file_range.size = -1;
1348
2
                    delete_file_range.file_size =
1349
2
                            delete_file.__isset.file_size ? delete_file.file_size : -1;
1350
2
                    create_status =
1351
2
                            _read_position_delete_file(&delete_file_range, position_delete.get());
1352
2
                    if (!create_status) {
1353
2
                        return nullptr;
1354
2
                    }
1355
2
                    return position_delete.release();
1356
2
                });
1357
2
        if (create_status.is<ErrorCode::END_OF_FILE>()) {
1358
0
            continue;
1359
2
        } else if (!create_status.ok()) {
1360
2
            return create_status;
1361
2
        }
1362
1363
0
        DeleteFile& delete_file_map = *((DeleteFile*)delete_file_cache);
1364
0
        auto get_value = [&](const auto& v) {
1365
0
            DeleteRows* row_ids = v.second.get();
1366
0
            if (!row_ids->empty()) {
1367
0
                delete_rows_array.emplace_back(row_ids);
1368
0
                num_delete_rows += row_ids->size();
1369
0
            }
1370
0
        };
1371
0
        delete_file_map.if_contains(data_file_path, get_value);
1372
0
    }
1373
0
    if (num_delete_rows > 0) {
1374
0
        SCOPED_TIMER(_iceberg_profile.delete_rows_sort_time);
1375
0
        _iceberg_delete_rows =
1376
0
                _kv_cache->template get<DeleteRows>(data_file_path, [&]() -> DeleteRows* {
1377
0
                    auto data_file_position_delete = std::make_unique<DeleteRows>();
1378
0
                    _sort_delete_rows(delete_rows_array, num_delete_rows,
1379
0
                                      *data_file_position_delete);
1380
0
                    return data_file_position_delete.release();
1381
0
                });
1382
0
        set_delete_rows();
1383
0
        COUNTER_UPDATE(_iceberg_profile.num_delete_rows, num_delete_rows);
1384
0
    }
1385
0
    return Status::OK();
1386
2
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EE
1387
1388
template <typename BaseReader>
1389
typename IcebergReaderMixin<BaseReader>::PositionDeleteRange
1390
0
IcebergReaderMixin<BaseReader>::_get_range(const ColumnDictI32& file_path_column) {
1391
0
    PositionDeleteRange range;
1392
0
    size_t read_rows = file_path_column.get_data().size();
1393
0
    const int* code_path = file_path_column.get_data().data();
1394
0
    const int* code_path_start = code_path;
1395
0
    const int* code_path_end = code_path + read_rows;
1396
0
    while (code_path < code_path_end) {
1397
0
        int code = code_path[0];
1398
0
        const int* code_end = std::upper_bound(code_path, code_path_end, code);
1399
0
        range.data_file_path.emplace_back(file_path_column.get_value(code).to_string());
1400
0
        range.range.emplace_back(code_path - code_path_start, code_end - code_path_start);
1401
0
        code_path = code_end;
1402
0
    }
1403
0
    return range;
1404
0
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE10_get_rangeERKNS_13ColumnDictI32E
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE10_get_rangeERKNS_13ColumnDictI32E
1405
1406
template <typename BaseReader>
1407
typename IcebergReaderMixin<BaseReader>::PositionDeleteRange
1408
0
IcebergReaderMixin<BaseReader>::_get_range(const ColumnString& file_path_column) {
1409
0
    PositionDeleteRange range;
1410
0
    size_t read_rows = file_path_column.size();
1411
0
    size_t index = 0;
1412
0
    while (index < read_rows) {
1413
0
        StringRef data_path = file_path_column.get_data_at(index);
1414
0
        size_t left = index - 1;
1415
0
        size_t right = read_rows;
1416
0
        while (left + 1 != right) {
1417
0
            size_t mid = left + (right - left) / 2;
1418
0
            if (file_path_column.get_data_at(mid) > data_path) {
1419
0
                right = mid;
1420
0
            } else {
1421
0
                left = mid;
1422
0
            }
1423
0
        }
1424
0
        range.data_file_path.emplace_back(data_path.to_string());
1425
0
        range.range.emplace_back(index, left + 1);
1426
0
        index = left + 1;
1427
0
    }
1428
0
    return range;
1429
0
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE10_get_rangeERKNS_9ColumnStrIjEE
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE10_get_rangeERKNS_9ColumnStrIjEE
1430
1431
template <typename BaseReader>
1432
void IcebergReaderMixin<BaseReader>::_sort_delete_rows(
1433
        const std::vector<std::vector<int64_t>*>& delete_rows_array, int64_t num_delete_rows,
1434
0
        std::vector<int64_t>& result) {
1435
0
    if (delete_rows_array.empty()) {
1436
0
        return;
1437
0
    }
1438
0
    if (delete_rows_array.size() == 1) {
1439
0
        result.resize(num_delete_rows);
1440
0
        memcpy(result.data(), delete_rows_array.front()->data(), sizeof(int64_t) * num_delete_rows);
1441
0
        return;
1442
0
    }
1443
0
    if (delete_rows_array.size() == 2) {
1444
0
        result.resize(num_delete_rows);
1445
0
        std::merge(delete_rows_array.front()->begin(), delete_rows_array.front()->end(),
1446
0
                   delete_rows_array.back()->begin(), delete_rows_array.back()->end(),
1447
0
                   result.begin());
1448
0
        return;
1449
0
    }
1450
1451
0
    using vec_pair = std::pair<std::vector<int64_t>::iterator, std::vector<int64_t>::iterator>;
1452
0
    result.resize(num_delete_rows);
1453
0
    auto row_id_iter = result.begin();
1454
0
    auto iter_end = result.end();
1455
0
    std::vector<vec_pair> rows_array;
1456
0
    for (auto* rows : delete_rows_array) {
1457
0
        if (!rows->empty()) {
1458
0
            rows_array.emplace_back(rows->begin(), rows->end());
1459
0
        }
1460
0
    }
1461
0
    size_t array_size = rows_array.size();
1462
0
    while (row_id_iter != iter_end) {
1463
0
        int64_t min_index = 0;
1464
0
        int64_t min = *rows_array[0].first;
1465
0
        for (size_t i = 0; i < array_size; ++i) {
1466
0
            if (*rows_array[i].first < min) {
1467
0
                min_index = i;
1468
0
                min = *rows_array[i].first;
1469
0
            }
1470
0
        }
1471
0
        *row_id_iter++ = min;
1472
0
        rows_array[min_index].first++;
1473
0
        if (UNLIKELY(rows_array[min_index].first == rows_array[min_index].second)) {
1474
0
            rows_array.erase(rows_array.begin() + min_index);
1475
0
            array_size--;
1476
0
        }
1477
0
    }
1478
0
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE17_sort_delete_rowsERKSt6vectorIPS3_IlSaIlEESaIS6_EElRS5_
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE17_sort_delete_rowsERKSt6vectorIPS3_IlSaIlEESaIS6_EElRS5_
1479
1480
template <typename BaseReader>
1481
Status IcebergReaderMixin<BaseReader>::_gen_position_delete_file_range(
1482
        Block& block, DeleteFile* position_delete, size_t read_rows,
1483
0
        bool file_path_column_dictionary_coded) {
1484
0
    SCOPED_TIMER(_iceberg_profile.parse_delete_file_time);
1485
0
    auto name_to_pos_map = block.get_name_to_pos_map();
1486
0
    ColumnPtr path_column = block.get_by_position(name_to_pos_map[ICEBERG_FILE_PATH]).column;
1487
0
    DCHECK_EQ(path_column->size(), read_rows);
1488
0
    ColumnPtr pos_column = block.get_by_position(name_to_pos_map[ICEBERG_ROW_POS]).column;
1489
0
    if (const auto* nullable_col = check_and_get_column<ColumnNullable>(*path_column);
1490
0
        nullable_col != nullptr) {
1491
0
        if (nullable_col->has_null(0, read_rows)) {
1492
0
            return Status::Corruption(
1493
0
                    "Iceberg position delete column file_path contains null values");
1494
0
        }
1495
0
        path_column = remove_nullable(path_column);
1496
0
    }
1497
0
    if (const auto* nullable_col = check_and_get_column<ColumnNullable>(*pos_column);
1498
0
        nullable_col != nullptr) {
1499
0
        if (nullable_col->has_null(0, read_rows)) {
1500
0
            return Status::Corruption("Iceberg position delete column pos contains null values");
1501
0
        }
1502
0
        pos_column = remove_nullable(pos_column);
1503
0
    }
1504
0
    using ColumnType = typename PrimitiveTypeTraits<TYPE_BIGINT>::ColumnType;
1505
0
    const int64_t* src_data = assert_cast<const ColumnType&>(*pos_column).get_data().data();
1506
0
    PositionDeleteRange range;
1507
0
    if (file_path_column_dictionary_coded) {
1508
0
        range = _get_range(assert_cast<const ColumnDictI32&>(*path_column));
1509
0
    } else {
1510
0
        range = _get_range(assert_cast<const ColumnString&>(*path_column));
1511
0
    }
1512
0
    for (int i = 0; i < range.range.size(); ++i) {
1513
0
        std::string key = range.data_file_path[i];
1514
0
        auto iter = position_delete->find(key);
1515
0
        DeleteRows* delete_rows;
1516
0
        if (iter == position_delete->end()) {
1517
0
            delete_rows = new DeleteRows;
1518
0
            std::unique_ptr<DeleteRows> delete_rows_ptr(delete_rows);
1519
0
            (*position_delete)[key] = std::move(delete_rows_ptr);
1520
0
        } else {
1521
0
            delete_rows = iter->second.get();
1522
0
        }
1523
0
        const int64_t* cpy_start = src_data + range.range[i].first;
1524
0
        const int64_t cpy_count = range.range[i].second - range.range[i].first;
1525
0
        int64_t origin_size = delete_rows->size();
1526
0
        delete_rows->resize(origin_size + cpy_count);
1527
0
        int64_t* dest_position = &(*delete_rows)[origin_size];
1528
0
        memcpy(dest_position, cpy_start, cpy_count * sizeof(int64_t));
1529
0
    }
1530
0
    return Status::OK();
1531
0
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE31_gen_position_delete_file_rangeERNS_5BlockEPN5phmap22parallel_flat_hash_mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt10unique_ptrISt6vectorIlSaIlEESt14default_deleteISG_EESt4hashISC_ESt8equal_toIvESaISt4pairIKSC_SJ_EELm8ESt5mutexEEmb
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE31_gen_position_delete_file_rangeERNS_5BlockEPN5phmap22parallel_flat_hash_mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt10unique_ptrISt6vectorIlSaIlEESt14default_deleteISG_EESt4hashISC_ESt8equal_toIvESaISt4pairIKSC_SJ_EELm8ESt5mutexEEmb
1532
1533
template <typename BaseReader>
1534
Status IcebergReaderMixin<BaseReader>::read_deletion_vector(
1535
1
        const std::string& data_file_path, const TIcebergDeleteFileDesc& delete_file_desc) {
1536
1
    size_t bytes_read = 0;
1537
1
    RETURN_IF_ERROR(validate_iceberg_deletion_vector_descriptor(delete_file_desc, bytes_read));
1538
1539
1
    Status create_status = Status::OK();
1540
1
    SCOPED_TIMER(_iceberg_profile.delete_files_read_time);
1541
1
    bool decoded_cache_hit = false;
1542
1
    _iceberg_deletion_vector = _kv_cache->template get<DeletionVector>(
1543
1
            build_iceberg_deletion_vector_cache_key(data_file_path, delete_file_desc),
1544
1
            [&]() -> DeletionVector* {
1545
1
                auto deletion_vector = std::make_unique<DeletionVector>();
1546
1547
1
                io::FileCacheStatistics file_cache_stats;
1548
1
                IcebergDeleteFileReaderOptions options;
1549
1
                options.state = this->get_state();
1550
1
                options.profile = this->get_profile();
1551
1
                options.scan_params = &this->get_scan_params();
1552
1
                options.io_ctx = this->get_io_ctx();
1553
1
                options.fs_name = &this->get_scan_range().fs_name;
1554
1
                options.deletion_vector_file_cache_stats = &file_cache_stats;
1555
1
                create_status = read_iceberg_deletion_vector(delete_file_desc, options,
1556
1
                                                             deletion_vector.get());
1557
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_hit_count,
1558
1
                               file_cache_stats.num_local_io_total);
1559
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_miss_count,
1560
1
                               file_cache_stats.num_remote_io_total);
1561
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_peer_read_count,
1562
1
                               file_cache_stats.num_peer_io_total);
1563
1
                if (!create_status.ok()) [[unlikely]] {
1564
1
                    return nullptr;
1565
1
                }
1566
1567
0
                SCOPED_TIMER(_iceberg_profile.parse_delete_file_time);
1568
0
                COUNTER_UPDATE(_iceberg_profile.num_delete_rows, deletion_vector->cardinality());
1569
0
                return deletion_vector.release();
1570
1
            },
_ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescEENKUlvE_clEv
Line
Count
Source
1544
1
            [&]() -> DeletionVector* {
1545
1
                auto deletion_vector = std::make_unique<DeletionVector>();
1546
1547
1
                io::FileCacheStatistics file_cache_stats;
1548
1
                IcebergDeleteFileReaderOptions options;
1549
1
                options.state = this->get_state();
1550
1
                options.profile = this->get_profile();
1551
1
                options.scan_params = &this->get_scan_params();
1552
1
                options.io_ctx = this->get_io_ctx();
1553
1
                options.fs_name = &this->get_scan_range().fs_name;
1554
1
                options.deletion_vector_file_cache_stats = &file_cache_stats;
1555
1
                create_status = read_iceberg_deletion_vector(delete_file_desc, options,
1556
1
                                                             deletion_vector.get());
1557
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_hit_count,
1558
1
                               file_cache_stats.num_local_io_total);
1559
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_miss_count,
1560
1
                               file_cache_stats.num_remote_io_total);
1561
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_peer_read_count,
1562
1
                               file_cache_stats.num_peer_io_total);
1563
1
                if (!create_status.ok()) [[unlikely]] {
1564
1
                    return nullptr;
1565
1
                }
1566
1567
0
                SCOPED_TIMER(_iceberg_profile.parse_delete_file_time);
1568
0
                COUNTER_UPDATE(_iceberg_profile.num_delete_rows, deletion_vector->cardinality());
1569
0
                return deletion_vector.release();
1570
1
            },
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescEENKUlvE_clEv
1571
1
            &decoded_cache_hit);
1572
1573
1
    RETURN_IF_ERROR(create_status);
1574
0
    COUNTER_UPDATE(decoded_cache_hit ? _iceberg_profile.decoded_cache_hit_count
1575
0
                                     : _iceberg_profile.decoded_cache_miss_count,
1576
0
                   1);
1577
0
    if (!_iceberg_deletion_vector->isEmpty()) [[likely]] {
1578
0
        set_deletion_vector();
1579
0
    }
1580
0
    return Status::OK();
1581
1
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescE
Line
Count
Source
1535
1
        const std::string& data_file_path, const TIcebergDeleteFileDesc& delete_file_desc) {
1536
1
    size_t bytes_read = 0;
1537
1
    RETURN_IF_ERROR(validate_iceberg_deletion_vector_descriptor(delete_file_desc, bytes_read));
1538
1539
1
    Status create_status = Status::OK();
1540
1
    SCOPED_TIMER(_iceberg_profile.delete_files_read_time);
1541
1
    bool decoded_cache_hit = false;
1542
1
    _iceberg_deletion_vector = _kv_cache->template get<DeletionVector>(
1543
1
            build_iceberg_deletion_vector_cache_key(data_file_path, delete_file_desc),
1544
1
            [&]() -> DeletionVector* {
1545
1
                auto deletion_vector = std::make_unique<DeletionVector>();
1546
1547
1
                io::FileCacheStatistics file_cache_stats;
1548
1
                IcebergDeleteFileReaderOptions options;
1549
1
                options.state = this->get_state();
1550
1
                options.profile = this->get_profile();
1551
1
                options.scan_params = &this->get_scan_params();
1552
1
                options.io_ctx = this->get_io_ctx();
1553
1
                options.fs_name = &this->get_scan_range().fs_name;
1554
1
                options.deletion_vector_file_cache_stats = &file_cache_stats;
1555
1
                create_status = read_iceberg_deletion_vector(delete_file_desc, options,
1556
1
                                                             deletion_vector.get());
1557
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_hit_count,
1558
1
                               file_cache_stats.num_local_io_total);
1559
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_miss_count,
1560
1
                               file_cache_stats.num_remote_io_total);
1561
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_peer_read_count,
1562
1
                               file_cache_stats.num_peer_io_total);
1563
1
                if (!create_status.ok()) [[unlikely]] {
1564
1
                    return nullptr;
1565
1
                }
1566
1567
1
                SCOPED_TIMER(_iceberg_profile.parse_delete_file_time);
1568
1
                COUNTER_UPDATE(_iceberg_profile.num_delete_rows, deletion_vector->cardinality());
1569
1
                return deletion_vector.release();
1570
1
            },
1571
1
            &decoded_cache_hit);
1572
1573
1
    RETURN_IF_ERROR(create_status);
1574
0
    COUNTER_UPDATE(decoded_cache_hit ? _iceberg_profile.decoded_cache_hit_count
1575
0
                                     : _iceberg_profile.decoded_cache_miss_count,
1576
0
                   1);
1577
0
    if (!_iceberg_deletion_vector->isEmpty()) [[likely]] {
1578
0
        set_deletion_vector();
1579
0
    }
1580
0
    return Status::OK();
1581
1
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescE
1582
1583
} // namespace doris