Coverage Report

Created: 2026-07-15 03:41

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 <cstddef>
23
#include <cstdint>
24
#include <memory>
25
#include <ranges>
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/primitive_type.h"
40
#include "format/generic_reader.h"
41
#include "format/table/equality_delete.h"
42
#include "format/table/iceberg_delete_file_reader_helper.h"
43
#include "format/table/table_schema_change_helper.h"
44
#include "runtime/runtime_profile.h"
45
#include "runtime/runtime_state.h"
46
#include "storage/olap_common.h"
47
#include "util/url_coding.h"
48
49
namespace doris {
50
class TIcebergDeleteFileDesc;
51
} // namespace doris
52
53
namespace doris {
54
55
class ShardedKVCache;
56
57
// CRTP mixin for Iceberg reader functionality.
58
// BaseReader should be ParquetReader or OrcReader.
59
// Inherits BaseReader + TableSchemaChangeHelper, providing shared Iceberg logic
60
// (delete files, deletion vectors, equality delete, $row_id synthesis).
61
//
62
// Inheritance chain:
63
//   IcebergParquetReader -> IcebergReaderMixin<ParquetReader> -> ParquetReader -> GenericReader
64
//   IcebergOrcReader     -> IcebergReaderMixin<OrcReader>     -> OrcReader     -> GenericReader
65
template <typename BaseReader>
66
class IcebergReaderMixin : public BaseReader, public TableSchemaChangeHelper {
67
public:
68
    struct PositionDeleteRange {
69
        std::vector<std::string> data_file_path;
70
        std::vector<std::pair<int, int>> range;
71
    };
72
73
    // Forward BaseReader constructor arguments + Iceberg-specific kv_cache
74
    template <typename... Args>
75
    IcebergReaderMixin(ShardedKVCache* kv_cache, Args&&... args)
76
22
            : BaseReader(std::forward<Args>(args)...), _kv_cache(kv_cache) {
77
22
        static const char* iceberg_profile = "IcebergProfile";
78
22
        ADD_TIMER(this->get_profile(), iceberg_profile);
79
22
        _iceberg_profile.num_delete_files = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteFiles",
80
22
                                                              TUnit::UNIT, iceberg_profile);
81
22
        _iceberg_profile.num_delete_rows = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteRows",
82
22
                                                             TUnit::UNIT, iceberg_profile);
83
22
        _iceberg_profile.delete_files_read_time =
84
22
                ADD_CHILD_TIMER(this->get_profile(), "DeleteFileReadTime", iceberg_profile);
85
22
        _iceberg_profile.delete_rows_sort_time =
86
22
                ADD_CHILD_TIMER(this->get_profile(), "DeleteRowsSortTime", iceberg_profile);
87
22
        _iceberg_profile.parse_delete_file_time =
88
22
                ADD_CHILD_TIMER(this->get_profile(), "ParseDeleteFileTime", iceberg_profile);
89
22
        _iceberg_profile.decoded_cache_hit_count =
90
22
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheHitCount",
91
22
                                  TUnit::UNIT, iceberg_profile);
92
22
        _iceberg_profile.decoded_cache_miss_count =
93
22
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheMissCount",
94
22
                                  TUnit::UNIT, iceberg_profile);
95
22
        _iceberg_profile.file_cache_hit_count =
96
22
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheHitCount",
97
22
                                  TUnit::UNIT, iceberg_profile);
98
22
        _iceberg_profile.file_cache_miss_count =
99
22
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheMissCount",
100
22
                                  TUnit::UNIT, iceberg_profile);
101
22
        _iceberg_profile.file_cache_peer_read_count =
102
22
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCachePeerReadCount",
103
22
                                  TUnit::UNIT, iceberg_profile);
104
22
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEEC2IJRPNS_14RuntimeProfileERKNS_20TFileScanRangeParamsERKNS_14TFileRangeDescERmRPKN4cctz9time_zoneERPNS_2io9IOContextERPNS_12RuntimeStateERPNS_13FileMetaCacheEEEEPNS_14ShardedKVCacheEDpOT_
Line
Count
Source
76
13
            : BaseReader(std::forward<Args>(args)...), _kv_cache(kv_cache) {
77
13
        static const char* iceberg_profile = "IcebergProfile";
78
13
        ADD_TIMER(this->get_profile(), iceberg_profile);
79
13
        _iceberg_profile.num_delete_files = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteFiles",
80
13
                                                              TUnit::UNIT, iceberg_profile);
81
13
        _iceberg_profile.num_delete_rows = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteRows",
82
13
                                                             TUnit::UNIT, iceberg_profile);
83
13
        _iceberg_profile.delete_files_read_time =
84
13
                ADD_CHILD_TIMER(this->get_profile(), "DeleteFileReadTime", iceberg_profile);
85
13
        _iceberg_profile.delete_rows_sort_time =
86
13
                ADD_CHILD_TIMER(this->get_profile(), "DeleteRowsSortTime", iceberg_profile);
87
13
        _iceberg_profile.parse_delete_file_time =
88
13
                ADD_CHILD_TIMER(this->get_profile(), "ParseDeleteFileTime", iceberg_profile);
89
13
        _iceberg_profile.decoded_cache_hit_count =
90
13
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheHitCount",
91
13
                                  TUnit::UNIT, iceberg_profile);
92
13
        _iceberg_profile.decoded_cache_miss_count =
93
13
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheMissCount",
94
13
                                  TUnit::UNIT, iceberg_profile);
95
13
        _iceberg_profile.file_cache_hit_count =
96
13
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheHitCount",
97
13
                                  TUnit::UNIT, iceberg_profile);
98
13
        _iceberg_profile.file_cache_miss_count =
99
13
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheMissCount",
100
13
                                  TUnit::UNIT, iceberg_profile);
101
13
        _iceberg_profile.file_cache_peer_read_count =
102
13
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCachePeerReadCount",
103
13
                                  TUnit::UNIT, iceberg_profile);
104
13
    }
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEEC2IJRPNS_14RuntimeProfileERPNS_12RuntimeStateERKNS_20TFileScanRangeParamsERKNS_14TFileRangeDescERmRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERPNS_2io9IOContextERPNS_13FileMetaCacheEEEEPNS_14ShardedKVCacheEDpOT_
Line
Count
Source
76
9
            : BaseReader(std::forward<Args>(args)...), _kv_cache(kv_cache) {
77
9
        static const char* iceberg_profile = "IcebergProfile";
78
9
        ADD_TIMER(this->get_profile(), iceberg_profile);
79
9
        _iceberg_profile.num_delete_files = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteFiles",
80
9
                                                              TUnit::UNIT, iceberg_profile);
81
9
        _iceberg_profile.num_delete_rows = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteRows",
82
9
                                                             TUnit::UNIT, iceberg_profile);
83
9
        _iceberg_profile.delete_files_read_time =
84
9
                ADD_CHILD_TIMER(this->get_profile(), "DeleteFileReadTime", iceberg_profile);
85
9
        _iceberg_profile.delete_rows_sort_time =
86
9
                ADD_CHILD_TIMER(this->get_profile(), "DeleteRowsSortTime", iceberg_profile);
87
9
        _iceberg_profile.parse_delete_file_time =
88
9
                ADD_CHILD_TIMER(this->get_profile(), "ParseDeleteFileTime", iceberg_profile);
89
9
        _iceberg_profile.decoded_cache_hit_count =
90
9
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheHitCount",
91
9
                                  TUnit::UNIT, iceberg_profile);
92
9
        _iceberg_profile.decoded_cache_miss_count =
93
9
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheMissCount",
94
9
                                  TUnit::UNIT, iceberg_profile);
95
9
        _iceberg_profile.file_cache_hit_count =
96
9
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheHitCount",
97
9
                                  TUnit::UNIT, iceberg_profile);
98
9
        _iceberg_profile.file_cache_miss_count =
99
9
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheMissCount",
100
9
                                  TUnit::UNIT, iceberg_profile);
101
9
        _iceberg_profile.file_cache_peer_read_count =
102
9
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCachePeerReadCount",
103
9
                                  TUnit::UNIT, iceberg_profile);
104
9
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEEC2IJRPNS_14RuntimeProfileERKNS_20TFileScanRangeParamsERKNS_14TFileRangeDescERmRPKN4cctz9time_zoneESt10shared_ptrINS_2io9IOContextEERPNS_12RuntimeStateERPNS_13FileMetaCacheEEEEPNS_14ShardedKVCacheEDpOT_
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEEC2IJRPNS_14RuntimeProfileERPNS_12RuntimeStateERKNS_20TFileScanRangeParamsERKNS_14TFileRangeDescERmRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt10shared_ptrINS_2io9IOContextEERPNS_13FileMetaCacheEEEEPNS_14ShardedKVCacheEDpOT_
105
106
22
    ~IcebergReaderMixin() override = default;
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEED2Ev
Line
Count
Source
106
13
    ~IcebergReaderMixin() override = default;
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEED2Ev
Line
Count
Source
106
9
    ~IcebergReaderMixin() override = default;
