Coverage Report

Created: 2026-08-06 18:32

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