Coverage Report

Created: 2026-10-09 18:00

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