107
108
    void set_current_file_info(const std::string& file_path, int32_t partition_spec_id,
109
0
                               const std::string& partition_data_json) {
110
0
        _current_file_path = file_path;
111
0
        _partition_spec_id = partition_spec_id;
112
0
        _partition_data_json = partition_data_json;
113
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21set_current_file_infoERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiSA_
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21set_current_file_infoERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiSA_
114
115
    enum { DATA, POSITION_DELETE, EQUALITY_DELETE, DELETION_VECTOR };
116
    enum Fileformat { NONE, PARQUET, ORC, AVRO };
117
118
    virtual void set_delete_rows() = 0;
119
    virtual void set_deletion_vector() = 0;
120
121
    // Table-level COUNT(*) is handled by CountReader (created by FileScanner after
122
    // init_reader). If _do_get_next_block is called, COUNT must have been resolved.
123
5
    Status _do_get_next_block(Block* block, size_t* read_rows, bool* eof) override {
124
5
        DCHECK(this->_push_down_agg_type != TPushAggOp::type::COUNT);
125
5
        return BaseReader::_do_get_next_block(block, read_rows, eof);
126
5
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE18_do_get_next_blockEPNS_5BlockEPmPb
Line
Count
Source
123
2
    Status _do_get_next_block(Block* block, size_t* read_rows, bool* eof) override {
124
        DCHECK(this->_push_down_agg_type != TPushAggOp::type::COUNT);
125
2
        return BaseReader::_do_get_next_block(block, read_rows, eof);
126
2
    }
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE18_do_get_next_blockEPNS_5BlockEPmPb
Line
Count
Source
123
3
    Status _do_get_next_block(Block* block, size_t* read_rows, bool* eof) override {
124
        DCHECK(this->_push_down_agg_type != TPushAggOp::type::COUNT);
125
3
        return BaseReader::_do_get_next_block(block, read_rows, eof);
126
3
    }
127
128
    void set_create_row_id_column_iterator_func(
129
0
            std::function<std::shared_ptr<segment_v2::RowIdColumnIteratorV2>()> create_func) {
130
0
        _create_topn_row_id_column_iterator = create_func;
131
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE38set_create_row_id_column_iterator_funcESt8functionIFSt10shared_ptrINS_10segment_v221RowIdColumnIteratorV2EEvEE
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE38set_create_row_id_column_iterator_funcESt8functionIFSt10shared_ptrINS_10segment_v221RowIdColumnIteratorV2EEvEE
132
133
    Status TEST_read_deletion_vector(const std::string& data_file_path,
134
1
                                     const TIcebergDeleteFileDesc& delete_file_desc) {
135
1
        return read_deletion_vector(data_file_path, delete_file_desc);
136
1
    }
137
138
    Status TEST_position_delete_base(const std::string& data_file_path,
139
1
                                     const std::vector<TIcebergDeleteFileDesc>& delete_files) {
140
1
        return _position_delete_base(data_file_path, delete_files);
141
1
    }
142
143
    void TEST_set_column_name_to_block_index(
144
2
            std::unordered_map<std::string, uint32_t>* column_name_to_block_index) {
145
2
        this->col_name_to_block_idx_ref() = column_name_to_block_index;
146
2
    }
147
148
    Status TEST_register_missing_equality_delete_column(int32_t field_id, const std::string& name,
149
5
                                                        const DataTypePtr& delete_key_type) {
150
5
        return _register_missing_equality_delete_column(field_id, name, delete_key_type);
151
5
    }
152
153
2
    Status TEST_materialize_missing_equality_delete_columns(Block* block, size_t rows) {
154
2
        return _materialize_missing_equality_delete_columns(block, rows);
155
2
    }
156
157
protected:
158
    // ---- Hook implementations ----
159
160
    // Called before reading a block: expand block for equality delete columns + detect row_id
161
5
    Status on_before_read_block(Block* block) override {
162
5
        RETURN_IF_ERROR(_expand_block_if_need(block));
163
5
        return Status::OK();
164
5
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20on_before_read_blockEPNS_5BlockE
Line
Count
Source
161
2
    Status on_before_read_block(Block* block) override {
162
2
        RETURN_IF_ERROR(_expand_block_if_need(block));
163
2
        return Status::OK();
164
2
    }
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE20on_before_read_blockEPNS_5BlockE
Line
Count
Source
161
3
    Status on_before_read_block(Block* block) override {
162
3
        RETURN_IF_ERROR(_expand_block_if_need(block));
163
3
        return Status::OK();
164
3
    }
165
166
    /// Fill Iceberg $row_id synthesized column. Registered as handler during init.
167
0
    Status _fill_iceberg_row_id(Block* block, size_t rows) {
168
0
        int row_id_pos = block->get_position_by_name(BeConsts::ICEBERG_ROWID_COL);
169
0
        DORIS_CHECK(row_id_pos >= 0);
170
171
        // Lazy-init file info: only set when $row_id is actually needed.
172
0
        const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
173
0
        std::string file_path = table_desc.original_file_path;
174
0
        int32_t partition_spec_id =
175
0
                table_desc.__isset.partition_spec_id ? table_desc.partition_spec_id : 0;
176
0
        std::string partition_data_json;
177
0
        if (table_desc.__isset.partition_data_json) {
178
0
            partition_data_json = table_desc.partition_data_json;
179
0
        }
180
0
        set_current_file_info(file_path, partition_spec_id, partition_data_json);
181
182
0
        const auto& row_ids = this->current_batch_row_positions();
183
0
        auto& col_with_type = block->get_by_position(static_cast<size_t>(row_id_pos));
184
0
        MutableColumnPtr row_id_column;
185
0
        RETURN_IF_ERROR(_build_iceberg_rowid_column(col_with_type.type, _current_file_path, row_ids,
186
0
                                                    _partition_spec_id, _partition_data_json,
187
0
                                                    &row_id_column));
188
0
        col_with_type.column = std::move(row_id_column);
189
0
        return Status::OK();
190
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20_fill_iceberg_row_idEPNS_5BlockEm
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE20_fill_iceberg_row_idEPNS_5BlockEm
191
192
0
    void _init_row_lineage_columns() {
193
0
        const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
194
0
        if (table_desc.__isset.first_row_id) {
195
0
            _row_lineage_columns.first_row_id = table_desc.first_row_id;
196
0
        }
197
0
        if (table_desc.__isset.last_updated_sequence_number) {
198
0
            _row_lineage_columns.last_updated_sequence_number =
199
0
                    table_desc.last_updated_sequence_number;
200
0
        }
201
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE25_init_row_lineage_columnsEv
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE25_init_row_lineage_columnsEv
202
203
0
    Status _fill_row_lineage_row_id(Block* block, size_t rows) {
204
0
        int col_pos = block->get_position_by_name(ROW_LINEAGE_ROW_ID);
205
0
        DORIS_CHECK(col_pos >= 0);
206
207
0
        if (_row_lineage_columns.first_row_id >= 0) {
208
0
            auto column_guard = block->mutate_column_scoped(col_pos);
209
0
            auto* nullable_column =
210
0
                    assert_cast<ColumnNullable*>(column_guard.mutable_column().get());
211
0
            auto& null_map = nullable_column->get_null_map_data();
212
0
            auto& data =
213
0
                    assert_cast<ColumnInt64&>(*nullable_column->get_nested_column_ptr()).get_data();
214
0
            const auto& row_ids = this->current_batch_row_positions();
215
0
            for (size_t i = 0; i < rows; ++i) {
216
0
                if (null_map[i] != 0) {
217
0
                    null_map[i] = 0;
218
0
                    data[i] = _row_lineage_columns.first_row_id + static_cast<int64_t>(row_ids[i]);
219
0
                }
220
0
            }
221
0
        }
222
0
        return Status::OK();
223
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE24_fill_row_lineage_row_idEPNS_5BlockEm
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE24_fill_row_lineage_row_idEPNS_5BlockEm
224
225
0
    Status _fill_row_lineage_last_updated_sequence_number(Block* block, size_t rows) {
226
0
        int col_pos = block->get_position_by_name(ROW_LINEAGE_LAST_UPDATED_SEQ_NUMBER);
227
0
        DORIS_CHECK(col_pos >= 0);
228
229
0
        if (_row_lineage_columns.last_updated_sequence_number >= 0) {
230
0
            auto column_guard = block->mutate_column_scoped(col_pos);
231
0
            auto* nullable_column =
232
0
                    assert_cast<ColumnNullable*>(column_guard.mutable_column().get());
233
0
            auto& null_map = nullable_column->get_null_map_data();
234
0
            auto& data =
235
0
                    assert_cast<ColumnInt64&>(*nullable_column->get_nested_column_ptr()).get_data();
236
0
            for (size_t i = 0; i < rows; ++i) {
237
0
                if (null_map[i] != 0) {
238
0
                    null_map[i] = 0;
239
0
                    data[i] = _row_lineage_columns.last_updated_sequence_number;
240
0
                }
241
0
            }
242
0
        }
243
0
        return Status::OK();
244
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
245
246
    // Called after reading a block: apply equality delete filter + shrink block
247
5
    Status on_after_read_block(Block* block, size_t* read_rows) override {
248
5
        if (!_equality_delete_impls.empty()) {
249
3
            std::unique_ptr<IColumn::Filter> filter =
250
3
                    std::make_unique<IColumn::Filter>(block->rows(), 1);
251
3
            for (auto& equality_delete_impl : _equality_delete_impls) {
252
3
                RETURN_IF_ERROR(equality_delete_impl->filter_data_block(
253
3
                        block, this->col_name_to_block_idx_ref(), _id_to_block_column_name,
254
3
                        *filter));
255
3
            }
256
3
            Block::filter_block_internal(block, *filter, block->columns());
257
3
            *read_rows = block->rows();
258
3
        }
259
5
        return _shrink_block_if_need(block);
260
5
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE19on_after_read_blockEPNS_5BlockEPm
Line
Count
Source
247
2
    Status on_after_read_block(Block* block, size_t* read_rows) override {
248
2
        if (!_equality_delete_impls.empty()) {
249
1
            std::unique_ptr<IColumn::Filter> filter =
250
1
                    std::make_unique<IColumn::Filter>(block->rows(), 1);
251
1
            for (auto& equality_delete_impl : _equality_delete_impls) {
252
1
                RETURN_IF_ERROR(equality_delete_impl->filter_data_block(
253
1
                        block, this->col_name_to_block_idx_ref(), _id_to_block_column_name,
254
1
                        *filter));
255
1
            }
256
1
            Block::filter_block_internal(block, *filter, block->columns());
257
1
            *read_rows = block->rows();
258
1
        }
259
2
        return _shrink_block_if_need(block);
260
2
    }
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE19on_after_read_blockEPNS_5BlockEPm
Line
Count
Source
247
3
    Status on_after_read_block(Block* block, size_t* read_rows) override {
248
3
        if (!_equality_delete_impls.empty()) {
249
2
            std::unique_ptr<IColumn::Filter> filter =
250
2
                    std::make_unique<IColumn::Filter>(block->rows(), 1);
251
2
            for (auto& equality_delete_impl : _equality_delete_impls) {
252
2
                RETURN_IF_ERROR(equality_delete_impl->filter_data_block(
253
2
                        block, this->col_name_to_block_idx_ref(), _id_to_block_column_name,
254
2
                        *filter));
255
2
            }
256
2
            Block::filter_block_internal(block, *filter, block->columns());
257
2
            *read_rows = block->rows();
258
2
        }
259
3
        return _shrink_block_if_need(block);
260
3
    }
261
262
    // ---- Shared Iceberg methods ----
263
264
    Status _init_row_filters();
265
    Status _position_delete_base(const std::string data_file_path,
266
                                 const std::vector<TIcebergDeleteFileDesc>& delete_files);
267
    Status _equality_delete_base(const std::vector<TIcebergDeleteFileDesc>& delete_files);
268
    Status read_deletion_vector(const std::string& data_file_path,
269
                                const TIcebergDeleteFileDesc& delete_file_desc);
270
271
    Status _expand_block_if_need(Block* block);
272
    Status _shrink_block_if_need(Block* block);
273
    Status _register_missing_equality_delete_column(int32_t field_id, const std::string& name,
274
                                                    const DataTypePtr& delete_key_type);
275
    Status _materialize_missing_equality_delete_column(Block* block, const std::string& name,
276
                                                       const ColumnPtr& value, size_t rows);
277
    Status _materialize_missing_equality_delete_columns(Block* block, size_t rows);
278
279
    // Type aliases — must be defined before member function declarations that use them.
280
    using DeleteRows = std::vector<int64_t>;
281
    using DeleteFile = phmap::parallel_flat_hash_map<
282
            std::string, std::unique_ptr<DeleteRows>, std::hash<std::string>, std::equal_to<>,
283
            std::allocator<std::pair<const std::string, std::unique_ptr<DeleteRows>>>, 8,
284
            std::mutex>;
285
286
    PositionDeleteRange _get_range(const ColumnDictI32& file_path_column);
287
    PositionDeleteRange _get_range(const ColumnString& file_path_column);
288
    static void _sort_delete_rows(const std::vector<std::vector<int64_t>*>& delete_rows_array,
289
                                  int64_t num_delete_rows, std::vector<int64_t>& result);
290
    Status _gen_position_delete_file_range(Block& block, DeleteFile* position_delete,
291
                                           size_t read_rows,
292
                                           bool file_path_column_dictionary_coded);
293
    void _generate_equality_delete_block(Block* block,
294
                                         const std::vector<std::string>& equality_delete_col_names,
295
                                         const std::vector<DataTypePtr>& equality_delete_col_types);
296
297
    // Pure virtual: format-specific delete file reading
298
    virtual Status _read_position_delete_file(const TFileRangeDesc*, DeleteFile*) = 0;
299
    virtual std::unique_ptr<GenericReader> _create_equality_reader(
300
            const TFileRangeDesc& delete_desc) = 0;
301
302
1
    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
302
1
    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
303
304
    /// Build the Iceberg V2 row-id struct column.
305
    static Status _build_iceberg_rowid_column(const DataTypePtr& type, const std::string& file_path,
306
                                              const std::vector<rowid_t>& row_ids,
307
                                              int32_t partition_spec_id,
308
                                              const std::string& partition_data_json,
309
0
                                              MutableColumnPtr* column_out) {
310
0
        if (type == nullptr || column_out == nullptr) {
311
0
            return Status::InvalidArgument("Invalid iceberg rowid column type or output column");
312
0
        }
313
0
        MutableColumnPtr column = type->create_column();
314
0
        ColumnNullable* nullable_col = check_and_get_column<ColumnNullable>(column.get());
315
0
        ColumnStruct* struct_col = nullptr;
316
0
        if (nullable_col != nullptr) {
317
0
            struct_col =
318
0
                    check_and_get_column<ColumnStruct>(nullable_col->get_nested_column_ptr().get());
319
0
        } else {
320
0
            struct_col = check_and_get_column<ColumnStruct>(column.get());
321
0
        }
322
0
        if (struct_col == nullptr || struct_col->tuple_size() < 4) {
323
0
            return Status::InternalError("Invalid iceberg rowid column structure");
324
0
        }
325
0
        size_t num_rows = row_ids.size();
326
0
        auto& file_path_col = struct_col->get_column(0);
327
0
        auto& row_pos_col = struct_col->get_column(1);
328
0
        auto& spec_id_col = struct_col->get_column(2);
329
0
        auto& partition_data_col = struct_col->get_column(3);
330
0
        file_path_col.reserve(num_rows);
331
0
        row_pos_col.reserve(num_rows);
332
0
        spec_id_col.reserve(num_rows);
333
0
        partition_data_col.reserve(num_rows);
334
0
        for (size_t i = 0; i < num_rows; ++i) {
335
0
            file_path_col.insert_data(file_path.data(), file_path.size());
336
0
        }
337
0
        for (size_t i = 0; i < num_rows; ++i) {
338
0
            int64_t row_pos = static_cast<int64_t>(row_ids[i]);
339
0
            row_pos_col.insert_data(reinterpret_cast<const char*>(&row_pos), sizeof(row_pos));
340
0
        }
341
0
        for (size_t i = 0; i < num_rows; ++i) {
342
0
            int32_t spec_id = partition_spec_id;
343
0
            spec_id_col.insert_data(reinterpret_cast<const char*>(&spec_id), sizeof(spec_id));
344
0
        }
345
0
        for (size_t i = 0; i < num_rows; ++i) {
346
0
            partition_data_col.insert_data(partition_data_json.data(), partition_data_json.size());
347
0
        }
348
0
        if (nullable_col != nullptr) {
349
0
            nullable_col->get_null_map_data().resize_fill(num_rows, 0);
350
0
        }
351
0
        *column_out = std::move(column);
352
0
        return Status::OK();
353
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
354
355
    struct IcebergProfile {
356
        RuntimeProfile::Counter* num_delete_files;
357
        RuntimeProfile::Counter* num_delete_rows;
358
        RuntimeProfile::Counter* delete_files_read_time;
359
        RuntimeProfile::Counter* delete_rows_sort_time;
360
        RuntimeProfile::Counter* parse_delete_file_time;
361
        RuntimeProfile::Counter* decoded_cache_hit_count;
362
        RuntimeProfile::Counter* decoded_cache_miss_count;
363
        RuntimeProfile::Counter* file_cache_hit_count;
364
        RuntimeProfile::Counter* file_cache_miss_count;
365
        RuntimeProfile::Counter* file_cache_peer_read_count;
366
    };
367
368
    bool _need_row_id_column = false;
369
    std::string _current_file_path;
370
    int32_t _partition_spec_id = 0;
371
    std::string _partition_data_json;
372
373
    ShardedKVCache* _kv_cache;
374
    IcebergProfile _iceberg_profile;
375
    const std::vector<int64_t>* _iceberg_delete_rows = nullptr;
376
    const DeletionVector* _iceberg_deletion_vector = nullptr;
377
    std::vector<std::string> _expand_col_names;
378
    std::vector<ColumnWithTypeAndName> _expand_columns;
379
    std::unordered_map<std::string, ColumnPtr> _missing_equality_delete_values;
380
    std::vector<std::string> _all_required_col_names;
381
    Fileformat _file_format = Fileformat::NONE;
382
383
    const int64_t MIN_SUPPORT_DELETE_FILES_VERSION = 2;
384
    const std::string ICEBERG_FILE_PATH = "file_path";
385
    const std::string ICEBERG_ROW_POS = "pos";
386
    const std::vector<std::string> delete_file_col_names {ICEBERG_FILE_PATH, ICEBERG_ROW_POS};
387
    const std::unordered_map<std::string, uint32_t> DELETE_COL_NAME_TO_BLOCK_IDX = {
388
            {ICEBERG_FILE_PATH, 0}, {ICEBERG_ROW_POS, 1}};
389
    const int ICEBERG_FILE_PATH_INDEX = 0;
390
    const int ICEBERG_FILE_POS_INDEX = 1;
391
    const int READ_DELETE_FILE_BATCH_SIZE = 102400;
392
393
    // all ids that need read for eq delete (from all eq delete files)
394
    std::set<int> _equality_delete_col_ids;
395
    // eq delete column ids -> location of _equality_delete_blocks / _equality_delete_impls
396
    std::map<std::vector<int>, int> _equality_delete_block_map;
397
    // EqualityDeleteBase stores raw pointers to these blocks, so do not modify this vector after
398
    // creating entries in _equality_delete_impls.
399
    std::vector<Block> _equality_delete_blocks;
400
    std::vector<std::unique_ptr<EqualityDeleteBase>> _equality_delete_impls;
401
402
    // id -> block column name
403
    std::unordered_map<int, std::string> _id_to_block_column_name;
404
405
    std::function<std::shared_ptr<segment_v2::RowIdColumnIteratorV2>()>
406
            _create_topn_row_id_column_iterator;
407
408
    static constexpr const char* ROW_LINEAGE_ROW_ID = "_row_id";
409
    static constexpr const char* ROW_LINEAGE_LAST_UPDATED_SEQ_NUMBER =
410
            "_last_updated_sequence_number";
411
    struct RowLineageColumns {
412
        int64_t first_row_id = -1;
413
        int64_t last_updated_sequence_number = -1;
414
    };
415
    RowLineageColumns _row_lineage_columns;
416
};
417
418
// ============================================================================
419
// Template method implementations (must be in header for templates)
420
// ============================================================================
421
422
template <typename BaseReader>
423
5
Status IcebergReaderMixin<BaseReader>::_init_row_filters() {
424
    // COUNT(*) short-circuit. A table-level row count of 0 (e.g. an all-deleted table read with
425
    // ignore_iceberg_dangling_delete, where total-records == total-position-deletes) is still a
426
    // valid pushed-down count, so accept >= 0 -- matching FileScanner and the Paimon readers. FE
427
    // sends -1 when there is no table-level count; using > 0 here would drop a genuine 0 into the
428
    // delete-applying path below and never produce the intended CountReader(0).
429
5
    if (this->_push_down_agg_type == TPushAggOp::type::COUNT &&
430
5
        this->get_scan_range().table_format_params.__isset.table_level_row_count &&
431
5
        this->get_scan_range().table_format_params.table_level_row_count >= 0) {
432
0
        return Status::OK();
433
0
    }
434
435
5
    const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
436
5
    const auto& version = table_desc.format_version;
437
5
    if (version < MIN_SUPPORT_DELETE_FILES_VERSION) {
438
2
        return Status::OK();
439
2
    }
440
441
3
    std::vector<TIcebergDeleteFileDesc> position_delete_files;
442
3
    std::vector<TIcebergDeleteFileDesc> equality_delete_files;
443
3
    std::vector<TIcebergDeleteFileDesc> deletion_vector_files;
444
3
    for (const TIcebergDeleteFileDesc& desc : table_desc.delete_files) {
445
3
        if (desc.content == POSITION_DELETE) {
446
0
            position_delete_files.emplace_back(desc);
447
3
        } else if (desc.content == EQUALITY_DELETE) {
448
3
            equality_delete_files.emplace_back(desc);
449
3
        } else if (desc.content == DELETION_VECTOR) {
450
0
            deletion_vector_files.emplace_back(desc);
451
0
        }
452
3
    }
453
454
3
    if (!equality_delete_files.empty()) {
455
3
        RETURN_IF_ERROR(_equality_delete_base(equality_delete_files));
456
3
        this->set_push_down_agg_type(TPushAggOp::NONE);
457
3
    }
458
459
3
    if (!deletion_vector_files.empty()) {
460
0
        if (deletion_vector_files.size() != 1) [[unlikely]] {
461
            /*
462
             * Deletion vectors are a binary representation of deletes for a single data file that is more efficient
463
             * at execution time than position delete files. Unlike equality or position delete files, there can be
464
             * at most one deletion vector for a given data file in a snapshot.
465
             */
466
0
            return Status::DataQualityError("This iceberg data file has multiple DVs.");
467
0
        }
468
0
        RETURN_IF_ERROR(
469
0
                read_deletion_vector(table_desc.original_file_path, deletion_vector_files[0]));
470
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
471
3
    } else if (!position_delete_files.empty()) {
472
0
        RETURN_IF_ERROR(
473
0
                _position_delete_base(table_desc.original_file_path, position_delete_files));
474
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
475
0
    }
476
477
3
    COUNTER_UPDATE(_iceberg_profile.num_delete_files, table_desc.delete_files.size());
478
3
    return Status::OK();
479
3
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE17_init_row_filtersEv
Line
Count
Source
423
2
Status IcebergReaderMixin<BaseReader>::_init_row_filters() {
424
    // COUNT(*) short-circuit. A table-level row count of 0 (e.g. an all-deleted table read with
425
    // ignore_iceberg_dangling_delete, where total-records == total-position-deletes) is still a
426
    // valid pushed-down count, so accept >= 0 -- matching FileScanner and the Paimon readers. FE
427
    // sends -1 when there is no table-level count; using > 0 here would drop a genuine 0 into the
428
    // delete-applying path below and never produce the intended CountReader(0).
429
2
    if (this->_push_down_agg_type == TPushAggOp::type::COUNT &&
430
2
        this->get_scan_range().table_format_params.__isset.table_level_row_count &&
431
2
        this->get_scan_range().table_format_params.table_level_row_count >= 0) {
432
0
        return Status::OK();
433
0
    }
434
435
2
    const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
436
2
    const auto& version = table_desc.format_version;
437
2
    if (version < MIN_SUPPORT_DELETE_FILES_VERSION) {
438
1
        return Status::OK();
439
1
    }
440
441
1
    std::vector<TIcebergDeleteFileDesc> position_delete_files;
442
1
    std::vector<TIcebergDeleteFileDesc> equality_delete_files;
443
1
    std::vector<TIcebergDeleteFileDesc> deletion_vector_files;
444
1
    for (const TIcebergDeleteFileDesc& desc : table_desc.delete_files) {
445
1
        if (desc.content == POSITION_DELETE) {
446
0
            position_delete_files.emplace_back(desc);
447
1
        } else if (desc.content == EQUALITY_DELETE) {
448
1
            equality_delete_files.emplace_back(desc);
449
1
        } else if (desc.content == DELETION_VECTOR) {
450
0
            deletion_vector_files.emplace_back(desc);
451
0
        }
452
1
    }
453
454
1
    if (!equality_delete_files.empty()) {
455
1
        RETURN_IF_ERROR(_equality_delete_base(equality_delete_files));
456
1
        this->set_push_down_agg_type(TPushAggOp::NONE);
457
1
    }
458
459
1
    if (!deletion_vector_files.empty()) {
460
0
        if (deletion_vector_files.size() != 1) [[unlikely]] {
461
            /*
462
             * Deletion vectors are a binary representation of deletes for a single data file that is more efficient
463
             * at execution time than position delete files. Unlike equality or position delete files, there can be
464
             * at most one deletion vector for a given data file in a snapshot.
465
             */
466
0
            return Status::DataQualityError("This iceberg data file has multiple DVs.");
467
0
        }
468
0
        RETURN_IF_ERROR(
469
0
                read_deletion_vector(table_desc.original_file_path, deletion_vector_files[0]));
470
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
471
1
    } else if (!position_delete_files.empty()) {
472
0
        RETURN_IF_ERROR(
473
0
                _position_delete_base(table_desc.original_file_path, position_delete_files));
474
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
475
0
    }
476
477
1
    COUNTER_UPDATE(_iceberg_profile.num_delete_files, table_desc.delete_files.size());
478
1
    return Status::OK();
479
1
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE17_init_row_filtersEv
Line
Count
Source
423
3
Status IcebergReaderMixin<BaseReader>::_init_row_filters() {
424
    // COUNT(*) short-circuit. A table-level row count of 0 (e.g. an all-deleted table read with
425
    // ignore_iceberg_dangling_delete, where total-records == total-position-deletes) is still a
426
    // valid pushed-down count, so accept >= 0 -- matching FileScanner and the Paimon readers. FE
427
    // sends -1 when there is no table-level count; using > 0 here would drop a genuine 0 into the
428
    // delete-applying path below and never produce the intended CountReader(0).
429
3
    if (this->_push_down_agg_type == TPushAggOp::type::COUNT &&
430
3
        this->get_scan_range().table_format_params.__isset.table_level_row_count &&
431
3
        this->get_scan_range().table_format_params.table_level_row_count >= 0) {
432
0
        return Status::OK();
433
0
    }
434
435
3
    const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
436
3
    const auto& version = table_desc.format_version;
437
3
    if (version < MIN_SUPPORT_DELETE_FILES_VERSION) {
438
1
        return Status::OK();
439
1
    }
440
441
2
    std::vector<TIcebergDeleteFileDesc> position_delete_files;
442
2
    std::vector<TIcebergDeleteFileDesc> equality_delete_files;
443
2
    std::vector<TIcebergDeleteFileDesc> deletion_vector_files;
444
2
    for (const TIcebergDeleteFileDesc& desc : table_desc.delete_files) {
445
2
        if (desc.content == POSITION_DELETE) {
446
0
            position_delete_files.emplace_back(desc);
447
2
        } else if (desc.content == EQUALITY_DELETE) {
448
2
            equality_delete_files.emplace_back(desc);
449
2
        } else if (desc.content == DELETION_VECTOR) {
450
0
            deletion_vector_files.emplace_back(desc);
451
0
        }
452
2
    }
453
454
2
    if (!equality_delete_files.empty()) {
455
2
        RETURN_IF_ERROR(_equality_delete_base(equality_delete_files));
456
2
        this->set_push_down_agg_type(TPushAggOp::NONE);
457
2
    }
458
459
2
    if (!deletion_vector_files.empty()) {
460
0
        if (deletion_vector_files.size() != 1) [[unlikely]] {
461
            /*
462
             * Deletion vectors are a binary representation of deletes for a single data file that is more efficient
463
             * at execution time than position delete files. Unlike equality or position delete files, there can be
464
             * at most one deletion vector for a given data file in a snapshot.
465
             */
466
0
            return Status::DataQualityError("This iceberg data file has multiple DVs.");
467
0
        }
468
0
        RETURN_IF_ERROR(
469
0
                read_deletion_vector(table_desc.original_file_path, deletion_vector_files[0]));
470
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
471
2
    } else if (!position_delete_files.empty()) {
472
0
        RETURN_IF_ERROR(
473
0
                _position_delete_base(table_desc.original_file_path, position_delete_files));
474
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
475
0
    }
476
477
2
    COUNTER_UPDATE(_iceberg_profile.num_delete_files, table_desc.delete_files.size());
478
2
    return Status::OK();
479
2
}
480
481
template <typename BaseReader>
482
Status IcebergReaderMixin<BaseReader>::_equality_delete_base(
483
3
        const std::vector<TIcebergDeleteFileDesc>& delete_files) {
484
3
    std::unordered_map<std::string, std::tuple<std::string, const SlotDescriptor*>>
485
3
            partition_columns;
486
3
    std::unordered_map<std::string, VExprContextSPtr> missing_columns;
487
488
3
    for (const auto& delete_file : delete_files) {
489
3
        TFileRangeDesc delete_desc;
490
3
        delete_desc.__set_fs_name(this->get_scan_range().fs_name);
491
3
        delete_desc.path = delete_file.path;
492
3
        delete_desc.start_offset = 0;
493
3
        delete_desc.size = -1;
494
3
        delete_desc.file_size = -1;
495
496
3
        if (!delete_file.__isset.field_ids) [[unlikely]] {
497
0
            return Status::InternalError(
498
0
                    "missing delete field ids when reading equality delete file");
499
0
        }
500
3
        auto& read_column_field_ids = delete_file.field_ids;
501
3
        std::set<int> read_column_field_ids_set;
502
3
        for (const auto& field_id : read_column_field_ids) {
503
3
            read_column_field_ids_set.insert(field_id);
504
3
            _equality_delete_col_ids.insert(field_id);
505
3
        }
506
507
3
        std::unique_ptr<GenericReader> delete_reader = _create_equality_reader(delete_desc);
508
3
        RETURN_IF_ERROR(delete_reader->init_schema_reader());
509
510
3
        std::vector<std::string> equality_delete_col_names;
511
3
        std::vector<DataTypePtr> equality_delete_col_types;
512
513
        // Build delete col names/types/ids by matching field_ids from delete file schema.
514
        // Master iterates delete file's FieldDescriptor and uses field_id to match,
515
        // NOT idx-based pairing (get_parsed_schema order != field_ids order).
516
3
        std::vector<std::string> delete_col_names;
517
3
        std::vector<DataTypePtr> delete_col_types;
518
3
        std::vector<int> delete_col_ids;
519
3
        std::unordered_map<std::string, uint32_t> delete_col_name_to_block_idx;
520
521
3
        if (auto* parquet_reader = typeid_cast<ParquetReader*>(delete_reader.get())) {
522
1
            const FieldDescriptor* delete_field_desc = nullptr;
523
1
            RETURN_IF_ERROR(parquet_reader->get_file_metadata_schema(&delete_field_desc));
524
1
            DCHECK(delete_field_desc != nullptr);
525
526
1
            for (const auto& delete_file_field : delete_field_desc->get_fields_schema()) {
527
1
                if (delete_file_field.field_id == -1) [[unlikely]] {
528
0
                    return Status::DataQualityError(
529
0
                            "missing field id when reading equality delete file");
530
0
                }
531
1
                if (!read_column_field_ids_set.contains(delete_file_field.field_id)) {
532
0
                    continue;
533
0
                }
534
1
                if (delete_file_field.children.size() > 0) [[unlikely]] {
535
0
                    return Status::InternalError(
536
0
                            "can not support read complex column in equality delete file");
537
0
                }
538
539
1
                delete_col_ids.emplace_back(delete_file_field.field_id);
540
1
                delete_col_names.emplace_back(delete_file_field.name);
541
1
                delete_col_types.emplace_back(make_nullable(delete_file_field.data_type));
542
543
1
                int field_id = delete_file_field.field_id;
544
1
                if (!_id_to_block_column_name.contains(field_id)) {
545
1
                    _id_to_block_column_name.emplace(field_id, delete_file_field.name);
546
1
                    _expand_col_names.emplace_back(delete_file_field.name);
547
1
                    _expand_columns.emplace_back(
548
1
                            make_nullable(delete_file_field.data_type)->create_column(),
549
1
                            make_nullable(delete_file_field.data_type), delete_file_field.name);
550
1
                }
551
1
            }
552
2
            for (uint32_t idx = 0; idx < delete_col_names.size(); ++idx) {
553
1
                delete_col_name_to_block_idx[delete_col_names[idx]] = idx;
554
1
            }
555
            // Delete files have TFileRangeDesc.size=-1, which would cause
556
            // set_fill_columns to return EndOfFile("No row group to read")
557
            // when _filter_groups is true. Master passes filter_groups=false.
558
1
            ParquetInitContext eq_delete_ctx;
559
1
            eq_delete_ctx.filter_groups = false;
560
1
            eq_delete_ctx.column_names = delete_col_names;
561
1
            eq_delete_ctx.col_name_to_block_idx = &delete_col_name_to_block_idx;
562
1
            auto st2 = parquet_reader->init_reader(&eq_delete_ctx);
563
1
            if (!st2.ok()) {
564
0
                return st2;
565
0
            }
566
2
        } else if (auto* orc_reader = typeid_cast<OrcReader*>(delete_reader.get())) {
567
            // For ORC: use get_parsed_schema with field_ids from delete_file
568
            // ORC field_ids come from the Thrift descriptor, not from ORC metadata
569
2
            RETURN_IF_ERROR(delete_reader->get_parsed_schema(&equality_delete_col_names,
570
2
                                                             &equality_delete_col_types));
571
4
            for (uint32_t idx = 0; idx < equality_delete_col_names.size(); ++idx) {
572
2
                if (idx < read_column_field_ids.size()) {
573
2
                    int field_id = read_column_field_ids[idx];
574
2
                    if (!read_column_field_ids_set.contains(field_id)) continue;
575
2
                    delete_col_ids.emplace_back(field_id);
576
2
                    delete_col_names.emplace_back(equality_delete_col_names[idx]);
577
2
                    delete_col_types.emplace_back(make_nullable(equality_delete_col_types[idx]));
578
2
                    if (!_id_to_block_column_name.contains(field_id)) {
579
2
                        _id_to_block_column_name.emplace(field_id, equality_delete_col_names[idx]);
580
2
                        _expand_col_names.emplace_back(equality_delete_col_names[idx]);
581
2
                        _expand_columns.emplace_back(
582
2
                                make_nullable(equality_delete_col_types[idx])->create_column(),
583
2
                                make_nullable(equality_delete_col_types[idx]),
584
2
                                equality_delete_col_names[idx]);
585
2
                    }
586
2
                }
587
2
            }
588
4
            for (uint32_t idx = 0; idx < delete_col_names.size(); ++idx) {
589
2
                delete_col_name_to_block_idx[delete_col_names[idx]] = idx;
590
2
            }
591
2
            OrcInitContext eq_delete_ctx;
592
2
            eq_delete_ctx.column_names = delete_col_names;
593
2
            eq_delete_ctx.col_name_to_block_idx = &delete_col_name_to_block_idx;
594
2
            RETURN_IF_ERROR(orc_reader->init_reader(&eq_delete_ctx));
595
2
        } else {
596
0
            return Status::InternalError("Unsupported format of delete file");
597
0
        }
598
599
3
        if (!_equality_delete_block_map.contains(delete_col_ids)) {
600
3
            _equality_delete_block_map.emplace(delete_col_ids, _equality_delete_blocks.size());
601
3
            Block block;
602
3
            _generate_equality_delete_block(&block, delete_col_names, delete_col_types);
603
3
            _equality_delete_blocks.emplace_back(block);
604
3
        }
605
3
        Block& eq_file_block = _equality_delete_blocks[_equality_delete_block_map[delete_col_ids]];
606
607
3
        bool eof = false;
608
8
        while (!eof) {
609
5
            Block tmp_block;
610
5
            _generate_equality_delete_block(&tmp_block, delete_col_names, delete_col_types);
611
5
            size_t read_rows = 0;
612
5
            auto st = delete_reader->get_next_block(&tmp_block, &read_rows, &eof);
613
5
            if (!st.ok()) {
614
0
                return st;
615
0
            }
616
5
            if (read_rows > 0) {
617
3
                ScopedMutableBlock scoped_mutable_block(&eq_file_block);
618
3
                auto& mutable_block = scoped_mutable_block.mutable_block();
619
3
                RETURN_IF_ERROR(mutable_block.merge(tmp_block));
620
3
            }
621
5
        }
622
3
    }
623
624
3
    for (const auto& [delete_col_ids, block_idx] : _equality_delete_block_map) {
625
3
        auto& eq_file_block = _equality_delete_blocks[block_idx];
626
3
        auto equality_delete_impl =
627
3
                EqualityDeleteBase::get_delete_impl(&eq_file_block, delete_col_ids);
628
3
        RETURN_IF_ERROR(equality_delete_impl->init(this->get_profile()));
629
3
        _equality_delete_impls.emplace_back(std::move(equality_delete_impl));
630
3
    }
631
3
    return Status::OK();
632
3
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_equality_delete_baseERKSt6vectorINS_22TIcebergDeleteFileDescESaIS4_EE
Line
Count
Source
483
1
        const std::vector<TIcebergDeleteFileDesc>& delete_files) {
484
1
    std::unordered_map<std::string, std::tuple<std::string, const SlotDescriptor*>>
485
1
            partition_columns;
486
1
    std::unordered_map<std::string, VExprContextSPtr> missing_columns;
487
488
1
    for (const auto& delete_file : delete_files) {
489
1
        TFileRangeDesc delete_desc;
490
1
        delete_desc.__set_fs_name(this->get_scan_range().fs_name);
491
1
        delete_desc.path = delete_file.path;
492
1
        delete_desc.start_offset = 0;
493
1
        delete_desc.size = -1;
494
1
        delete_desc.file_size = -1;
495
496
1
        if (!delete_file.__isset.field_ids) [[unlikely]] {
497
0
            return Status::InternalError(
498
0
                    "missing delete field ids when reading equality delete file");
499
0
        }
500
1
        auto& read_column_field_ids = delete_file.field_ids;
501
1
        std::set<int> read_column_field_ids_set;
502
1
        for (const auto& field_id : read_column_field_ids) {
503
1
            read_column_field_ids_set.insert(field_id);
504
1
            _equality_delete_col_ids.insert(field_id);
505
1
        }
506
507
1
        std::unique_ptr<GenericReader> delete_reader = _create_equality_reader(delete_desc);
508
1
        RETURN_IF_ERROR(delete_reader->init_schema_reader());
509
510
1
        std::vector<std::string> equality_delete_col_names;
511
1
        std::vector<DataTypePtr> equality_delete_col_types;
512
513
        // Build delete col names/types/ids by matching field_ids from delete file schema.
514
        // Master iterates delete file's FieldDescriptor and uses field_id to match,
515
        // NOT idx-based pairing (get_parsed_schema order != field_ids order).
516
1
        std::vector<std::string> delete_col_names;
517
1
        std::vector<DataTypePtr> delete_col_types;
518
1
        std::vector<int> delete_col_ids;
519
1
        std::unordered_map<std::string, uint32_t> delete_col_name_to_block_idx;
520
521
1
        if (auto* parquet_reader = typeid_cast<ParquetReader*>(delete_reader.get())) {
522
1
            const FieldDescriptor* delete_field_desc = nullptr;
523
1
            RETURN_IF_ERROR(parquet_reader->get_file_metadata_schema(&delete_field_desc));
524
1
            DCHECK(delete_field_desc != nullptr);
525
526
1
            for (const auto& delete_file_field : delete_field_desc->get_fields_schema()) {
527
1
                if (delete_file_field.field_id == -1) [[unlikely]] {
528
0
                    return Status::DataQualityError(
529
0
                            "missing field id when reading equality delete file");
530
0
                }
531
1
                if (!read_column_field_ids_set.contains(delete_file_field.field_id)) {
532
0
                    continue;
533
0
                }
534
1
                if (delete_file_field.children.size() > 0) [[unlikely]] {
535
0
                    return Status::InternalError(
536
0
                            "can not support read complex column in equality delete file");
537
0
                }
538
539
1
                delete_col_ids.emplace_back(delete_file_field.field_id);
540
1
                delete_col_names.emplace_back(delete_file_field.name);
541
1
                delete_col_types.emplace_back(make_nullable(delete_file_field.data_type));
542
543
1
                int field_id = delete_file_field.field_id;
544
1
                if (!_id_to_block_column_name.contains(field_id)) {
545
1
                    _id_to_block_column_name.emplace(field_id, delete_file_field.name);
546
1
                    _expand_col_names.emplace_back(delete_file_field.name);
547
1
                    _expand_columns.emplace_back(
548
1
                            make_nullable(delete_file_field.data_type)->create_column(),
549
1
                            make_nullable(delete_file_field.data_type), delete_file_field.name);
550
1
                }
551
1
            }
552
2
            for (uint32_t idx = 0; idx < delete_col_names.size(); ++idx) {
553
1
                delete_col_name_to_block_idx[delete_col_names[idx]] = idx;
554
1
            }
555
            // Delete files have TFileRangeDesc.size=-1, which would cause
556
            // set_fill_columns to return EndOfFile("No row group to read")
557
            // when _filter_groups is true. Master passes filter_groups=false.
558
1
            ParquetInitContext eq_delete_ctx;
559
1
            eq_delete_ctx.filter_groups = false;
560
1
            eq_delete_ctx.column_names = delete_col_names;
561
1
            eq_delete_ctx.col_name_to_block_idx = &delete_col_name_to_block_idx;
562
1
            auto st2 = parquet_reader->init_reader(&eq_delete_ctx);
563
1
            if (!st2.ok()) {
564
0
                return st2;
565
0
            }
566
1
        } else if (auto* orc_reader = typeid_cast<OrcReader*>(delete_reader.get())) {
567
            // For ORC: use get_parsed_schema with field_ids from delete_file
568
            // ORC field_ids come from the Thrift descriptor, not from ORC metadata
569
0
            RETURN_IF_ERROR(delete_reader->get_parsed_schema(&equality_delete_col_names,
570
0
                                                             &equality_delete_col_types));
571
0
            for (uint32_t idx = 0; idx < equality_delete_col_names.size(); ++idx) {
572
0
                if (idx < read_column_field_ids.size()) {
573
0
                    int field_id = read_column_field_ids[idx];
574
0
                    if (!read_column_field_ids_set.contains(field_id)) continue;
575
0
                    delete_col_ids.emplace_back(field_id);
576
0
                    delete_col_names.emplace_back(equality_delete_col_names[idx]);
577
0
                    delete_col_types.emplace_back(make_nullable(equality_delete_col_types[idx]));
578
0
                    if (!_id_to_block_column_name.contains(field_id)) {
579
0
                        _id_to_block_column_name.emplace(field_id, equality_delete_col_names[idx]);
580
0
                        _expand_col_names.emplace_back(equality_delete_col_names[idx]);
581
0
                        _expand_columns.emplace_back(
582
0
                                make_nullable(equality_delete_col_types[idx])->create_column(),
583
0
                                make_nullable(equality_delete_col_types[idx]),
584
0
                                equality_delete_col_names[idx]);
585
0
                    }
586
0
                }
587
0
            }
588
0
            for (uint32_t idx = 0; idx < delete_col_names.size(); ++idx) {
589
0
                delete_col_name_to_block_idx[delete_col_names[idx]] = idx;
590
0
            }
591
0
            OrcInitContext eq_delete_ctx;
592
0
            eq_delete_ctx.column_names = delete_col_names;
593
0
            eq_delete_ctx.col_name_to_block_idx = &delete_col_name_to_block_idx;
594
0
            RETURN_IF_ERROR(orc_reader->init_reader(&eq_delete_ctx));
595
0
        } else {
596
0
            return Status::InternalError("Unsupported format of delete file");
597
0
        }
598
599
1
        if (!_equality_delete_block_map.contains(delete_col_ids)) {
600
1
            _equality_delete_block_map.emplace(delete_col_ids, _equality_delete_blocks.size());
601
1
            Block block;
602
1
            _generate_equality_delete_block(&block, delete_col_names, delete_col_types);
603
1
            _equality_delete_blocks.emplace_back(block);
604
1
        }
605
1
        Block& eq_file_block = _equality_delete_blocks[_equality_delete_block_map[delete_col_ids]];
606
607
1
        bool eof = false;
608
2
        while (!eof) {
609
1
            Block tmp_block;
610
1
            _generate_equality_delete_block(&tmp_block, delete_col_names, delete_col_types);
611
1
            size_t read_rows = 0;
612
1
            auto st = delete_reader->get_next_block(&tmp_block, &read_rows, &eof);
613
1
            if (!st.ok()) {
614
0
                return st;
615
0
            }
616
1
            if (read_rows > 0) {
617
1
                ScopedMutableBlock scoped_mutable_block(&eq_file_block);
618
1
                auto& mutable_block = scoped_mutable_block.mutable_block();
619
1
                RETURN_IF_ERROR(mutable_block.merge(tmp_block));
620
1
            }
621
1
        }
622
1
    }
623
624
1
    for (const auto& [delete_col_ids, block_idx] : _equality_delete_block_map) {
625
1
        auto& eq_file_block = _equality_delete_blocks[block_idx];
626
1
        auto equality_delete_impl =
627
1
                EqualityDeleteBase::get_delete_impl(&eq_file_block, delete_col_ids);
628
1
        RETURN_IF_ERROR(equality_delete_impl->init(this->get_profile()));
629
1
        _equality_delete_impls.emplace_back(std::move(equality_delete_impl));
630
1
    }
631
1
    return Status::OK();
632
1
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_equality_delete_baseERKSt6vectorINS_22TIcebergDeleteFileDescESaIS4_EE
Line
Count
Source
483
2
        const std::vector<TIcebergDeleteFileDesc>& delete_files) {
484
2
    std::unordered_map<std::string, std::tuple<std::string, const SlotDescriptor*>>
485
2
            partition_columns;
486
2
    std::unordered_map<std::string, VExprContextSPtr> missing_columns;
487
488
2
    for (const auto& delete_file : delete_files) {
489
2
        TFileRangeDesc delete_desc;
490
2
        delete_desc.__set_fs_name(this->get_scan_range().fs_name);
491
2
        delete_desc.path = delete_file.path;
492
2
        delete_desc.start_offset = 0;
493
2
        delete_desc.size = -1;
494
2
        delete_desc.file_size = -1;
495
496
2
        if (!delete_file.__isset.field_ids) [[unlikely]] {
497
0
            return Status::InternalError(
498
0
                    "missing delete field ids when reading equality delete file");
499
0
        }
500
2
        auto& read_column_field_ids = delete_file.field_ids;
501
2
        std::set<int> read_column_field_ids_set;
502
2
        for (const auto& field_id : read_column_field_ids) {
503
2
            read_column_field_ids_set.insert(field_id);
504
2
            _equality_delete_col_ids.insert(field_id);
505
2
        }
506
507
2
        std::unique_ptr<GenericReader> delete_reader = _create_equality_reader(delete_desc);
508
2
        RETURN_IF_ERROR(delete_reader->init_schema_reader());
509
510
2
        std::vector<std::string> equality_delete_col_names;
511
2
        std::vector<DataTypePtr> equality_delete_col_types;
512
513
        // Build delete col names/types/ids by matching field_ids from delete file schema.
514
        // Master iterates delete file's FieldDescriptor and uses field_id to match,
515
        // NOT idx-based pairing (get_parsed_schema order != field_ids order).
516
2
        std::vector<std::string> delete_col_names;
517
2
        std::vector<DataTypePtr> delete_col_types;
518
2
        std::vector<int> delete_col_ids;
519
2
        std::unordered_map<std::string, uint32_t> delete_col_name_to_block_idx;
520
521
2
        if (auto* parquet_reader = typeid_cast<ParquetReader*>(delete_reader.get())) {
522
0
            const FieldDescriptor* delete_field_desc = nullptr;
523
0
            RETURN_IF_ERROR(parquet_reader->get_file_metadata_schema(&delete_field_desc));
524
0
            DCHECK(delete_field_desc != nullptr);
525
526
0
            for (const auto& delete_file_field : delete_field_desc->get_fields_schema()) {
527
0
                if (delete_file_field.field_id == -1) [[unlikely]] {
528
0
                    return Status::DataQualityError(
529
0
                            "missing field id when reading equality delete file");
530
0
                }
531
0
                if (!read_column_field_ids_set.contains(delete_file_field.field_id)) {
532
0
                    continue;
533
0
                }
534
0
                if (delete_file_field.children.size() > 0) [[unlikely]] {
535
0
                    return Status::InternalError(
536
0
                            "can not support read complex column in equality delete file");
537
0
                }
538
539
0
                delete_col_ids.emplace_back(delete_file_field.field_id);
540
0
                delete_col_names.emplace_back(delete_file_field.name);
541
0
                delete_col_types.emplace_back(make_nullable(delete_file_field.data_type));
542
543
0
                int field_id = delete_file_field.field_id;
544
0
                if (!_id_to_block_column_name.contains(field_id)) {
545
0
                    _id_to_block_column_name.emplace(field_id, delete_file_field.name);
546
0
                    _expand_col_names.emplace_back(delete_file_field.name);
547
0
                    _expand_columns.emplace_back(
548
0
                            make_nullable(delete_file_field.data_type)->create_column(),
549
0
                            make_nullable(delete_file_field.data_type), delete_file_field.name);
550
0
                }
551
0
            }
552
0
            for (uint32_t idx = 0; idx < delete_col_names.size(); ++idx) {
553
0
                delete_col_name_to_block_idx[delete_col_names[idx]] = idx;
554
0
            }
555
            // Delete files have TFileRangeDesc.size=-1, which would cause
556
            // set_fill_columns to return EndOfFile("No row group to read")
557
            // when _filter_groups is true. Master passes filter_groups=false.
558
0
            ParquetInitContext eq_delete_ctx;
559
0
            eq_delete_ctx.filter_groups = false;
560
0
            eq_delete_ctx.column_names = delete_col_names;
561
0
            eq_delete_ctx.col_name_to_block_idx = &delete_col_name_to_block_idx;
562
0
            auto st2 = parquet_reader->init_reader(&eq_delete_ctx);
563
0
            if (!st2.ok()) {
564
0
                return st2;
565
0
            }
566
2
        } else if (auto* orc_reader = typeid_cast<OrcReader*>(delete_reader.get())) {
567
            // For ORC: use get_parsed_schema with field_ids from delete_file
568
            // ORC field_ids come from the Thrift descriptor, not from ORC metadata
569
2
            RETURN_IF_ERROR(delete_reader->get_parsed_schema(&equality_delete_col_names,
570
2
                                                             &equality_delete_col_types));
571
4
            for (uint32_t idx = 0; idx < equality_delete_col_names.size(); ++idx) {
572
2
                if (idx < read_column_field_ids.size()) {
573
2
                    int field_id = read_column_field_ids[idx];
574
2
                    if (!read_column_field_ids_set.contains(field_id)) continue;
575
2
                    delete_col_ids.emplace_back(field_id);
576
2
                    delete_col_names.emplace_back(equality_delete_col_names[idx]);
577
2
                    delete_col_types.emplace_back(make_nullable(equality_delete_col_types[idx]));
578
2
                    if (!_id_to_block_column_name.contains(field_id)) {
579
2
                        _id_to_block_column_name.emplace(field_id, equality_delete_col_names[idx]);
580
2
                        _expand_col_names.emplace_back(equality_delete_col_names[idx]);
581
2
                        _expand_columns.emplace_back(
582
2
                                make_nullable(equality_delete_col_types[idx])->create_column(),
583
2
                                make_nullable(equality_delete_col_types[idx]),
584
2
                                equality_delete_col_names[idx]);
585
2
                    }
586
2
                }
587
2
            }
588
4
            for (uint32_t idx = 0; idx < delete_col_names.size(); ++idx) {
589
2
                delete_col_name_to_block_idx[delete_col_names[idx]] = idx;
590
2
            }
591
2
            OrcInitContext eq_delete_ctx;
592
2
            eq_delete_ctx.column_names = delete_col_names;
593
2
            eq_delete_ctx.col_name_to_block_idx = &delete_col_name_to_block_idx;
594
2
            RETURN_IF_ERROR(orc_reader->init_reader(&eq_delete_ctx));
595
2
        } else {
596
0
            return Status::InternalError("Unsupported format of delete file");
597
0
        }
598
599
2
        if (!_equality_delete_block_map.contains(delete_col_ids)) {
600
2
            _equality_delete_block_map.emplace(delete_col_ids, _equality_delete_blocks.size());
601
2
            Block block;
602
2
            _generate_equality_delete_block(&block, delete_col_names, delete_col_types);
603
2
            _equality_delete_blocks.emplace_back(block);
604
2
        }
605
2
        Block& eq_file_block = _equality_delete_blocks[_equality_delete_block_map[delete_col_ids]];
606
607
2
        bool eof = false;
608
6
        while (!eof) {
609
4
            Block tmp_block;
610
4
            _generate_equality_delete_block(&tmp_block, delete_col_names, delete_col_types);
611
4
            size_t read_rows = 0;
612
4
            auto st = delete_reader->get_next_block(&tmp_block, &read_rows, &eof);
613
4
            if (!st.ok()) {
614
0
                return st;
615
0
            }
616
4
            if (read_rows > 0) {
617
2
                ScopedMutableBlock scoped_mutable_block(&eq_file_block);
618
2
                auto& mutable_block = scoped_mutable_block.mutable_block();
619
2
                RETURN_IF_ERROR(mutable_block.merge(tmp_block));
620
2
            }
621
4
        }
622
2
    }
623
624
2
    for (const auto& [delete_col_ids, block_idx] : _equality_delete_block_map) {
625
2
        auto& eq_file_block = _equality_delete_blocks[block_idx];
626
2
        auto equality_delete_impl =
627
2
                EqualityDeleteBase::get_delete_impl(&eq_file_block, delete_col_ids);
628
2
        RETURN_IF_ERROR(equality_delete_impl->init(this->get_profile()));
629
2
        _equality_delete_impls.emplace_back(std::move(equality_delete_impl));
630
2
    }
631
2
    return Status::OK();
632
2
}
633
634
template <typename BaseReader>
635
void IcebergReaderMixin<BaseReader>::_generate_equality_delete_block(
636
        Block* block, const std::vector<std::string>& equality_delete_col_names,
637
8
        const std::vector<DataTypePtr>& equality_delete_col_types) {
638
16
    for (int i = 0; i < equality_delete_col_names.size(); ++i) {
639
8
        DataTypePtr data_type = make_nullable(equality_delete_col_types[i]);
640
8
        MutableColumnPtr data_column = data_type->create_column();
641
8
        block->insert(ColumnWithTypeAndName(std::move(data_column), data_type,
642
8
                                            equality_delete_col_names[i]));
643
8
    }
644
8
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE31_generate_equality_delete_blockEPNS_5BlockERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISB_EERKS5_ISt10shared_ptrIKNS_9IDataTypeEESaISJ_EE
Line
Count
Source
637
2
        const std::vector<DataTypePtr>& equality_delete_col_types) {
638
4
    for (int i = 0; i < equality_delete_col_names.size(); ++i) {
639
2
        DataTypePtr data_type = make_nullable(equality_delete_col_types[i]);
640
2
        MutableColumnPtr data_column = data_type->create_column();
641
2
        block->insert(ColumnWithTypeAndName(std::move(data_column), data_type,
642
2
                                            equality_delete_col_names[i]));
643
2
    }
644
2
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE31_generate_equality_delete_blockEPNS_5BlockERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISB_EERKS5_ISt10shared_ptrIKNS_9IDataTypeEESaISJ_EE
Line
Count
Source
637
6
        const std::vector<DataTypePtr>& equality_delete_col_types) {
638
12
    for (int i = 0; i < equality_delete_col_names.size(); ++i) {
639
6
        DataTypePtr data_type = make_nullable(equality_delete_col_types[i]);
640
6
        MutableColumnPtr data_column = data_type->create_column();
641
6
        block->insert(ColumnWithTypeAndName(std::move(data_column), data_type,
642
6
                                            equality_delete_col_names[i]));
643
6
    }
644
6
}
645
646
template <typename BaseReader>
647
5
Status IcebergReaderMixin<BaseReader>::_expand_block_if_need(Block* block) {
648
5
    std::set<std::string> names;
649
5
    auto block_names = block->get_names();
650
5
    names.insert(block_names.begin(), block_names.end());
651
5
    for (auto& col : _expand_columns) {
652
3
        if (_missing_equality_delete_values.contains(col.name)) {
653
            // Missing equality keys are logical columns, not physical file columns. Add them only
654
            // after the base reader has established the batch row count.
655
1
            continue;
656
1
        }
657
2
        if (names.contains(col.name)) {
658
0
            return Status::InternalError("Wrong expand column '{}'", col.name);
659
0
        }
660
2
        names.insert(col.name);
661
2
        (*this->col_name_to_block_idx_ref())[col.name] = block->columns();
662
2
        block->insert({col.type->create_column(), col.type, col.name});
663
2
    }
664
5
    return Status::OK();
665
5
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_expand_block_if_needEPNS_5BlockE
Line
Count
Source
647
2
Status IcebergReaderMixin<BaseReader>::_expand_block_if_need(Block* block) {
648
2
    std::set<std::string> names;
649
2
    auto block_names = block->get_names();
650
2
    names.insert(block_names.begin(), block_names.end());
651
2
    for (auto& col : _expand_columns) {
652
1
        if (_missing_equality_delete_values.contains(col.name)) {
653
            // Missing equality keys are logical columns, not physical file columns. Add them only
654
            // after the base reader has established the batch row count.
655
0
            continue;
656
0
        }
657
1
        if (names.contains(col.name)) {
658
0
            return Status::InternalError("Wrong expand column '{}'", col.name);
659
0
        }
660
1
        names.insert(col.name);
661
1
        (*this->col_name_to_block_idx_ref())[col.name] = block->columns();
662
1
        block->insert({col.type->create_column(), col.type, col.name});
663
1
    }
664
2
    return Status::OK();
665
2
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_expand_block_if_needEPNS_5BlockE
Line
Count
Source
647
3
Status IcebergReaderMixin<BaseReader>::_expand_block_if_need(Block* block) {
648
3
    std::set<std::string> names;
649
3
    auto block_names = block->get_names();
650
3
    names.insert(block_names.begin(), block_names.end());
651
3
    for (auto& col : _expand_columns) {
652
2
        if (_missing_equality_delete_values.contains(col.name)) {
653
            // Missing equality keys are logical columns, not physical file columns. Add them only
654
            // after the base reader has established the batch row count.
655
1
            continue;
656
1
        }
657
1
        if (names.contains(col.name)) {
658
0
            return Status::InternalError("Wrong expand column '{}'", col.name);
659
0
        }
660
1
        names.insert(col.name);
661
1
        (*this->col_name_to_block_idx_ref())[col.name] = block->columns();
662
1
        block->insert({col.type->create_column(), col.type, col.name});
663
1
    }
664
3
    return Status::OK();
665
3
}
666
667
template <typename BaseReader>
668
Status IcebergReaderMixin<BaseReader>::_register_missing_equality_delete_column(
669
6
        int32_t field_id, const std::string& name, const DataTypePtr& delete_key_type) {
670
6
    DORIS_CHECK(delete_key_type != nullptr);
671
6
    const schema::external::TField* table_field = nullptr;
672
6
    const auto& scan_params = this->get_scan_params();
673
6
    const schema::external::TSchema* current_schema = nullptr;
674
6
    if (scan_params.__isset.history_schema_info && !scan_params.history_schema_info.empty()) {
675
6
        current_schema = &scan_params.history_schema_info.front();
676
6
    }
677
6
    if (current_schema != nullptr && scan_params.__isset.current_schema_id) {
678
6
        const auto schema_it = std::ranges::find_if(
679
6
                scan_params.history_schema_info, [&](const schema::external::TSchema& schema) {
680
6
                    return schema.__isset.schema_id &&
681
6
                           schema.schema_id == scan_params.current_schema_id;
682
6
                });
_ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE40_register_missing_equality_delete_columnEiRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt10shared_ptrIKNS_9IDataTypeEEENKUlRKNS_6schema8external7TSchemaEE_clESL_
Line
Count
Source
679
5
                scan_params.history_schema_info, [&](const schema::external::TSchema& schema) {
680
5
                    return schema.__isset.schema_id &&
681
5
                           schema.schema_id == scan_params.current_schema_id;
682
5
                });
_ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE40_register_missing_equality_delete_columnEiRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt10shared_ptrIKNS_9IDataTypeEEENKUlRKNS_6schema8external7TSchemaEE_clESL_
Line
Count
Source
679
1
                scan_params.history_schema_info, [&](const schema::external::TSchema& schema) {
680
1
                    return schema.__isset.schema_id &&
681
1
                           schema.schema_id == scan_params.current_schema_id;
682
1
                });
683
6
        if (schema_it != scan_params.history_schema_info.end()) {
684
6
            current_schema = &*schema_it;
685
6
        } else {
686
0
            current_schema = nullptr;
687
0
        }
688
6
    }
689
6
    if (current_schema != nullptr && current_schema->__isset.root_field) {
690
11
        for (const auto& field_ptr : current_schema->root_field.fields) {
691
11
            if (field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr &&
692
11
                field_ptr.field_ptr->__isset.id && field_ptr.field_ptr->id == field_id) {
693
5
                table_field = field_ptr.field_ptr.get();
694
5
                break;
695
5
            }
696
11
        }
697
6
    }
698
6
    if (table_field == nullptr) {
699
        // A projected descriptor from an older FE may omit a hidden equality key. Without the
700
        // current Iceberg field metadata BE cannot distinguish a true NULL initial default from a
701
        // non-NULL default, so continuing would risk silently keeping or deleting wrong rows.
702
1
        return Status::InternalError(
703
1
                "Missing Iceberg schema metadata for equality-delete field id {}", field_id);
704
1
    }
705
706
5
    Field value;
707
5
    if (table_field->__isset.initial_default_value) {
708
5
        const auto nested_type = remove_nullable(delete_key_type);
709
5
        const bool default_is_base64 = (table_field->__isset.initial_default_value_is_base64 &&
710
5
                                        table_field->initial_default_value_is_base64) ||
711
5
                                       (table_field->__isset.type &&
712
3
                                        thrift_to_type(table_field->type.type) == TYPE_VARBINARY);
713
5
        if (default_is_base64) {
714
2
            std::string decoded_default;
715
2
            if (!base64_decode(table_field->initial_default_value, &decoded_default)) {
716
0
                return Status::InvalidArgument(
717
0
                        "Invalid Base64 Iceberg initial default for field {}", table_field->name);
718
0
            }
719
2
            if (nested_type->get_primitive_type() == TYPE_VARBINARY) {
720
1
                value = Field::create_field<TYPE_VARBINARY>(StringView(decoded_default));
721
1
            } else {
722
1
                DORIS_CHECK(is_string_type(nested_type->get_primitive_type()));
723
1
                value = Field::create_field<TYPE_STRING>(decoded_default);
724
1
            }
725
3
        } else {
726
3
            RETURN_IF_ERROR(nested_type->get_serde()->from_fe_string(
727
3
                    table_field->initial_default_value, value));
728
3
        }
729
5
    }
730
5
    const bool inserted = _missing_equality_delete_values
731
5
                                  .emplace(name, delete_key_type->create_column_const(1, value))
732
5
                                  .second;
733
5
    DORIS_CHECK(inserted);
734
5
    this->register_synthesized_column_handler(
735
5
            name, [this, name](Block* block, size_t rows) -> Status {
736
1
                DORIS_CHECK(_missing_equality_delete_values.contains(name));
737
1
                return _materialize_missing_equality_delete_column(
738
1
                        block, name, _missing_equality_delete_values.at(name), rows);
739
1
            });
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE40_register_missing_equality_delete_columnEiRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt10shared_ptrIKNS_9IDataTypeEEENKUlPNS_5BlockEmE_clESI_m
_ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE40_register_missing_equality_delete_columnEiRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt10shared_ptrIKNS_9IDataTypeEEENKUlPNS_5BlockEmE_clESI_m
Line
Count
Source
735
1
            name, [this, name](Block* block, size_t rows) -> Status {
736
1
                DORIS_CHECK(_missing_equality_delete_values.contains(name));
737
1
                return _materialize_missing_equality_delete_column(
738
1
                        block, name, _missing_equality_delete_values.at(name), rows);
739
1
            });
740
5
    return Status::OK();
741
5
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE40_register_missing_equality_delete_columnEiRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
669
5
        int32_t field_id, const std::string& name, const DataTypePtr& delete_key_type) {
670
5
    DORIS_CHECK(delete_key_type != nullptr);
671
5
    const schema::external::TField* table_field = nullptr;
672
5
    const auto& scan_params = this->get_scan_params();
673
5
    const schema::external::TSchema* current_schema = nullptr;
674
5
    if (scan_params.__isset.history_schema_info && !scan_params.history_schema_info.empty()) {
675
5
        current_schema = &scan_params.history_schema_info.front();
676
5
    }
677
5
    if (current_schema != nullptr && scan_params.__isset.current_schema_id) {
678
5
        const auto schema_it = std::ranges::find_if(
679
5
                scan_params.history_schema_info, [&](const schema::external::TSchema& schema) {
680
5
                    return schema.__isset.schema_id &&
681
5
                           schema.schema_id == scan_params.current_schema_id;
682
5
                });
683
5
        if (schema_it != scan_params.history_schema_info.end()) {
684
5
            current_schema = &*schema_it;
685
5
        } else {
686
0
            current_schema = nullptr;
687
0
        }
688
5
    }
689
5
    if (current_schema != nullptr && current_schema->__isset.root_field) {
690
9
        for (const auto& field_ptr : current_schema->root_field.fields) {
691
9
            if (field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr &&
692
9
                field_ptr.field_ptr->__isset.id && field_ptr.field_ptr->id == field_id) {
693
4
                table_field = field_ptr.field_ptr.get();
694
4
                break;
695
4
            }
696
9
        }
697
5
    }
698
5
    if (table_field == nullptr) {
699
        // A projected descriptor from an older FE may omit a hidden equality key. Without the
700
        // current Iceberg field metadata BE cannot distinguish a true NULL initial default from a
701
        // non-NULL default, so continuing would risk silently keeping or deleting wrong rows.
702
1
        return Status::InternalError(
703
1
                "Missing Iceberg schema metadata for equality-delete field id {}", field_id);
704
1
    }
705
706
4
    Field value;
707
4
    if (table_field->__isset.initial_default_value) {
708
4
        const auto nested_type = remove_nullable(delete_key_type);
709
4
        const bool default_is_base64 = (table_field->__isset.initial_default_value_is_base64 &&
710
4
                                        table_field->initial_default_value_is_base64) ||
711
4
                                       (table_field->__isset.type &&
712
2
                                        thrift_to_type(table_field->type.type) == TYPE_VARBINARY);
713
4
        if (default_is_base64) {
714
2
            std::string decoded_default;
715
2
            if (!base64_decode(table_field->initial_default_value, &decoded_default)) {
716
0
                return Status::InvalidArgument(
717
0
                        "Invalid Base64 Iceberg initial default for field {}", table_field->name);
718
0
            }
719
2
            if (nested_type->get_primitive_type() == TYPE_VARBINARY) {
720
1
                value = Field::create_field<TYPE_VARBINARY>(StringView(decoded_default));
721
1
            } else {
722
1
                DORIS_CHECK(is_string_type(nested_type->get_primitive_type()));
723
1
                value = Field::create_field<TYPE_STRING>(decoded_default);
724
1
            }
725
2
        } else {
726
2
            RETURN_IF_ERROR(nested_type->get_serde()->from_fe_string(
727
2
                    table_field->initial_default_value, value));
728
2
        }
729
4
    }
730
4
    const bool inserted = _missing_equality_delete_values
731
4
                                  .emplace(name, delete_key_type->create_column_const(1, value))
732
4
                                  .second;
733
4
    DORIS_CHECK(inserted);
734
4
    this->register_synthesized_column_handler(
735
4
            name, [this, name](Block* block, size_t rows) -> Status {
736
4
                DORIS_CHECK(_missing_equality_delete_values.contains(name));
737
4
                return _materialize_missing_equality_delete_column(
738
4
                        block, name, _missing_equality_delete_values.at(name), rows);
739
4
            });
740
4
    return Status::OK();
741
4
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE40_register_missing_equality_delete_columnEiRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
669
1
        int32_t field_id, const std::string& name, const DataTypePtr& delete_key_type) {
670
1
    DORIS_CHECK(delete_key_type != nullptr);
671
1
    const schema::external::TField* table_field = nullptr;
672
1
    const auto& scan_params = this->get_scan_params();
673
1
    const schema::external::TSchema* current_schema = nullptr;
674
1
    if (scan_params.__isset.history_schema_info && !scan_params.history_schema_info.empty()) {
675
1
        current_schema = &scan_params.history_schema_info.front();
676
1
    }
677
1
    if (current_schema != nullptr && scan_params.__isset.current_schema_id) {
678
1
        const auto schema_it = std::ranges::find_if(
679
1
                scan_params.history_schema_info, [&](const schema::external::TSchema& schema) {
680
1
                    return schema.__isset.schema_id &&
681
1
                           schema.schema_id == scan_params.current_schema_id;
682
1
                });
683
1
        if (schema_it != scan_params.history_schema_info.end()) {
684
1
            current_schema = &*schema_it;
685
1
        } else {
686
0
            current_schema = nullptr;
687
0
        }
688
1
    }
689
1
    if (current_schema != nullptr && current_schema->__isset.root_field) {
690
2
        for (const auto& field_ptr : current_schema->root_field.fields) {
691
2
            if (field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr &&
692
2
                field_ptr.field_ptr->__isset.id && field_ptr.field_ptr->id == field_id) {
693
1
                table_field = field_ptr.field_ptr.get();
694
1
                break;
695
1
            }
696
2
        }
697
1
    }
698
1
    if (table_field == nullptr) {
699
        // A projected descriptor from an older FE may omit a hidden equality key. Without the
700
        // current Iceberg field metadata BE cannot distinguish a true NULL initial default from a
701
        // non-NULL default, so continuing would risk silently keeping or deleting wrong rows.
702
0
        return Status::InternalError(
703
0
                "Missing Iceberg schema metadata for equality-delete field id {}", field_id);
704
0
    }
705
706
1
    Field value;
707
1
    if (table_field->__isset.initial_default_value) {
708
1
        const auto nested_type = remove_nullable(delete_key_type);
709
1
        const bool default_is_base64 = (table_field->__isset.initial_default_value_is_base64 &&
710
1
                                        table_field->initial_default_value_is_base64) ||
711
1
                                       (table_field->__isset.type &&
712
1
                                        thrift_to_type(table_field->type.type) == TYPE_VARBINARY);
713
1
        if (default_is_base64) {
714
0
            std::string decoded_default;
715
0
            if (!base64_decode(table_field->initial_default_value, &decoded_default)) {
716
0
                return Status::InvalidArgument(
717
0
                        "Invalid Base64 Iceberg initial default for field {}", table_field->name);
718
0
            }
719
0
            if (nested_type->get_primitive_type() == TYPE_VARBINARY) {
720
0
                value = Field::create_field<TYPE_VARBINARY>(StringView(decoded_default));
721
0
            } else {
722
0
                DORIS_CHECK(is_string_type(nested_type->get_primitive_type()));
723
0
                value = Field::create_field<TYPE_STRING>(decoded_default);
724
0
            }
725
1
        } else {
726
1
            RETURN_IF_ERROR(nested_type->get_serde()->from_fe_string(
727
1
                    table_field->initial_default_value, value));
728
1
        }
729
1
    }
730
1
    const bool inserted = _missing_equality_delete_values
731
1
                                  .emplace(name, delete_key_type->create_column_const(1, value))
732
1
                                  .second;
733
1
    DORIS_CHECK(inserted);
734
1
    this->register_synthesized_column_handler(
735
1
            name, [this, name](Block* block, size_t rows) -> Status {
736
1
                DORIS_CHECK(_missing_equality_delete_values.contains(name));
737
1
                return _materialize_missing_equality_delete_column(
738
1
                        block, name, _missing_equality_delete_values.at(name), rows);
739
1
            });
740
1
    return Status::OK();
741
1
}
742
743
template <typename BaseReader>
744
Status IcebergReaderMixin<BaseReader>::_materialize_missing_equality_delete_column(
745
5
        Block* block, const std::string& name, const ColumnPtr& value, size_t rows) {
746
5
    if (!this->col_name_to_block_idx_ref()->contains(name)) {
747
        // ORC must not register a key that is absent from the file as a physical child. In that
748
        // case the reader block has no slot for the synthesized key, so append one here before
749
        // equality-delete filtering. MultiEqualityDelete requires a full, batch-sized column.
750
1
        const auto expand_col = std::ranges::find_if(
751
1
                _expand_columns,
752
1
                [&](const ColumnWithTypeAndName& col) { return col.name == name; });
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE43_materialize_missing_equality_delete_columnEPNS_5BlockERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_3COWINS_7IColumnEE13immutable_ptrISE_EEmENKUlRKNS_21ColumnWithTypeAndNameEE_clESM_
_ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE43_materialize_missing_equality_delete_columnEPNS_5BlockERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_3COWINS_7IColumnEE13immutable_ptrISE_EEmENKUlRKNS_21ColumnWithTypeAndNameEE_clESM_
Line
Count
Source
752
1
                [&](const ColumnWithTypeAndName& col) { return col.name == name; });
753
1
        DORIS_CHECK(expand_col != _expand_columns.end());
754
1
        (*this->col_name_to_block_idx_ref())[name] = block->columns();
755
1
        block->insert({value->clone_resized(rows)->convert_to_full_column_if_const(),
756
1
                       expand_col->type, name});
757
1
        return Status::OK();
758
1
    }
759
4
    const auto position = this->col_name_to_block_idx_ref()->at(name);
760
4
    DORIS_CHECK(position < block->columns());
761
4
    DORIS_CHECK(block->get_by_position(position).column->empty());
762
    // MultiEqualityDelete hashes each key column directly. Materialize the repeated default so
763
    // every key has the batch row count; a ColumnConst keeps only one nested value and therefore
764
    // cannot participate in the row-wise multi-column hash contract.
765
4
    block->get_by_position(position).column =
766
4
            value->clone_resized(rows)->convert_to_full_column_if_const();
767
4
    return Status::OK();
768
5
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE43_materialize_missing_equality_delete_columnEPNS_5BlockERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_3COWINS_7IColumnEE13immutable_ptrISE_EEm
Line
Count
Source
745
4
        Block* block, const std::string& name, const ColumnPtr& value, size_t rows) {
746
4
    if (!this->col_name_to_block_idx_ref()->contains(name)) {
747
        // ORC must not register a key that is absent from the file as a physical child. In that
748
        // case the reader block has no slot for the synthesized key, so append one here before
749
        // equality-delete filtering. MultiEqualityDelete requires a full, batch-sized column.
750
0
        const auto expand_col = std::ranges::find_if(
751
0
                _expand_columns,
752
0
                [&](const ColumnWithTypeAndName& col) { return col.name == name; });
753
0
        DORIS_CHECK(expand_col != _expand_columns.end());
754
0
        (*this->col_name_to_block_idx_ref())[name] = block->columns();
755
0
        block->insert({value->clone_resized(rows)->convert_to_full_column_if_const(),
756
0
                       expand_col->type, name});
757
0
        return Status::OK();
758
0
    }
759
4
    const auto position = this->col_name_to_block_idx_ref()->at(name);
760
4
    DORIS_CHECK(position < block->columns());
761
4
    DORIS_CHECK(block->get_by_position(position).column->empty());
762
    // MultiEqualityDelete hashes each key column directly. Materialize the repeated default so
763
    // every key has the batch row count; a ColumnConst keeps only one nested value and therefore
764
    // cannot participate in the row-wise multi-column hash contract.
765
4
    block->get_by_position(position).column =
766
4
            value->clone_resized(rows)->convert_to_full_column_if_const();
767
4
    return Status::OK();
768
4
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE43_materialize_missing_equality_delete_columnEPNS_5BlockERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_3COWINS_7IColumnEE13immutable_ptrISE_EEm
Line
Count
Source
745
1
        Block* block, const std::string& name, const ColumnPtr& value, size_t rows) {
746
1
    if (!this->col_name_to_block_idx_ref()->contains(name)) {
747
        // ORC must not register a key that is absent from the file as a physical child. In that
748
        // case the reader block has no slot for the synthesized key, so append one here before
749
        // equality-delete filtering. MultiEqualityDelete requires a full, batch-sized column.
750
1
        const auto expand_col = std::ranges::find_if(
751
1
                _expand_columns,
752
1
                [&](const ColumnWithTypeAndName& col) { return col.name == name; });
753
1
        DORIS_CHECK(expand_col != _expand_columns.end());
754
1
        (*this->col_name_to_block_idx_ref())[name] = block->columns();
755
1
        block->insert({value->clone_resized(rows)->convert_to_full_column_if_const(),
756
1
                       expand_col->type, name});
757
1
        return Status::OK();
758
1
    }
759
0
    const auto position = this->col_name_to_block_idx_ref()->at(name);
760
0
    DORIS_CHECK(position < block->columns());
761
0
    DORIS_CHECK(block->get_by_position(position).column->empty());
762
    // MultiEqualityDelete hashes each key column directly. Materialize the repeated default so
763
    // every key has the batch row count; a ColumnConst keeps only one nested value and therefore
764
    // cannot participate in the row-wise multi-column hash contract.
765
0
    block->get_by_position(position).column =
766
0
            value->clone_resized(rows)->convert_to_full_column_if_const();
767
0
    return Status::OK();
768
1
}
769
770
template <typename BaseReader>
771
Status IcebergReaderMixin<BaseReader>::_materialize_missing_equality_delete_columns(Block* block,
772
2
                                                                                    size_t rows) {
773
4
    for (const auto& [name, value] : _missing_equality_delete_values) {
774
4
        RETURN_IF_ERROR(_materialize_missing_equality_delete_column(block, name, value, rows));
775
4
    }
776
2
    return Status::OK();
777
2
}
778
779
template <typename BaseReader>
780
5
Status IcebergReaderMixin<BaseReader>::_shrink_block_if_need(Block* block) {
781
5
    std::set<size_t> positions_to_erase;
782
5
    for (const std::string& expand_col : _expand_col_names) {
783
3
        if (!this->col_name_to_block_idx_ref()->contains(expand_col)) {
784
0
            return Status::InternalError("Wrong erase column '{}', block: {}", expand_col,
785
0
                                         block->dump_names());
786
0
        }
787
3
        positions_to_erase.emplace((*this->col_name_to_block_idx_ref())[expand_col]);
788
3
    }
789
5
    block->erase(positions_to_erase);
790
5
    for (const std::string& expand_col : _expand_col_names) {
791
3
        this->col_name_to_block_idx_ref()->erase(expand_col);
792
3
    }
793
5
    return Status::OK();
794
5
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_shrink_block_if_needEPNS_5BlockE
Line
Count
Source
780
2
Status IcebergReaderMixin<BaseReader>::_shrink_block_if_need(Block* block) {
781
2
    std::set<size_t> positions_to_erase;
782
2
    for (const std::string& expand_col : _expand_col_names) {
783
1
        if (!this->col_name_to_block_idx_ref()->contains(expand_col)) {
784
0
            return Status::InternalError("Wrong erase column '{}', block: {}", expand_col,
785
0
                                         block->dump_names());
786
0
        }
787
1
        positions_to_erase.emplace((*this->col_name_to_block_idx_ref())[expand_col]);
788
1
    }
789
2
    block->erase(positions_to_erase);
790
2
    for (const std::string& expand_col : _expand_col_names) {
791
1
        this->col_name_to_block_idx_ref()->erase(expand_col);
792
1
    }
793
2
    return Status::OK();
794
2
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_shrink_block_if_needEPNS_5BlockE
Line
Count
Source
780
3
Status IcebergReaderMixin<BaseReader>::_shrink_block_if_need(Block* block) {
781
3
    std::set<size_t> positions_to_erase;
782
3
    for (const std::string& expand_col : _expand_col_names) {
783
2
        if (!this->col_name_to_block_idx_ref()->contains(expand_col)) {
784
0
            return Status::InternalError("Wrong erase column '{}', block: {}", expand_col,
785
0
                                         block->dump_names());
786
0
        }
787
2
        positions_to_erase.emplace((*this->col_name_to_block_idx_ref())[expand_col]);
788
2
    }
789
3
    block->erase(positions_to_erase);
790
3
    for (const std::string& expand_col : _expand_col_names) {
791
2
        this->col_name_to_block_idx_ref()->erase(expand_col);
792
2
    }
793
3
    return Status::OK();
794
3
}
795
796
template <typename BaseReader>
797
Status IcebergReaderMixin<BaseReader>::_position_delete_base(
798
1
        const std::string data_file_path, const std::vector<TIcebergDeleteFileDesc>& delete_files) {
799
1
    std::vector<DeleteRows*> delete_rows_array;
800
1
    int64_t num_delete_rows = 0;
801
1
    for (const auto& delete_file : delete_files) {
802
1
        SCOPED_TIMER(_iceberg_profile.delete_files_read_time);
803
1
        Status create_status = Status::OK();
804
1
        auto* delete_file_cache = _kv_cache->template get<DeleteFile>(
805
1
                _delet_file_cache_key(delete_file.path), [&]() -> DeleteFile* {
806
1
                    auto position_delete = std::make_unique<DeleteFile>();
807
1
                    TFileRangeDesc delete_file_range;
808
1
                    delete_file_range.__set_fs_name(this->get_scan_range().fs_name);
809
1
                    delete_file_range.path = delete_file.path;
810
1
                    delete_file_range.start_offset = 0;
811
1
                    delete_file_range.size = -1;
812
1
                    delete_file_range.file_size = -1;
813
1
                    create_status =
814
1
                            _read_position_delete_file(&delete_file_range, position_delete.get());
815
1
                    if (!create_status) {
816
1
                        return nullptr;
817
1
                    }
818
0
                    return position_delete.release();
819
1
                });
_ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlvE_clB5cxx11Ev
Line
Count
Source
805
1
                _delet_file_cache_key(delete_file.path), [&]() -> DeleteFile* {
806
1
                    auto position_delete = std::make_unique<DeleteFile>();
807
1
                    TFileRangeDesc delete_file_range;
808
1
                    delete_file_range.__set_fs_name(this->get_scan_range().fs_name);
809
1
                    delete_file_range.path = delete_file.path;
810
1
                    delete_file_range.start_offset = 0;
811
1
                    delete_file_range.size = -1;
812
1
                    delete_file_range.file_size = -1;
813
1
                    create_status =
814
1
                            _read_position_delete_file(&delete_file_range, position_delete.get());
815
1
                    if (!create_status) {
816
1
                        return nullptr;
817
1
                    }
818
0
                    return position_delete.release();
819
1
                });
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlvE_clB5cxx11Ev
820
1
        if (create_status.is<ErrorCode::END_OF_FILE>()) {
821
0
            continue;
822
1
        } else if (!create_status.ok()) {
823
1
            return create_status;
824
1
        }
825
826
0
        DeleteFile& delete_file_map = *((DeleteFile*)delete_file_cache);
827
0
        auto get_value = [&](const auto& v) {
828
0
            DeleteRows* row_ids = v.second.get();
829
0
            if (!row_ids->empty()) {
830
0
                delete_rows_array.emplace_back(row_ids);
831
0
                num_delete_rows += row_ids->size();
832
0
            }
833
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_
834
0
        delete_file_map.if_contains(data_file_path, get_value);
835
0
    }
836
0
    if (num_delete_rows > 0) {
837
0
        SCOPED_TIMER(_iceberg_profile.delete_rows_sort_time);
838
0
        _iceberg_delete_rows =
839
0
                _kv_cache->template get<DeleteRows>(data_file_path, [&]() -> DeleteRows* {
840
0
                    auto data_file_position_delete = std::make_unique<DeleteRows>();
841
0
                    _sort_delete_rows(delete_rows_array, num_delete_rows,
842
0
                                      *data_file_position_delete);
843
0
                    return data_file_position_delete.release();
844
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
845
0
        set_delete_rows();
846
0
        COUNTER_UPDATE(_iceberg_profile.num_delete_rows, num_delete_rows);
847
0
    }
848
0
    return Status::OK();
849
1
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EE
Line
Count
Source
798
1
        const std::string data_file_path, const std::vector<TIcebergDeleteFileDesc>& delete_files) {
799
1
    std::vector<DeleteRows*> delete_rows_array;
800
1
    int64_t num_delete_rows = 0;
801
1
    for (const auto& delete_file : delete_files) {
802
1
        SCOPED_TIMER(_iceberg_profile.delete_files_read_time);
803
1
        Status create_status = Status::OK();
804
1
        auto* delete_file_cache = _kv_cache->template get<DeleteFile>(
805
1
                _delet_file_cache_key(delete_file.path), [&]() -> DeleteFile* {
806
1
                    auto position_delete = std::make_unique<DeleteFile>();
807
1
                    TFileRangeDesc delete_file_range;
808
1
                    delete_file_range.__set_fs_name(this->get_scan_range().fs_name);
809
1
                    delete_file_range.path = delete_file.path;
810
1
                    delete_file_range.start_offset = 0;
811
1
                    delete_file_range.size = -1;
812
1
                    delete_file_range.file_size = -1;
813
1
                    create_status =
814
1
                            _read_position_delete_file(&delete_file_range, position_delete.get());
815
1
                    if (!create_status) {
816
1
                        return nullptr;
817
1
                    }
818
1
                    return position_delete.release();
819
1
                });
820
1
        if (create_status.is<ErrorCode::END_OF_FILE>()) {
821
0
            continue;
822
1
        } else if (!create_status.ok()) {
823
1
            return create_status;
824
1
        }
825
826
0
        DeleteFile& delete_file_map = *((DeleteFile*)delete_file_cache);
827
0
        auto get_value = [&](const auto& v) {
828
0
            DeleteRows* row_ids = v.second.get();
829
0
            if (!row_ids->empty()) {
830
0
                delete_rows_array.emplace_back(row_ids);
831
0
                num_delete_rows += row_ids->size();
832
0
            }
833
0
        };
834
0
        delete_file_map.if_contains(data_file_path, get_value);
835
0
    }
836
0
    if (num_delete_rows > 0) {
837
0
        SCOPED_TIMER(_iceberg_profile.delete_rows_sort_time);
838
0
        _iceberg_delete_rows =
839
0
                _kv_cache->template get<DeleteRows>(data_file_path, [&]() -> DeleteRows* {
840
0
                    auto data_file_position_delete = std::make_unique<DeleteRows>();
841
0
                    _sort_delete_rows(delete_rows_array, num_delete_rows,
842
0
                                      *data_file_position_delete);
843
0
                    return data_file_position_delete.release();
844
0
                });
845
0
        set_delete_rows();
846
0
        COUNTER_UPDATE(_iceberg_profile.num_delete_rows, num_delete_rows);
847
0
    }
848
0
    return Status::OK();
849
1
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EE
850
851
template <typename BaseReader>
852
typename IcebergReaderMixin<BaseReader>::PositionDeleteRange
853
0
IcebergReaderMixin<BaseReader>::_get_range(const ColumnDictI32& file_path_column) {
854
0
    PositionDeleteRange range;
855
0
    size_t read_rows = file_path_column.get_data().size();
856
0
    const int* code_path = file_path_column.get_data().data();
857
0
    const int* code_path_start = code_path;
858
0
    const int* code_path_end = code_path + read_rows;
859
0
    while (code_path < code_path_end) {
860
0
        int code = code_path[0];
861
0
        const int* code_end = std::upper_bound(code_path, code_path_end, code);
862
0
        range.data_file_path.emplace_back(file_path_column.get_value(code).to_string());
863
0
        range.range.emplace_back(code_path - code_path_start, code_end - code_path_start);
864
0
        code_path = code_end;
865
0
    }
866
0
    return range;
867
0
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE10_get_rangeERKNS_13ColumnDictI32E
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE10_get_rangeERKNS_13ColumnDictI32E
868
869
template <typename BaseReader>
870
typename IcebergReaderMixin<BaseReader>::PositionDeleteRange
871
0
IcebergReaderMixin<BaseReader>::_get_range(const ColumnString& file_path_column) {
872
0
    PositionDeleteRange range;
873
0
    size_t read_rows = file_path_column.size();
874
0
    size_t index = 0;
875
0
    while (index < read_rows) {
876
0
        StringRef data_path = file_path_column.get_data_at(index);
877
0
        size_t left = index - 1;
878
0
        size_t right = read_rows;
879
0
        while (left + 1 != right) {
880
0
            size_t mid = left + (right - left) / 2;
881
0
            if (file_path_column.get_data_at(mid) > data_path) {
882
0
                right = mid;
883
0
            } else {
884
0
                left = mid;
885
0
            }
886
0
        }
887
0
        range.data_file_path.emplace_back(data_path.to_string());
888
0
        range.range.emplace_back(index, left + 1);
889
0
        index = left + 1;
890
0
    }
891
0
    return range;
892
0
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE10_get_rangeERKNS_9ColumnStrIjEE
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE10_get_rangeERKNS_9ColumnStrIjEE
893
894
template <typename BaseReader>
895
void IcebergReaderMixin<BaseReader>::_sort_delete_rows(
896
        const std::vector<std::vector<int64_t>*>& delete_rows_array, int64_t num_delete_rows,
897
0
        std::vector<int64_t>& result) {
898
0
    if (delete_rows_array.empty()) {
899
0
        return;
900
0
    }
901
0
    if (delete_rows_array.size() == 1) {
902
0
        result.resize(num_delete_rows);
903
0
        memcpy(result.data(), delete_rows_array.front()->data(), sizeof(int64_t) * num_delete_rows);
904
0
        return;
905
0
    }
906
0
    if (delete_rows_array.size() == 2) {
907
0
        result.resize(num_delete_rows);
908
0
        std::merge(delete_rows_array.front()->begin(), delete_rows_array.front()->end(),
909
0
                   delete_rows_array.back()->begin(), delete_rows_array.back()->end(),
910
0
                   result.begin());
911
0
        return;
912
0
    }
913
914
0
    using vec_pair = std::pair<std::vector<int64_t>::iterator, std::vector<int64_t>::iterator>;
915
0
    result.resize(num_delete_rows);
916
0
    auto row_id_iter = result.begin();
917
0
    auto iter_end = result.end();
918
0
    std::vector<vec_pair> rows_array;
919
0
    for (auto* rows : delete_rows_array) {
920
0
        if (!rows->empty()) {
921
0
            rows_array.emplace_back(rows->begin(), rows->end());
922
0
        }
923
0
    }
924
0
    size_t array_size = rows_array.size();
925
0
    while (row_id_iter != iter_end) {
926
0
        int64_t min_index = 0;
927
0
        int64_t min = *rows_array[0].first;
928
0
        for (size_t i = 0; i < array_size; ++i) {
929
0
            if (*rows_array[i].first < min) {
930
0
                min_index = i;
931
0
                min = *rows_array[i].first;
932
0
            }
933
0
        }
934
0
        *row_id_iter++ = min;
935
0
        rows_array[min_index].first++;
936
0
        if (UNLIKELY(rows_array[min_index].first == rows_array[min_index].second)) {
937
0
            rows_array.erase(rows_array.begin() + min_index);
938
0
            array_size--;
939
0
        }
940
0
    }
941
0
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE17_sort_delete_rowsERKSt6vectorIPS3_IlSaIlEESaIS6_EElRS5_
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE17_sort_delete_rowsERKSt6vectorIPS3_IlSaIlEESaIS6_EElRS5_
942
943
template <typename BaseReader>
944
Status IcebergReaderMixin<BaseReader>::_gen_position_delete_file_range(
945
        Block& block, DeleteFile* position_delete, size_t read_rows,
946
0
        bool file_path_column_dictionary_coded) {
947
0
    SCOPED_TIMER(_iceberg_profile.parse_delete_file_time);
948
0
    auto name_to_pos_map = block.get_name_to_pos_map();
949
0
    ColumnPtr path_column = block.get_by_position(name_to_pos_map[ICEBERG_FILE_PATH]).column;
950
0
    DCHECK_EQ(path_column->size(), read_rows);
951
0
    ColumnPtr pos_column = block.get_by_position(name_to_pos_map[ICEBERG_ROW_POS]).column;
952
0
    if (const auto* nullable_col = check_and_get_column<ColumnNullable>(*path_column);
953
0
        nullable_col != nullptr) {
954
0
        if (nullable_col->has_null(0, read_rows)) {
955
0
            return Status::Corruption(
956
0
                    "Iceberg position delete column file_path contains null values");
957
0
        }
958
0
        path_column = remove_nullable(path_column);
959
0
    }
960
0
    if (const auto* nullable_col = check_and_get_column<ColumnNullable>(*pos_column);
961
0
        nullable_col != nullptr) {
962
0
        if (nullable_col->has_null(0, read_rows)) {
963
0
            return Status::Corruption("Iceberg position delete column pos contains null values");
964
0
        }
965
0
        pos_column = remove_nullable(pos_column);
966
0
    }
967
0
    using ColumnType = typename PrimitiveTypeTraits<TYPE_BIGINT>::ColumnType;
968
0
    const int64_t* src_data = assert_cast<const ColumnType&>(*pos_column).get_data().data();
969
0
    PositionDeleteRange range;
970
0
    if (file_path_column_dictionary_coded) {
971
0
        range = _get_range(assert_cast<const ColumnDictI32&>(*path_column));
972
0
    } else {
973
0
        range = _get_range(assert_cast<const ColumnString&>(*path_column));
974
0
    }
975
0
    for (int i = 0; i < range.range.size(); ++i) {
976
0
        std::string key = range.data_file_path[i];
977
0
        auto iter = position_delete->find(key);
978
0
        DeleteRows* delete_rows;
979
0
        if (iter == position_delete->end()) {
980
0
            delete_rows = new DeleteRows;
981
0
            std::unique_ptr<DeleteRows> delete_rows_ptr(delete_rows);
982
0
            (*position_delete)[key] = std::move(delete_rows_ptr);
983
0
        } else {
984
0
            delete_rows = iter->second.get();
985
0
        }
986
0
        const int64_t* cpy_start = src_data + range.range[i].first;
987
0
        const int64_t cpy_count = range.range[i].second - range.range[i].first;
988
0
        int64_t origin_size = delete_rows->size();
989
0
        delete_rows->resize(origin_size + cpy_count);
990
0
        int64_t* dest_position = &(*delete_rows)[origin_size];
991
0
        memcpy(dest_position, cpy_start, cpy_count * sizeof(int64_t));
992
0
    }
993
0
    return Status::OK();
994
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
995
996
template <typename BaseReader>
997
Status IcebergReaderMixin<BaseReader>::read_deletion_vector(
998
1
        const std::string& data_file_path, const TIcebergDeleteFileDesc& delete_file_desc) {
999
1
    Status create_status = Status::OK();
1000
1
    SCOPED_TIMER(_iceberg_profile.delete_files_read_time);
1001
1
    bool decoded_cache_hit = false;
1002
1
    _iceberg_deletion_vector = _kv_cache->template get<DeletionVector>(
1003
1
            build_iceberg_deletion_vector_cache_key(data_file_path, delete_file_desc),
1004
1
            [&]() -> DeletionVector* {
1005
1
                auto deletion_vector = std::make_unique<DeletionVector>();
1006
1007
1
                io::FileCacheStatistics file_cache_stats;
1008
1
                IcebergDeleteFileReaderOptions options;
1009
1
                options.state = this->get_state();
1010
1
                options.profile = this->get_profile();
1011
1
                options.scan_params = &this->get_scan_params();
1012
1
                options.io_ctx = this->get_io_ctx();
1013
1
                options.fs_name = &this->get_scan_range().fs_name;
1014
1
                options.deletion_vector_file_cache_stats = &file_cache_stats;
1015
1
                create_status = read_iceberg_deletion_vector(delete_file_desc, options,
1016
1
                                                             deletion_vector.get());
1017
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_hit_count,
1018
1
                               file_cache_stats.num_local_io_total);
1019
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_miss_count,
1020
1
                               file_cache_stats.num_remote_io_total);
1021
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_peer_read_count,
1022
1
                               file_cache_stats.num_peer_io_total);
1023
1
                if (!create_status.ok()) [[unlikely]] {
1024
1
                    return nullptr;
1025
1
                }
1026
1027
0
                SCOPED_TIMER(_iceberg_profile.parse_delete_file_time);
1028
0
                COUNTER_UPDATE(_iceberg_profile.num_delete_rows, deletion_vector->cardinality());
1029
0
                return deletion_vector.release();
1030
1
            },
_ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescEENKUlvE_clEv
Line
Count
Source
1004
1
            [&]() -> DeletionVector* {
1005
1
                auto deletion_vector = std::make_unique<DeletionVector>();
1006
1007
1
                io::FileCacheStatistics file_cache_stats;
1008
1
                IcebergDeleteFileReaderOptions options;
1009
1
                options.state = this->get_state();
1010
1
                options.profile = this->get_profile();
1011
1
                options.scan_params = &this->get_scan_params();
1012
1
                options.io_ctx = this->get_io_ctx();
1013
1
                options.fs_name = &this->get_scan_range().fs_name;
1014
1
                options.deletion_vector_file_cache_stats = &file_cache_stats;
1015
1
                create_status = read_iceberg_deletion_vector(delete_file_desc, options,
1016
1
                                                             deletion_vector.get());
1017
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_hit_count,
1018
1
                               file_cache_stats.num_local_io_total);
1019
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_miss_count,
1020
1
                               file_cache_stats.num_remote_io_total);
1021
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_peer_read_count,
1022
1
                               file_cache_stats.num_peer_io_total);
1023
1
                if (!create_status.ok()) [[unlikely]] {
1024
1
                    return nullptr;
1025
1
                }
1026
1027
0
                SCOPED_TIMER(_iceberg_profile.parse_delete_file_time);
1028
0
                COUNTER_UPDATE(_iceberg_profile.num_delete_rows, deletion_vector->cardinality());
1029
0
                return deletion_vector.release();
1030
1
            },
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescEENKUlvE_clEv
1031
1
            &decoded_cache_hit);
1032
1033
1
    RETURN_IF_ERROR(create_status);
1034
0
    COUNTER_UPDATE(decoded_cache_hit ? _iceberg_profile.decoded_cache_hit_count
1035
0
                                     : _iceberg_profile.decoded_cache_miss_count,
1036
0
                   1);
1037
0
    if (!_iceberg_deletion_vector->isEmpty()) [[likely]] {
1038
0
        set_deletion_vector();
1039
0
    }
1040
0
    return Status::OK();
1041
1
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescE
Line
Count
Source
998
1
        const std::string& data_file_path, const TIcebergDeleteFileDesc& delete_file_desc) {
999
1
    Status create_status = Status::OK();
1000
1
    SCOPED_TIMER(_iceberg_profile.delete_files_read_time);
1001
1
    bool decoded_cache_hit = false;
1002
1
    _iceberg_deletion_vector = _kv_cache->template get<DeletionVector>(
1003
1
            build_iceberg_deletion_vector_cache_key(data_file_path, delete_file_desc),
1004
1
            [&]() -> DeletionVector* {
1005
1
                auto deletion_vector = std::make_unique<DeletionVector>();
1006
1007
1
                io::FileCacheStatistics file_cache_stats;
1008
1
                IcebergDeleteFileReaderOptions options;
1009
1
                options.state = this->get_state();
1010
1
                options.profile = this->get_profile();
1011
1
                options.scan_params = &this->get_scan_params();
1012
1
                options.io_ctx = this->get_io_ctx();
1013
1
                options.fs_name = &this->get_scan_range().fs_name;
1014
1
                options.deletion_vector_file_cache_stats = &file_cache_stats;
1015
1
                create_status = read_iceberg_deletion_vector(delete_file_desc, options,
1016
1
                                                             deletion_vector.get());
1017
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_hit_count,
1018
1
                               file_cache_stats.num_local_io_total);
1019
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_miss_count,
1020
1
                               file_cache_stats.num_remote_io_total);
1021
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_peer_read_count,
1022
1
                               file_cache_stats.num_peer_io_total);
1023
1
                if (!create_status.ok()) [[unlikely]] {
1024
1
                    return nullptr;
1025
1
                }
1026
1027
1
                SCOPED_TIMER(_iceberg_profile.parse_delete_file_time);
1028
1
                COUNTER_UPDATE(_iceberg_profile.num_delete_rows, deletion_vector->cardinality());
1029
1
                return deletion_vector.release();
1030
1
            },
1031
1
            &decoded_cache_hit);
1032
1033
1
    RETURN_IF_ERROR(create_status);
1034
0
    COUNTER_UPDATE(decoded_cache_hit ? _iceberg_profile.decoded_cache_hit_count
1035
0
                                     : _iceberg_profile.decoded_cache_miss_count,
1036
0
                   1);
1037
0
    if (!_iceberg_deletion_vector->isEmpty()) [[likely]] {
1038
0
        set_deletion_vector();
1039
0
    }
1040
0
    return Status::OK();
1041
1
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescE
1042
1043
} // namespace doris