Coverage Report

Created: 2026-07-13 08:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/format_v2/table_reader.cpp
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
#include "format_v2/table_reader.h"
19
20
#include <gen_cpp/ExternalTableSchema_types.h>
21
#include <gen_cpp/PlanNodes_types.h>
22
#include <gen_cpp/Types_types.h>
23
24
#include <algorithm>
25
#include <memory>
26
#include <ranges>
27
#include <set>
28
#include <sstream>
29
#include <utility>
30
#include <vector>
31
32
#include "common/cast_set.h"
33
#include "common/status.h"
34
#include "core/assert_cast.h"
35
#include "core/data_type/data_type_array.h"
36
#include "core/data_type/data_type_map.h"
37
#include "core/data_type/data_type_struct.h"
38
#include "exprs/vexpr_context.h"
39
#include "exprs/vslot_ref.h"
40
#include "format/table/deletion_vector_reader.h"
41
#include "format/table/iceberg_delete_file_reader_helper.h"
42
#include "format/table/paimon_reader.h"
43
#include "format_v2/column_mapper.h"
44
#include "format_v2/delimited_text/csv_reader.h"
45
#include "format_v2/delimited_text/text_reader.h"
46
#include "format_v2/json/json_reader.h"
47
#include "format_v2/native/native_reader.h"
48
#include "format_v2/orc/orc_reader.h"
49
#include "format_v2/parquet/parquet_reader.h"
50
#include "storage/segment/condition_cache.h"
51
#include "util/debug_points.h"
52
#include "util/string_util.h"
53
54
namespace doris::format {
55
namespace {
56
57
template <typename T, typename Formatter>
58
61
std::string join_table_reader_debug_strings(const std::vector<T>& values, Formatter formatter) {
59
61
    std::ostringstream out;
60
61
    out << "[";
61
70
    for (size_t i = 0; i < values.size(); ++i) {
62
9
        if (i > 0) {
63
3
            out << ", ";
64
3
        }
65
9
        out << formatter(values[i]);
66
9
    }
67
61
    out << "]";
68
61
    return out.str();
69
61
}
table_reader.cpp:_ZN5doris6format12_GLOBAL__N_131join_table_reader_debug_stringsINS0_16ColumnDefinitionEZNKS0_11TableReader12debug_stringB5cxx11EvE3$_0EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIT_SaISD_EET0_
Line
Count
Source
58
12
std::string join_table_reader_debug_strings(const std::vector<T>& values, Formatter formatter) {
59
12
    std::ostringstream out;
60
12
    out << "[";
61
14
    for (size_t i = 0; i < values.size(); ++i) {
62
2
        if (i > 0) {
63
1
            out << ", ";
64
1
        }
65
2
        out << formatter(values[i]);
66
2
    }
67
12
    out << "]";
68
12
    return out.str();
69
12
}
table_reader.cpp:_ZN5doris6format12_GLOBAL__N_131join_table_reader_debug_stringsINS0_11TableFilterEZNKS0_11TableReader12debug_stringB5cxx11EvE3$_1EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIT_SaISD_EET0_
Line
Count
Source
58
12
std::string join_table_reader_debug_strings(const std::vector<T>& values, Formatter formatter) {
59
12
    std::ostringstream out;
60
12
    out << "[";
61
13
    for (size_t i = 0; i < values.size(); ++i) {
62
1
        if (i > 0) {
63
0
            out << ", ";
64
0
        }
65
1
        out << formatter(values[i]);
66
1
    }
67
12
    out << "]";
68
12
    return out.str();
69
12
}
table_reader.cpp:_ZN5doris6format12_GLOBAL__N_131join_table_reader_debug_stringsINS0_11GlobalIndexEZNS1_25table_filter_debug_stringB5cxx11ERKNS0_11TableFilterEE3$_0EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIT_SaISF_EET0_
Line
Count
Source
58
1
std::string join_table_reader_debug_strings(const std::vector<T>& values, Formatter formatter) {
59
1
    std::ostringstream out;
60
1
    out << "[";
61
2
    for (size_t i = 0; i < values.size(); ++i) {
62
1
        if (i > 0) {
63
0
            out << ", ";
64
0
        }
65
1
        out << formatter(values[i]);
66
1
    }
67
1
    out << "]";
68
1
    return out.str();
69
1
}
table_reader.cpp:_ZN5doris6format12_GLOBAL__N_131join_table_reader_debug_stringsISt10shared_ptrINS_12VExprContextEEZNKS0_11TableReader12debug_stringB5cxx11EvE3$_2EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIT_SaISF_EET0_
Line
Count
Source
58
12
std::string join_table_reader_debug_strings(const std::vector<T>& values, Formatter formatter) {
59
12
    std::ostringstream out;
60
12
    out << "[";
61
13
    for (size_t i = 0; i < values.size(); ++i) {
62
1
        if (i > 0) {
63
0
            out << ", ";
64
0
        }
65
1
        out << formatter(values[i]);
66
1
    }
67
12
    out << "]";
68
12
    return out.str();
69
12
}
table_reader.cpp:_ZN5doris6format12_GLOBAL__N_131join_table_reader_debug_stringsINS0_16ColumnDefinitionEZNKS0_11TableReader12debug_stringB5cxx11EvE3$_3EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIT_SaISD_EET0_
Line
Count
Source
58
12
std::string join_table_reader_debug_strings(const std::vector<T>& values, Formatter formatter) {
59
12
    std::ostringstream out;
60
12
    out << "[";
61
14
    for (size_t i = 0; i < values.size(); ++i) {
62
2
        if (i > 0) {
63
1
            out << ", ";
64
1
        }
65
2
        out << formatter(values[i]);
66
2
    }
67
12
    out << "]";
68
12
    return out.str();
69
12
}
table_reader.cpp:_ZN5doris6format12_GLOBAL__N_131join_table_reader_debug_stringsINS0_11TableReader15FileBlockColumnEZNKS3_12debug_stringB5cxx11EvE3$_4EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIT_SaISD_EET0_
Line
Count
Source
58
12
std::string join_table_reader_debug_strings(const std::vector<T>& values, Formatter formatter) {
59
12
    std::ostringstream out;
60
12
    out << "[";
61
14
    for (size_t i = 0; i < values.size(); ++i) {
62
2
        if (i > 0) {
63
1
            out << ", ";
64
1
        }
65
2
        out << formatter(values[i]);
66
2
    }
67
12
    out << "]";
68
12
    return out.str();
69
12
}
70
71
12
std::string file_format_to_string(FileFormat format) {
72
12
    switch (format) {
73
5
    case FileFormat::PARQUET:
74
5
        return "PARQUET";
75
1
    case FileFormat::ORC:
76
1
        return "ORC";
77
1
    case FileFormat::CSV:
78
1
        return "CSV";
79
1
    case FileFormat::JSON:
80
1
        return "JSON";
81
1
    case FileFormat::TEXT:
82
1
        return "TEXT";
83
1
    case FileFormat::JNI:
84
1
        return "JNI";
85
1
    case FileFormat::NATIVE:
86
1
        return "NATIVE";
87
1
    case FileFormat::ARROW:
88
1
        return "ARROW";
89
12
    }
90
0
    return "UNKNOWN";
91
12
}
92
93
12
std::string push_down_agg_to_string(TPushAggOp::type op) {
94
12
    switch (op) {
95
8
    case TPushAggOp::NONE:
96
8
        return "NONE";
97
1
    case TPushAggOp::COUNT:
98
1
        return "COUNT";
99
1
    case TPushAggOp::MINMAX:
100
1
        return "MINMAX";
101
1
    case TPushAggOp::MIX:
102
1
        return "MIX";
103
1
    case TPushAggOp::COUNT_ON_INDEX:
104
1
        return "COUNT_ON_INDEX";
105
12
    }
106
0
    return "UNKNOWN";
107
12
}
108
109
12
std::string current_file_debug_string(const std::unique_ptr<ScanTask>& task) {
110
12
    if (task == nullptr || task->data_file == nullptr) {
111
11
        return "null";
112
11
    }
113
1
    const auto& file = *task->data_file;
114
1
    std::ostringstream out;
115
1
    out << "FileDescription{path=" << file.path << ", file_size=" << file.file_size
116
1
        << ", range_start_offset=" << file.range_start_offset << ", range_size=" << file.range_size
117
1
        << ", mtime=" << file.mtime << ", fs_name=" << file.fs_name
118
1
        << ", file_cache_admission=" << file.file_cache_admission << "}";
119
1
    return out.str();
120
12
}
121
122
12
std::string partition_values_debug_string(const std::map<std::string, Field>& partition_values) {
123
12
    std::ostringstream out;
124
12
    out << "{";
125
12
    size_t idx = 0;
126
12
    for (const auto& [key, _] : partition_values) {
127
1
        if (idx++ > 0) {
128
0
            out << ", ";
129
0
        }
130
1
        out << key;
131
1
    }
132
12
    out << "}";
133
12
    return out.str();
134
12
}
135
136
1.09M
const schema::external::TField* get_field_ptr(const schema::external::TFieldPtr& field_ptr) {
137
1.09M
    if (!field_ptr.__isset.field_ptr || field_ptr.field_ptr == nullptr) {
138
0
        return nullptr;
139
0
    }
140
1.09M
    return field_ptr.field_ptr.get();
141
1.09M
}
142
143
1.08M
bool external_field_matches_name(const schema::external::TField& field, const std::string& name) {
144
1.08M
    if (field.__isset.name && to_lower(field.name) == to_lower(name)) {
145
60.2k
        return true;
146
60.2k
    }
147
1.02M
    return field.__isset.name_mapping &&
148
1.02M
           std::ranges::any_of(field.name_mapping, [&](const std::string& alias) {
149
10
               return to_lower(alias) == to_lower(name);
150
10
           });
151
1.08M
}
152
153
DataTypePtr find_struct_child_type_by_external_field(const DataTypeStruct& struct_type,
154
14.0k
                                                     const schema::external::TField& field) {
155
29.2k
    for (size_t field_idx = 0; field_idx < struct_type.get_elements().size(); ++field_idx) {
156
29.2k
        if (external_field_matches_name(field, struct_type.get_element_name(field_idx))) {
157
14.0k
            return struct_type.get_element(field_idx);
158
14.0k
        }
159
29.2k
    }
160
4
    return nullptr;
161
14.0k
}
162
163
ColumnDefinition build_schema_column_from_external_field(const schema::external::TField& field,
164
84.3k
                                                         DataTypePtr type) {
165
84.3k
    ColumnDefinition column {
166
18.4E
            .identifier = field.__isset.id ? Field::create_field<TYPE_INT>(field.id) : Field {},
167
84.3k
            .name = field.__isset.name ? field.name : "",
168
84.3k
            .name_mapping =
169
84.3k
                    field.__isset.name_mapping ? field.name_mapping : std::vector<std::string> {},
170
84.3k
            .type = std::move(type),
171
84.3k
            .children = {},
172
84.3k
            .default_expr = nullptr,
173
84.3k
            .is_partition_key = false,
174
84.3k
    };
175
84.3k
    if (column.type == nullptr || !field.__isset.nestedField) {
176
62.9k
        return column;
177
62.9k
    }
178
179
21.3k
    const auto nested_type = remove_nullable(column.type);
180
21.3k
    switch (nested_type->get_primitive_type()) {
181
6.15k
    case TYPE_STRUCT: {
182
6.15k
        if (!field.nestedField.__isset.struct_field ||
183
6.15k
            !field.nestedField.struct_field.__isset.fields) {
184
0
            return column;
185
0
        }
186
6.15k
        const auto& struct_type = assert_cast<const DataTypeStruct&>(*nested_type);
187
14.0k
        for (const auto& child_ptr : field.nestedField.struct_field.fields) {
188
14.0k
            const auto* child_field = get_field_ptr(child_ptr);
189
14.0k
            if (child_field == nullptr || !child_field->__isset.name) {
190
0
                continue;
191
0
            }
192
14.0k
            auto child_type = find_struct_child_type_by_external_field(struct_type, *child_field);
193
14.0k
            if (child_type == nullptr) {
194
0
                continue;
195
0
            }
196
14.0k
            column.children.push_back(
197
14.0k
                    build_schema_column_from_external_field(*child_field, child_type));
198
14.0k
        }
199
6.15k
        break;
200
6.15k
    }
201
6.41k
    case TYPE_ARRAY: {
202
6.41k
        if (!field.nestedField.__isset.array_field ||
203
6.41k
            !field.nestedField.array_field.__isset.item_field) {
204
0
            return column;
205
0
        }
206
6.41k
        const auto* item_field = get_field_ptr(field.nestedField.array_field.item_field);
207
6.41k
        if (item_field == nullptr) {
208
0
            return column;
209
0
        }
210
6.41k
        const auto& array_type = assert_cast<const DataTypeArray&>(*nested_type);
211
6.41k
        auto child =
212
6.41k
                build_schema_column_from_external_field(*item_field, array_type.get_nested_type());
213
6.41k
        child.name = "element";
214
6.41k
        if (child.has_identifier_name()) {
215
0
            child.identifier = Field::create_field<TYPE_STRING>(child.name);
216
0
        }
217
6.41k
        column.children.push_back(std::move(child));
218
6.41k
        break;
219
6.41k
    }
220
8.83k
    case TYPE_MAP: {
221
8.83k
        if (!field.nestedField.__isset.map_field ||
222
8.83k
            !field.nestedField.map_field.__isset.key_field ||
223
8.83k
            !field.nestedField.map_field.__isset.value_field) {
224
0
            return column;
225
0
        }
226
8.83k
        const auto& map_type = assert_cast<const DataTypeMap&>(*nested_type);
227
8.83k
        const auto* key_field = get_field_ptr(field.nestedField.map_field.key_field);
228
8.83k
        if (key_field != nullptr) {
229
8.83k
            auto child =
230
8.83k
                    build_schema_column_from_external_field(*key_field, map_type.get_key_type());
231
8.83k
            child.name = "key";
232
8.83k
            if (child.has_identifier_name()) {
233
0
                child.identifier = Field::create_field<TYPE_STRING>(child.name);
234
0
            }
235
8.83k
            column.children.push_back(std::move(child));
236
8.83k
        }
237
8.83k
        const auto* value_field = get_field_ptr(field.nestedField.map_field.value_field);
238
8.83k
        if (value_field != nullptr) {
239
8.83k
            auto child = build_schema_column_from_external_field(*value_field,
240
8.83k
                                                                 map_type.get_value_type());
241
8.83k
            child.name = "value";
242
8.83k
            if (child.has_identifier_name()) {
243
0
                child.identifier = Field::create_field<TYPE_STRING>(child.name);
244
0
            }
245
8.83k
            column.children.push_back(std::move(child));
246
8.83k
        }
247
8.83k
        break;
248
8.83k
    }
249
0
    default:
250
0
        break;
251
21.3k
    }
252
21.3k
    return column;
253
21.3k
}
254
255
const schema::external::TField* find_external_root_field(const TFileScanRangeParams* params,
256
142k
                                                         const ColumnDefinition& column) {
257
142k
    if (params == nullptr || !params->__isset.history_schema_info ||
258
142k
        params->history_schema_info.empty()) {
259
96.1k
        return nullptr;
260
96.1k
    }
261
46.3k
    const auto* schema = &params->history_schema_info.front();
262
46.3k
    if (params->__isset.current_schema_id) {
263
46.3k
        for (const auto& candidate_schema : params->history_schema_info) {
264
46.3k
            if (candidate_schema.__isset.schema_id &&
265
46.3k
                candidate_schema.schema_id == params->current_schema_id) {
266
46.3k
                schema = &candidate_schema;
267
46.3k
                break;
268
46.3k
            }
269
46.3k
        }
270
46.3k
    }
271
46.3k
    if (!schema->__isset.root_field || !schema->root_field.__isset.fields) {
272
0
        return nullptr;
273
0
    }
274
1.05M
    for (const auto& field_ptr : schema->root_field.fields) {
275
1.05M
        const auto* field = get_field_ptr(field_ptr);
276
1.05M
        if (field == nullptr) {
277
0
            continue;
278
0
        }
279
1.05M
        if (external_field_matches_name(*field, column.name)) {
280
46.2k
            return field;
281
46.2k
        }
282
1.05M
    }
283
184
    return nullptr;
284
46.3k
}
285
286
2
std::string expr_context_debug_string(const VExprContextSPtr& context) {
287
2
    if (context == nullptr) {
288
0
        return "null";
289
0
    }
290
2
    const auto root = context->root();
291
2
    if (root == nullptr) {
292
0
        return "VExprContext{root=null}";
293
0
    }
294
2
    std::ostringstream out;
295
2
    out << "VExprContext{root_name=" << root->expr_name() << ", root_debug=" << root->debug_string()
296
2
        << "}";
297
2
    return out.str();
298
2
}
299
300
1
std::string table_filter_debug_string(const TableFilter& filter) {
301
1
    std::ostringstream out;
302
1
    out << "TableFilter{conjunct=" << expr_context_debug_string(filter.conjunct)
303
1
        << ", global_indices="
304
1
        << join_table_reader_debug_strings(
305
1
                   filter.global_indices,
306
1
                   [](GlobalIndex global_index) { return std::to_string(global_index.value()); })
307
1
        << "}";
308
1
    return out.str();
309
1
}
310
311
12.6k
bool contains_runtime_filter(const VExprContextSPtrs& conjuncts) {
312
13.0k
    return std::ranges::any_of(conjuncts, [](const auto& conjunct) {
313
13.0k
        return conjunct != nullptr && conjunct->root() != nullptr &&
314
13.0k
               conjunct->root()->is_rf_wrapper();
315
13.0k
    });
316
12.6k
}
317
318
136k
void collect_global_indices(const VExprSPtr& expr, std::set<GlobalIndex>* global_indices) {
319
136k
    if (expr == nullptr) {
320
0
        return;
321
0
    }
322
136k
    if (expr->is_rf_wrapper()) {
323
        // RuntimeFilterExpr wraps a real predicate expression but its own thrift node can still
324
        // look like SLOT_REF. Collect indices from the wrapped predicate; do not cast the wrapper
325
        // itself to VSlotRef.
326
4.20k
        collect_global_indices(expr->get_impl(), global_indices);
327
4.20k
        return;
328
4.20k
    }
329
132k
    if (expr->is_slot_ref()) {
330
43.7k
        const auto* slot_ref = assert_cast<const VSlotRef*>(expr.get());
331
43.7k
        DORIS_CHECK(slot_ref->column_id() >= 0);
332
43.7k
        global_indices->insert(GlobalIndex(cast_set<size_t>(slot_ref->column_id())));
333
43.7k
    }
334
132k
    for (const auto& child : expr->children()) {
335
89.5k
        collect_global_indices(child, global_indices);
336
89.5k
    }
337
132k
}
338
339
Status build_table_filters_from_conjunct(const VExprContextSPtr& conjunct, RuntimeState* state,
340
40.1k
                                         std::vector<TableFilter>* table_filters) {
341
40.1k
    if (conjunct == nullptr) {
342
0
        return Status::OK();
343
0
    }
344
40.1k
    std::set<GlobalIndex> global_indices;
345
40.1k
    collect_global_indices(conjunct->root(), &global_indices);
346
40.1k
    if (!global_indices.empty()) {
347
40.1k
        TableFilter table_filter;
348
40.1k
        VExprSPtr filter_root;
349
40.1k
        RETURN_IF_ERROR(clone_table_expr_tree(conjunct->root(), &filter_root));
350
40.1k
        table_filter.conjunct = VExprContext::create_shared(std::move(filter_root));
351
40.7k
        for (const auto global_index : global_indices) {
352
40.7k
            table_filter.global_indices.push_back(global_index);
353
40.7k
        }
354
40.1k
        table_filters->push_back(std::move(table_filter));
355
40.1k
    }
356
40.1k
    return Status::OK();
357
40.1k
}
358
359
Status parse_deletion_vector(const char* buf, size_t buffer_size, DeleteFileDesc::Format format,
360
834
                             DeletionVector* deletion_vector) {
361
834
    DORIS_CHECK(buf != nullptr);
362
834
    DORIS_CHECK(deletion_vector != nullptr);
363
834
    DORIS_CHECK(format == DeleteFileDesc::Format::PAIMON ||
364
834
                format == DeleteFileDesc::Format::ICEBERG);
365
366
834
    if (format == DeleteFileDesc::Format::PAIMON) {
367
115
        RETURN_IF_ERROR(decode_paimon_deletion_vector_buffer(buf, buffer_size, deletion_vector));
368
115
        return Status::OK();
369
115
    }
370
371
719
    return decode_iceberg_deletion_vector_buffer(buf, buffer_size, deletion_vector);
372
834
}
373
374
} // namespace
375
376
std::shared_ptr<io::FileSystemProperties> create_system_properties(
377
27.8k
        const TFileScanRangeParams* scan_params) {
378
27.8k
    auto system_properties = std::make_shared<io::FileSystemProperties>();
379
27.8k
    if (scan_params == nullptr || !scan_params->__isset.file_type) {
380
3.44k
        system_properties->system_type = TFileType::FILE_LOCAL;
381
3.44k
        return system_properties;
382
3.44k
    }
383
24.4k
    system_properties->system_type = scan_params->file_type;
384
24.4k
    system_properties->properties = scan_params->properties;
385
24.4k
    system_properties->hdfs_params = scan_params->hdfs_params;
386
24.4k
    if (scan_params->__isset.broker_addresses) {
387
0
        system_properties->broker_addresses.assign(scan_params->broker_addresses.begin(),
388
0
                                                   scan_params->broker_addresses.end());
389
0
    }
390
24.4k
    return system_properties;
391
27.8k
}
392
393
12
std::string TableReader::debug_string() const {
394
12
    std::ostringstream out;
395
12
    out << "TableReader{format=" << file_format_to_string(_format)
396
12
        << ", push_down_agg_type=" << push_down_agg_to_string(_push_down_agg_type)
397
12
        << ", aggregate_pushdown_tried=" << _aggregate_pushdown_tried
398
12
        << ", has_current_reader=" << (_data_reader.reader != nullptr)
399
12
        << ", has_current_task=" << (_current_task != nullptr)
400
12
        << ", current_file=" << current_file_debug_string(_current_task)
401
12
        << ", has_delete_rows=" << (_delete_rows != nullptr)
402
12
        << ", delete_row_count=" << (_delete_rows == nullptr ? 0 : _delete_rows->size())
403
12
        << ", has_deletion_vector=" << (_deletion_vector != nullptr)
404
12
        << ", deletion_vector_cardinality="
405
12
        << (_deletion_vector == nullptr ? 0 : _deletion_vector->cardinality())
406
12
        << ", has_system_properties=" << (_system_properties != nullptr) << ", system_type="
407
12
        << (_system_properties == nullptr ? static_cast<int>(TFileType::FILE_LOCAL)
408
12
                                          : static_cast<int>(_system_properties->system_type))
409
12
        << ", has_scan_params=" << (_scan_params != nullptr)
410
12
        << ", has_io_ctx=" << (_io_ctx != nullptr)
411
12
        << ", has_runtime_state=" << (_runtime_state != nullptr)
412
12
        << ", has_scanner_profile=" << (_scanner_profile != nullptr)
413
12
        << ", mapper_options=" << _mapper_options.debug_string() << ", projected_columns="
414
12
        << join_table_reader_debug_strings(
415
12
                   _projected_columns,
416
12
                   [](const ColumnDefinition& column) { return column.debug_string(); })
417
12
        << ", partition_values=" << partition_values_debug_string(_partition_values)
418
12
        << ", table_filters="
419
12
        << join_table_reader_debug_strings(
420
12
                   _table_filters,
421
12
                   [](const TableFilter& filter) { return table_filter_debug_string(filter); })
422
12
        << ", conjunct_count=" << _conjuncts.size() << ", conjuncts="
423
12
        << join_table_reader_debug_strings(_conjuncts,
424
12
                                           [](const VExprContextSPtr& conjunct) {
425
1
                                               return expr_context_debug_string(conjunct);
426
1
                                           })
427
12
        << ", file_schema="
428
12
        << join_table_reader_debug_strings(
429
12
                   _data_reader.file_schema,
430
12
                   [](const ColumnDefinition& field) { return field.debug_string(); })
431
12
        << ", file_block_layout="
432
12
        << join_table_reader_debug_strings(
433
12
                   _data_reader.file_block_layout,
434
12
                   [](const FileBlockColumn& column) {
435
2
                       std::ostringstream column_out;
436
2
                       column_out << "FileBlockColumn{file_column_id=" << column.file_column_id
437
2
                                  << ", name=" << column.name << ", type="
438
2
                                  << (column.type == nullptr ? "null" : column.type->get_name())
439
2
                                  << "}";
440
2
                       return column_out.str();
441
2
                   })
442
12
        << ", block_template_columns=" << _data_reader.block_template.columns()
443
12
        << ", column_mapper="
444
12
        << (_data_reader.column_mapper == nullptr ? "null"
445
12
                                                  : _data_reader.column_mapper->debug_string())
446
12
        << "}";
447
12
    return out.str();
448
12
}
449
450
Status TableReader::annotate_projected_column(const TFileScanSlotInfo& slot_info,
451
                                              ProjectedColumnBuildContext* context,
452
142k
                                              ColumnDefinition* column) const {
453
142k
    (void)slot_info;
454
142k
    DORIS_CHECK(context != nullptr);
455
142k
    DORIS_CHECK(column != nullptr);
456
142k
    context->schema_column.reset();
457
142k
    const auto* schema_field = find_external_root_field(context->scan_params, *column);
458
142k
    if (schema_field == nullptr) {
459
96.3k
        return Status::OK();
460
96.3k
    }
461
46.2k
    context->schema_column = build_schema_column_from_external_field(*schema_field, column->type);
462
46.2k
    column->identifier = context->schema_column->identifier;
463
46.2k
    column->name_mapping = context->schema_column->name_mapping;
464
46.2k
    return Status::OK();
465
142k
}
466
467
27.8k
Status TableReader::init(TableReadOptions&& options) {
468
27.8k
    _scan_params = options.scan_params;
469
27.8k
    _format = options.format;
470
27.8k
    _io_ctx = options.io_ctx;
471
27.8k
    _runtime_state = options.runtime_state;
472
27.8k
    _scanner_profile = options.scanner_profile;
473
27.8k
    _file_slot_descs = options.file_slot_descs;
474
27.8k
    _push_down_agg_type = options.push_down_agg_type;
475
27.8k
    _condition_cache_digest = options.condition_cache_digest;
476
27.8k
    _projected_columns = std::move(options.projected_columns);
477
27.8k
    _system_properties = create_system_properties(_scan_params);
478
27.8k
    _mapper_options.mode = TableColumnMappingMode::BY_NAME;
479
27.8k
    _conjuncts = std::move(options.conjuncts);
480
481
27.8k
    if (_scanner_profile != nullptr) {
482
27.8k
        static const char* table_profile = "TableReader";
483
27.8k
        ADD_TIMER_WITH_LEVEL(_scanner_profile, table_profile, 1);
484
27.8k
        _profile.num_delete_files = ADD_CHILD_COUNTER_WITH_LEVEL(_scanner_profile, "NumDeleteFiles",
485
27.8k
                                                                 TUnit::UNIT, table_profile, 1);
486
27.8k
        _profile.num_delete_rows = ADD_CHILD_COUNTER_WITH_LEVEL(_scanner_profile, "NumDeleteRows",
487
27.8k
                                                                TUnit::UNIT, table_profile, 1);
488
27.8k
        _profile.parse_delete_file_time = ADD_CHILD_TIMER_WITH_LEVEL(
489
27.8k
                _scanner_profile, "ParseDeleteFileTime", table_profile, 1);
490
27.8k
        _profile.decoded_dv_cache_hit_count =
491
27.8k
                ADD_CHILD_COUNTER_WITH_LEVEL(_scanner_profile, "DeletionVectorDecodedCacheHitCount",
492
27.8k
                                             TUnit::UNIT, table_profile, 1);
493
27.8k
        _profile.decoded_dv_cache_miss_count = ADD_CHILD_COUNTER_WITH_LEVEL(
494
27.8k
                _scanner_profile, "DeletionVectorDecodedCacheMissCount", TUnit::UNIT, table_profile,
495
27.8k
                1);
496
27.8k
        _profile.dv_file_cache_hit_count = ADD_CHILD_COUNTER_WITH_LEVEL(
497
27.8k
                _scanner_profile, "DeletionVectorFileCacheHitCount", TUnit::UNIT, table_profile, 1);
498
27.8k
        _profile.dv_file_cache_miss_count =
499
27.8k
                ADD_CHILD_COUNTER_WITH_LEVEL(_scanner_profile, "DeletionVectorFileCacheMissCount",
500
27.8k
                                             TUnit::UNIT, table_profile, 1);
501
27.8k
        _profile.dv_file_cache_peer_read_count = ADD_CHILD_COUNTER_WITH_LEVEL(
502
27.8k
                _scanner_profile, "DeletionVectorFileCachePeerReadCount", TUnit::UNIT,
503
27.8k
                table_profile, 1);
504
27.8k
        _profile.exec_timer =
505
27.8k
                ADD_CHILD_TIMER_WITH_LEVEL(_scanner_profile, "GetBlockTime", table_profile, 1);
506
27.8k
        _profile.prepare_split_timer =
507
27.8k
                ADD_CHILD_TIMER_WITH_LEVEL(_scanner_profile, "PrepareSplitTime", table_profile, 1);
508
27.8k
        _profile.finalize_timer =
509
27.8k
                ADD_CHILD_TIMER_WITH_LEVEL(_scanner_profile, "FinalizeBlockTime", table_profile, 1);
510
27.8k
        _profile.create_reader_timer =
511
27.8k
                ADD_CHILD_TIMER_WITH_LEVEL(_scanner_profile, "CreateReaderTime", table_profile, 1);
512
27.8k
        _profile.pushdown_agg_timer =
513
27.8k
                ADD_CHILD_TIMER_WITH_LEVEL(_scanner_profile, "PushDownAggTime", table_profile, 1);
514
27.8k
        _profile.open_reader_timer =
515
27.8k
                ADD_CHILD_TIMER_WITH_LEVEL(_scanner_profile, "OpenReaderTime", table_profile, 1);
516
27.8k
        _profile.runtime_filter_partition_prune_timer = ADD_TIMER_WITH_LEVEL(
517
27.8k
                _scanner_profile, "FileScannerRuntimeFilterPartitionPruningTime", 1);
518
27.8k
        _profile.runtime_filter_partition_pruned_range_counter = ADD_COUNTER_WITH_LEVEL(
519
27.8k
                _scanner_profile, "RuntimeFilterPartitionPrunedRangeNum", TUnit::UNIT, 1);
520
27.8k
    }
521
27.8k
    return Status::OK();
522
27.8k
}
523
524
59.2k
Status TableReader::_build_table_filters_from_conjuncts() {
525
59.2k
    _table_filters.clear();
526
59.2k
    for (const auto& conjunct : _conjuncts) {
527
40.1k
        RETURN_IF_ERROR(
528
40.1k
                build_table_filters_from_conjunct(conjunct, _runtime_state, &_table_filters));
529
40.1k
    }
530
59.2k
    return Status::OK();
531
59.2k
}
532
533
58.6k
Status TableReader::_open_local_filter_exprs(const FileScanRequest& file_request) {
534
58.6k
    RowDescriptor row_desc;
535
58.6k
    for (const auto& conjunct : file_request.conjuncts) {
536
35.4k
        RETURN_IF_ERROR(conjunct->prepare(_runtime_state, row_desc));
537
35.4k
        RETURN_IF_ERROR(conjunct->open(_runtime_state));
538
35.4k
    }
539
58.6k
    for (const auto& delete_conjunct : file_request.delete_conjuncts) {
540
14.8k
        RETURN_IF_ERROR(delete_conjunct->prepare(_runtime_state, row_desc));
541
14.8k
        RETURN_IF_ERROR(delete_conjunct->open(_runtime_state));
542
14.8k
    }
543
58.6k
    return Status::OK();
544
58.6k
}
545
546
58.6k
bool TableReader::_should_enable_condition_cache(const FileScanRequest& file_request) const {
547
58.6k
    if (_condition_cache_digest == 0 || _push_down_agg_type == TPushAggOp::type::COUNT ||
548
58.6k
        _current_file_description == std::nullopt || _data_reader.reader == nullptr) {
549
8.58k
        return false;
550
8.58k
    }
551
    // Condition cache is populated by file readers after evaluating file-local row-level
552
    // conjuncts. Metadata pruning can skip row groups/pages, but it does not produce a per-row
553
    // survivor bitmap that can safely populate the cache.
554
50.0k
    if (file_request.conjuncts.empty()) {
555
28.2k
        return false;
556
28.2k
    }
557
    // Delete files/deletion vectors are table-format state. They may change independently of the
558
    // data file path/mtime/size used by the external cache key, so caching their result can become
559
    // stale. Keep delete filtering enabled, but do not read or write condition cache.
560
21.8k
    if (_delete_rows != nullptr || _deletion_vector != nullptr ||
561
21.8k
        !file_request.delete_conjuncts.empty()) {
562
9.28k
        return false;
563
9.28k
    }
564
    // Runtime filters can arrive late and their payload is not guaranteed to be represented by the
565
    // scan-local digest. Without a read-only mode, a MISS could insert a bitmap for P AND RF under
566
    // the digest for only P. This mirrors the old FileScanner guard.
567
12.5k
    return !contains_runtime_filter(file_request.conjuncts);
568
21.8k
}
569
570
58.6k
Status TableReader::_init_reader_condition_cache(const FileScanRequest& file_request) {
571
58.6k
    _condition_cache = nullptr;
572
58.6k
    _condition_cache_ctx = nullptr;
573
58.6k
    if (!_should_enable_condition_cache(file_request)) {
574
46.6k
        return Status::OK();
575
46.6k
    }
576
577
12.0k
    auto* cache = segment_v2::ConditionCache::instance();
578
12.0k
    if (cache == nullptr) {
579
0
        return Status::OK();
580
0
    }
581
12.0k
    const auto& file = *_current_file_description;
582
12.0k
    _condition_cache_key = segment_v2::ConditionCache::ExternalCacheKey(
583
12.0k
            file.path, file.mtime, file.file_size, _condition_cache_digest, file.range_start_offset,
584
12.0k
            file.range_size,
585
12.0k
            segment_v2::ConditionCache::ExternalCacheKey::BASE_GRANULE_AWARE_VERSION);
586
587
12.0k
    segment_v2::ConditionCacheHandle handle;
588
12.0k
    const bool condition_cache_hit = cache->lookup(_condition_cache_key, &handle);
589
12.0k
    if (condition_cache_hit) {
590
1.78k
        _condition_cache = handle.get_filter_result();
591
1.78k
        ++_condition_cache_hit_count;
592
10.2k
    } else {
593
10.2k
        const int64_t total_rows = _data_reader.reader->get_total_rows();
594
10.2k
        if (total_rows <= 0) {
595
8.18k
            return Status::OK();
596
8.18k
        }
597
        // Add one guard granule for split ranges that start in the middle of a granule. A guard
598
        // false bit beyond the real range never overlaps real rows, but avoids boundary overflow
599
        // when a reader marks the last partial granule.
600
2.05k
        const size_t num_granules = (total_rows + ConditionCacheContext::GRANULE_SIZE - 1) /
601
2.05k
                                    ConditionCacheContext::GRANULE_SIZE;
602
2.05k
        _condition_cache = std::make_shared<std::vector<bool>>(num_granules + 1, false);
603
2.05k
    }
604
605
3.88k
    if (_condition_cache != nullptr) {
606
3.88k
        _condition_cache_ctx = std::make_shared<ConditionCacheContext>();
607
3.88k
        _condition_cache_ctx->is_hit = condition_cache_hit;
608
3.88k
        _condition_cache_ctx->filter_result = _condition_cache;
609
3.88k
        _condition_cache_ctx->num_granules = _condition_cache->size();
610
3.88k
        if (condition_cache_hit) {
611
1.78k
            _condition_cache_ctx->base_granule = handle.get_base_granule();
612
1.78k
        }
613
3.88k
        _data_reader.reader->set_condition_cache_context(_condition_cache_ctx);
614
3.88k
    }
615
3.84k
    return Status::OK();
616
12.0k
}
617
618
59.4k
void TableReader::_finalize_reader_condition_cache() {
619
59.4k
    if (_condition_cache_ctx == nullptr || _condition_cache_ctx->is_hit) {
620
57.3k
        _condition_cache = nullptr;
621
57.3k
        _condition_cache_ctx = nullptr;
622
57.3k
        return;
623
57.3k
    }
624
    // LIMIT or scanner cancellation may close a reader before all selected row ranges are visited.
625
    // Unvisited granules remain false in a MISS bitmap, so inserting a partial bitmap would make a
626
    // later HIT skip valid rows. Only publish cache entries after the physical reader reaches EOF.
627
2.09k
    if (!_current_reader_reached_eof) {
628
40
        _condition_cache = nullptr;
629
40
        _condition_cache_ctx = nullptr;
630
40
        return;
631
40
    }
632
2.05k
    DORIS_CHECK(_condition_cache_ctx->num_granules <= _condition_cache->size());
633
2.05k
    _condition_cache->resize(_condition_cache_ctx->num_granules);
634
2.05k
    segment_v2::ConditionCache::instance()->insert(
635
2.05k
            _condition_cache_key, std::move(_condition_cache), _condition_cache_ctx->base_granule);
636
2.05k
    _condition_cache = nullptr;
637
2.05k
    _condition_cache_ctx = nullptr;
638
2.05k
}
639
640
117k
Status TableReader::create_next_reader(bool* eos) {
641
117k
    SCOPED_TIMER(_profile.create_reader_timer);
642
117k
    DCHECK(_data_reader.reader == nullptr);
643
117k
    if (_current_task == nullptr) {
644
58.3k
        *eos = true;
645
58.3k
        return Status::OK();
646
58.3k
    }
647
648
59.2k
    RETURN_IF_ERROR(create_file_reader(&_data_reader.reader));
649
59.2k
    DORIS_CHECK(_data_reader.reader != nullptr);
650
59.2k
    if (_batch_size > 0) {
651
29.3k
        _data_reader.reader->set_batch_size(_batch_size);
652
29.3k
    }
653
59.2k
    Status st = _data_reader.reader->init(_runtime_state);
654
59.2k
    if (!st.ok()) {
655
8
        if (_io_ctx != nullptr && _io_ctx->should_stop && st.is<ErrorCode::END_OF_FILE>()) {
656
0
            *eos = true;
657
0
            _data_reader.reader.reset();
658
0
            return Status::OK();
659
0
        }
660
8
        return st;
661
8
    }
662
59.2k
    st = open_reader();
663
59.2k
    if (!st.ok()) {
664
0
        if (_io_ctx != nullptr && _io_ctx->should_stop && st.is<ErrorCode::END_OF_FILE>()) {
665
0
            *eos = true;
666
0
            _data_reader.reader.reset();
667
0
            return Status::OK();
668
0
        }
669
0
        return st;
670
0
    }
671
59.2k
    if (_data_reader.reader == nullptr) {
672
686
        *eos = _current_task == nullptr;
673
686
        return Status::OK();
674
686
    }
675
58.5k
    *eos = false;
676
58.5k
    return Status::OK();
677
59.2k
}
678
679
59.2k
Status TableReader::create_file_reader(std::unique_ptr<FileReader>* reader) {
680
59.2k
    DORIS_CHECK(reader != nullptr);
681
59.2k
    const bool enable_mapping_timestamp_tz = _scan_params != nullptr &&
682
59.2k
                                             _scan_params->__isset.enable_mapping_timestamp_tz &&
683
59.3k
                                             _scan_params->enable_mapping_timestamp_tz;
684
59.2k
    if (_format == FileFormat::PARQUET) {
685
40.9k
        *reader = std::make_unique<format::parquet::ParquetReader>(
686
40.9k
                _system_properties, _current_task->data_file, _io_ctx, _scanner_profile,
687
40.9k
                _global_rowid_context, enable_mapping_timestamp_tz);
688
40.9k
        return Status::OK();
689
40.9k
    }
690
18.3k
    if (_format == FileFormat::ORC) {
691
15.1k
        *reader = std::make_unique<format::orc::OrcReader>(
692
15.1k
                _system_properties, _current_task->data_file, _io_ctx, _scanner_profile,
693
15.1k
                _global_rowid_context, enable_mapping_timestamp_tz);
694
15.1k
        return Status::OK();
695
15.1k
    }
696
3.19k
    if (_format == FileFormat::CSV) {
697
645
        if (_file_slot_descs == nullptr) {
698
0
            return Status::InvalidArgument("CSV reader requires file slot descriptors");
699
0
        }
700
        // CSV has no embedded schema. TableReader owns table-level mapping, while CsvReader needs
701
        // only the physical file slots plus scan text parameters to build a file-local schema.
702
        // Non-file columns such as partitions/defaults/virtual row ids are intentionally excluded
703
        // from `_file_slot_descs` and are materialized during finalize_chunk().
704
645
        *reader = std::make_unique<format::csv::CsvReader>(
705
645
                _system_properties, _current_task->data_file, _io_ctx, _scanner_profile,
706
645
                _scan_params, *_file_slot_descs, _current_range_compress_type,
707
645
                _current_range_load_id);
708
645
        return Status::OK();
709
645
    }
710
2.54k
    if (_format == FileFormat::TEXT) {
711
2.33k
        if (_file_slot_descs == nullptr) {
712
0
            return Status::InvalidArgument("Text reader requires file slot descriptors");
713
0
        }
714
        // Text files have no embedded schema. As with CSV, TableReader handles table-level mapping
715
        // and only passes physical file slots to the v2 TextReader.
716
2.33k
        *reader = std::make_unique<format::text::TextReader>(
717
2.33k
                _system_properties, _current_task->data_file, _io_ctx, _scanner_profile,
718
2.33k
                _scan_params, *_file_slot_descs, _current_range_compress_type,
719
2.33k
                _current_range_load_id);
720
2.33k
        return Status::OK();
721
2.33k
    }
722
300
    if (_format == FileFormat::JSON) {
723
300
        if (_file_slot_descs == nullptr) {
724
0
            return Status::InvalidArgument("JSON reader requires file slot descriptors");
725
0
        }
726
300
        *reader = std::make_unique<format::json::JsonReader>(
727
300
                _system_properties, _current_task->data_file, _io_ctx, _scanner_profile,
728
300
                _scan_params, _current_file_range_desc, *_file_slot_descs,
729
300
                _current_range_compress_type, _current_range_load_id);
730
300
        return Status::OK();
731
300
    }
732
18.4E
    if (_format == FileFormat::NATIVE) {
733
2
        *reader = std::make_unique<format::native::NativeReader>(
734
2
                _system_properties, _current_task->data_file, _io_ctx, _scanner_profile);
735
2
        return Status::OK();
736
2
    }
737
18.4E
    return Status::NotSupported("TableReader does not support file format {}",
738
18.4E
                                file_format_to_string(_format));
739
18.4E
}
740
741
62.2k
std::unique_ptr<io::FileDescription> create_file_description(const TFileRangeDesc& range) {
742
62.2k
    auto file_description = std::make_unique<io::FileDescription>();
743
62.2k
    file_description->path = range.path;
744
18.4E
    file_description->file_size = range.__isset.file_size ? range.file_size : -1;
745
62.2k
    file_description->mtime = range.__isset.modification_time ? range.modification_time : 0;
746
62.2k
    file_description->range_start_offset = range.__isset.start_offset ? range.start_offset : 0;
747
62.2k
    file_description->range_size = range.__isset.size ? range.size : -1;
748
62.2k
    if (range.__isset.fs_name) {
749
43.9k
        file_description->fs_name = range.fs_name;
750
43.9k
    }
751
62.2k
    if (range.__isset.file_cache_admission) {
752
62.0k
        file_description->file_cache_admission = range.file_cache_admission;
753
62.0k
    }
754
62.2k
    return file_description;
755
62.2k
}
756
757
62.4k
Status TableReader::prepare_split(const SplitReadOptions& options) {
758
62.4k
    SCOPED_TIMER(_profile.prepare_split_timer);
759
62.4k
    _current_split_pruned = false;
760
    // Update to current split format to handle ORC/PARQUET files in one table.
761
62.4k
    _format = options.current_split_format;
762
62.4k
    _partition_values = std::move(options.partition_values);
763
62.4k
    _current_task.reset();
764
62.4k
    _current_file_description.reset();
765
62.4k
    _current_file_range_desc = options.current_range;
766
62.4k
    _current_range_compress_type = options.current_range.__isset.compress_type
767
62.4k
                                           ? options.current_range.compress_type
768
62.4k
                                           : TFileCompressType::UNKNOWN;
769
62.4k
    _current_range_load_id = options.current_range.__isset.load_id
770
62.4k
                                     ? std::make_optional(options.current_range.load_id)
771
62.4k
                                     : std::nullopt;
772
62.4k
    _global_rowid_context = options.global_rowid_context;
773
62.4k
    _delete_rows = nullptr;
774
62.4k
    _deletion_vector = nullptr;
775
62.4k
    _aggregate_pushdown_tried = false;
776
62.4k
    _remaining_table_level_count = -1;
777
62.4k
    _current_reader_reached_eof = false;
778
62.4k
    RETURN_IF_ERROR(_evaluate_partition_prune_conjuncts(options.partition_prune_conjuncts,
779
62.4k
                                                        &_current_split_pruned));
780
62.4k
    if (_current_split_pruned) {
781
255
        COUNTER_UPDATE(_profile.runtime_filter_partition_pruned_range_counter, 1);
782
255
        return Status::OK();
783
255
    }
784
62.2k
    _current_task = std::make_unique<ScanTask>();
785
62.2k
    _current_task->data_file = create_file_description(options.current_range);
786
62.2k
    _current_file_description = *_current_task->data_file;
787
62.2k
    if (_push_down_agg_type == TPushAggOp::type::COUNT &&
788
62.2k
        options.current_range.__isset.table_format_params &&
789
62.2k
        options.current_range.table_format_params.__isset.table_level_row_count) {
790
1.34k
        DORIS_CHECK(options.current_range.table_format_params.table_level_row_count >= -1);
791
1.34k
        _remaining_table_level_count =
792
1.34k
                options.current_range.table_format_params.table_level_row_count;
793
1.34k
    }
794
62.2k
    if (_is_table_level_count_active()) {
795
108
        return Status::OK();
796
108
    }
797
62.1k
    return _parse_delete_predicates(options);
798
62.2k
}
799
800
Status TableReader::_evaluate_partition_prune_conjuncts(const VExprContextSPtrs& conjuncts,
801
62.4k
                                                        bool* can_filter_all) {
802
62.4k
    DORIS_CHECK(can_filter_all != nullptr);
803
62.4k
    SCOPED_TIMER(_profile.runtime_filter_partition_prune_timer);
804
62.4k
    *can_filter_all = false;
805
62.4k
    if (conjuncts.empty() || _partition_values.empty()) {
806
60.4k
        return Status::OK();
807
60.4k
    }
808
809
2.00k
    VExprContextSPtrs partition_conjuncts;
810
3.03k
    for (const auto& conjunct : conjuncts) {
811
3.03k
        DORIS_CHECK(conjunct != nullptr);
812
3.03k
        DORIS_CHECK(conjunct->root() != nullptr);
813
3.03k
        std::set<GlobalIndex> global_indices;
814
3.03k
        collect_global_indices(conjunct->root(), &global_indices);
815
3.03k
        if (global_indices.empty()) {
816
0
            continue;
817
0
        }
818
3.06k
        const bool partition_only = std::ranges::all_of(global_indices, [&](GlobalIndex index) {
819
3.06k
            if (index.value() >= _projected_columns.size()) {
820
0
                return false;
821
0
            }
822
3.06k
            const auto& column = _projected_columns[index.value()];
823
3.06k
            return column.is_partition_key &&
824
3.06k
                   find_partition_value(column, _partition_values) != nullptr;
825
3.06k
        });
826
3.03k
        if (partition_only) {
827
2.17k
            partition_conjuncts.push_back(conjunct);
828
2.17k
        }
829
3.03k
    }
830
2.00k
    if (partition_conjuncts.empty()) {
831
640
        return Status::OK();
832
640
    }
833
834
1.36k
    Block block;
835
1.36k
    RETURN_IF_ERROR(_build_partition_prune_block(&block));
836
1.36k
    RowDescriptor row_desc;
837
2.17k
    for (const auto& conjunct : partition_conjuncts) {
838
2.17k
        RETURN_IF_ERROR(conjunct->prepare(_runtime_state, row_desc));
839
2.17k
        RETURN_IF_ERROR(conjunct->open(_runtime_state));
840
2.17k
    }
841
1.36k
    IColumn::Filter result_filter(block.rows(), 1);
842
1.36k
    return VExprContext::execute_conjuncts(partition_conjuncts, nullptr, &block, &result_filter,
843
1.36k
                                           can_filter_all);
844
1.36k
}
845
846
1.43k
Status TableReader::_build_partition_prune_block(Block* block) const {
847
1.43k
    DORIS_CHECK(block != nullptr);
848
1.43k
    DORIS_CHECK(!_projected_columns.empty());
849
1.43k
    block->clear();
850
3.53k
    for (const auto& column : _projected_columns) {
851
3.53k
        DORIS_CHECK(column.type != nullptr);
852
3.53k
        ColumnPtr value_column = column.type->create_column_const_with_default_value(1);
853
3.53k
        if (column.is_partition_key) {
854
1.86k
            const auto* partition_value = find_partition_value(column, _partition_values);
855
1.86k
            if (partition_value != nullptr) {
856
1.86k
                value_column = column.type->create_column_const(1, *partition_value);
857
1.86k
            }
858
1.86k
        }
859
3.53k
        block->insert({std::move(value_column), column.type, column.name});
860
3.53k
    }
861
1.43k
    return Status::OK();
862
1.43k
}
863
864
62.0k
Status TableReader::_parse_delete_predicates(const SplitReadOptions& options) {
865
62.0k
    DeleteFileDesc desc {.fs_name = options.current_range.fs_name};
866
62.0k
    bool has_delete_file = false;
867
62.0k
    RETURN_IF_ERROR(_parse_deletion_vector_file(options.current_range.table_format_params, &desc,
868
62.0k
                                                &has_delete_file));
869
62.0k
    if (has_delete_file) {
870
12.6k
        DORIS_CHECK(options.cache != nullptr);
871
12.6k
        Status create_status = Status::OK();
872
873
12.6k
        bool decoded_cache_hit = false;
874
12.6k
        _deletion_vector = options.cache->get<DeletionVector>(
875
12.6k
                desc.key,
876
12.6k
                [&]() -> DeletionVector* {
877
842
                    auto deletion_vector = std::make_unique<DeletionVector>();
878
879
842
                    DeletionVectorReader dv_reader(_runtime_state, _scanner_profile, *_scan_params,
880
842
                                                   desc, _io_ctx.get());
881
842
                    create_status = dv_reader.open();
882
842
                    if (!create_status.ok()) [[unlikely]] {
883
0
                        return nullptr;
884
0
                    }
885
886
842
                    size_t bytes_read = desc.size;
887
842
                    std::vector<char> buffer(bytes_read);
888
842
                    DBUG_EXECUTE_IF("TableReader.parse_deletion_vector.io_error", {
889
842
                        create_status =
890
842
                                Status::IOError("injected format v2 deletion vector read failure");
891
842
                        return nullptr;
892
842
                    });
893
836
                    DBUG_EXECUTE_IF("TableReader.parse_deletion_vector.should_stop", {
894
836
                        create_status = Status::EndOfFile("stop read.");
895
836
                        return nullptr;
896
836
                    });
897
835
                    create_status =
898
835
                            dv_reader.read_at(desc.start_offset, {buffer.data(), bytes_read});
899
835
                    const auto& file_cache_stats = dv_reader.file_cache_statistics();
900
835
                    COUNTER_UPDATE(_profile.dv_file_cache_hit_count,
901
835
                                   file_cache_stats.num_local_io_total);
902
835
                    COUNTER_UPDATE(_profile.dv_file_cache_miss_count,
903
835
                                   file_cache_stats.num_remote_io_total);
904
835
                    COUNTER_UPDATE(_profile.dv_file_cache_peer_read_count,
905
835
                                   file_cache_stats.num_peer_io_total);
906
835
                    if (!create_status.ok()) [[unlikely]] {
907
0
                        return nullptr;
908
0
                    }
909
910
835
                    const char* buf = buffer.data();
911
835
                    SCOPED_TIMER(_profile.parse_delete_file_time);
912
835
                    create_status = parse_deletion_vector(buf, bytes_read, desc.format,
913
835
                                                          deletion_vector.get());
914
835
                    if (!create_status.ok()) [[unlikely]] {
915
1
                        return nullptr;
916
1
                    }
917
834
                    COUNTER_UPDATE(_profile.num_delete_rows, deletion_vector->cardinality());
918
834
                    return deletion_vector.release();
919
835
                },
920
12.6k
                &decoded_cache_hit);
921
12.6k
        RETURN_IF_ERROR(create_status);
922
12.6k
        COUNTER_UPDATE(decoded_cache_hit ? _profile.decoded_dv_cache_hit_count
923
12.6k
                                         : _profile.decoded_dv_cache_miss_count,
924
12.6k
                       1);
925
12.6k
    }
926
927
62.0k
    return Status::OK();
928
62.0k
}
929
} // namespace doris::format