Coverage Report

Created: 2026-07-08 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/tablet/tablet_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 "storage/tablet/tablet_reader.h"
19
20
#include <gen_cpp/olap_file.pb.h>
21
#include <gen_cpp/segment_v2.pb.h>
22
#include <thrift/protocol/TDebugProtocol.h>
23
24
#include <algorithm>
25
#include <functional>
26
#include <iterator>
27
#include <memory>
28
#include <numeric>
29
#include <ostream>
30
#include <set>
31
#include <shared_mutex>
32
#include <unordered_map>
33
34
#include "common/compiler_util.h" // IWYU pragma: keep
35
#include "common/config.h"
36
#include "common/exception.h"
37
#include "common/logging.h"
38
#include "common/status.h"
39
#include "core/arena.h"
40
#include "core/block/block.h"
41
#include "exec/common/variant_util.h"
42
#include "exprs/bloom_filter_func.h"
43
#include "exprs/create_predicate_function.h"
44
#include "exprs/hybrid_set.h"
45
#include "runtime/query_context.h"
46
#include "runtime/runtime_predicate.h"
47
#include "runtime/runtime_state.h"
48
#include "storage/delete/delete_handler.h"
49
#include "storage/index/bloom_filter/bloom_filter.h"
50
#include "storage/itoken_extractor.h"
51
#include "storage/olap_common.h"
52
#include "storage/olap_define.h"
53
#include "storage/predicate/block_column_predicate.h"
54
#include "storage/predicate/column_predicate.h"
55
#include "storage/predicate/like_column_predicate.h"
56
#include "storage/predicate/predicate_creator.h"
57
#include "storage/row_cursor.h"
58
#include "storage/schema.h"
59
#include "storage/tablet/tablet.h"
60
#include "storage/tablet/tablet_meta.h"
61
#include "storage/tablet/tablet_schema.h"
62
63
namespace doris {
64
using namespace ErrorCode;
65
66
906k
void TabletReader::ReaderParams::check_validation() const {
67
906k
    if (UNLIKELY(version.first == -1 && is_segcompaction == false)) {
68
0
        throw Exception(Status::FatalError("version is not set. tablet={}", tablet->tablet_id()));
69
0
    }
70
906k
}
71
72
905k
Status TabletReader::init(const ReaderParams& read_params) {
73
905k
    Status res = _init_params(read_params);
74
905k
    if (!res.ok()) {
75
0
        LOG(WARNING) << "fail to init reader when init params. res:" << res
76
0
                     << ", tablet_id:" << read_params.tablet->tablet_id()
77
0
                     << ", schema_hash:" << read_params.tablet->schema_hash()
78
0
                     << ", reader type:" << int(read_params.reader_type)
79
0
                     << ", version:" << read_params.version;
80
0
    }
81
905k
    return res;
82
905k
}
83
84
void TabletReader::remove_delete_columns_from_access_paths(
85
        const DeleteHandler& delete_handler, const TabletSchema& tablet_schema,
86
63
        std::map<int32_t, TColumnAccessPaths>& all_access_paths) {
87
63
    auto delete_predicates = AndBlockColumnPredicate::create_shared();
88
63
    std::unordered_map<int32_t, std::vector<std::shared_ptr<const ColumnPredicate>>>
89
63
            del_predicates_for_zone_map;
90
63
    delete_handler.get_delete_conditions_after_version(0, delete_predicates.get(),
91
63
                                                       &del_predicates_for_zone_map);
92
63
    std::set<ColumnId> delete_column_ids;
93
63
    delete_predicates->get_all_column_ids(delete_column_ids);
94
108
    for (auto cid : delete_column_ids) {
95
108
        all_access_paths.erase(tablet_schema.column(cid).unique_id());
96
108
    }
97
63
}
98
99
903k
Status TabletReader::_capture_rs_readers(const ReaderParams& read_params) {
100
903k
    SCOPED_RAW_TIMER(&_stats.tablet_reader_capture_rs_readers_timer_ns);
101
903k
    if (read_params.rs_splits.empty()) {
102
0
        return Status::InternalError("fail to acquire data sources. tablet={}",
103
0
                                     _tablet->tablet_id());
104
0
    }
105
106
903k
    bool eof = false;
107
903k
    bool is_lower_key_included = _keys_param.start_key_include;
108
903k
    bool is_upper_key_included = _keys_param.end_key_include;
109
110
2.21M
    for (int i = 0; i < _keys_param.start_keys.size(); ++i) {
111
        // lower bound
112
1.31M
        RowCursor& start_key = _keys_param.start_keys[i];
113
1.31M
        RowCursor& end_key = _keys_param.end_keys[i];
114
115
1.31M
        if (!is_lower_key_included) {
116
879
            if (compare_row_key(start_key, end_key) >= 0) {
117
0
                VLOG_NOTICE << "return EOF when lower key not include"
118
0
                            << ", start_key=" << start_key.to_string()
119
0
                            << ", end_key=" << end_key.to_string();
120
0
                eof = true;
121
0
                break;
122
0
            }
123
1.31M
        } else {
124
1.31M
            if (compare_row_key(start_key, end_key) > 0) {
125
0
                VLOG_NOTICE << "return EOF when lower key include="
126
0
                            << ", start_key=" << start_key.to_string()
127
0
                            << ", end_key=" << end_key.to_string();
128
0
                eof = true;
129
0
                break;
130
0
            }
131
1.31M
        }
132
133
1.31M
        _is_lower_keys_included.push_back(is_lower_key_included);
134
1.31M
        _is_upper_keys_included.push_back(is_upper_key_included);
135
1.31M
    }
136
137
903k
    if (eof) {
138
0
        return Status::EndOfFile("reach end of scan range. tablet={}", _tablet->tablet_id());
139
0
    }
140
141
903k
    bool need_ordered_result = true;
142
903k
    if (read_params.reader_type == ReaderType::READER_QUERY ||
143
903k
        read_params.reader_type == ReaderType::READER_BINLOG) {
144
880k
        if (_tablet_schema->keys_type() == DUP_KEYS) {
145
            // duplicated keys are allowed, no need to merge sort keys in rowset
146
371k
            need_ordered_result = false;
147
371k
        }
148
880k
        if (_tablet_schema->keys_type() == UNIQUE_KEYS &&
149
880k
            _tablet->enable_unique_key_merge_on_write()) {
150
            // unique keys with merge on write, no need to merge sort keys in rowset
151
466k
            need_ordered_result = false;
152
466k
        }
153
880k
        if (_aggregation) {
154
            // compute engine will aggregate rows with the same key,
155
            // it's ok for rowset to return unordered result
156
841k
            need_ordered_result = false;
157
841k
        }
158
159
880k
        if (_direct_mode) {
160
            // direct mode indicates that the storage layer does not need to merge,
161
            // it's ok for rowset to return unordered result
162
868k
            need_ordered_result = false;
163
868k
        }
164
165
880k
        if (read_params.read_orderby_key) {
166
2.54k
            need_ordered_result = true;
167
2.54k
        }
168
880k
    }
169
170
903k
    _reader_context.reader_type = read_params.reader_type;
171
903k
    _reader_context.version = read_params.version;
172
903k
    _reader_context.tablet_schema = _tablet_schema;
173
903k
    _reader_context.need_ordered_result = need_ordered_result;
174
903k
    _reader_context.topn_filter_source_node_ids = read_params.topn_filter_source_node_ids;
175
903k
    _reader_context.topn_filter_target_node_id = read_params.topn_filter_target_node_id;
176
903k
    _reader_context.read_orderby_key_reverse = read_params.read_orderby_key_reverse;
177
903k
    _reader_context.use_insert_order_when_same =
178
903k
            read_params.use_insert_order_when_same ||
179
903k
            read_params.reader_type == ReaderType::READER_BINLOG ||
180
905k
            read_params.reader_type == ReaderType::READER_BINLOG_COMPACTION;
181
903k
    _reader_context.force_key_ordered_read = read_params.force_key_ordered_read;
182
903k
    _reader_context.read_orderby_key_limit = read_params.read_orderby_key_limit;
183
903k
    _reader_context.return_columns = &_return_columns;
184
903k
    _reader_context.tso_predicate_column_id = read_params.tso_predicate_column_id;
185
903k
    _reader_context.read_orderby_key_columns =
186
903k
            !_orderby_key_columns.empty() ? &_orderby_key_columns : nullptr;
187
903k
    _reader_context.predicates = &_col_predicates;
188
903k
    _reader_context.value_predicates = &_value_col_predicates;
189
903k
    _reader_context.lower_bound_keys = &_keys_param.start_keys;
190
903k
    _reader_context.is_lower_keys_included = &_is_lower_keys_included;
191
903k
    _reader_context.upper_bound_keys = &_keys_param.end_keys;
192
903k
    _reader_context.is_upper_keys_included = &_is_upper_keys_included;
193
903k
    _reader_context.delete_handler = &_delete_handler;
194
903k
    _reader_context.stats = &_stats;
195
903k
    _reader_context.use_page_cache = read_params.use_page_cache;
196
903k
    _reader_context.sequence_id_idx = _sequence_col_idx;
197
903k
    _reader_context.is_unique = tablet()->keys_type() == UNIQUE_KEYS;
198
903k
    _reader_context.merged_rows = &_merged_rows;
199
903k
    _reader_context.delete_bitmap = read_params.delete_bitmap;
200
903k
    _reader_context.enable_unique_key_merge_on_write = tablet()->enable_unique_key_merge_on_write();
201
903k
    _reader_context.enable_mor_value_predicate_pushdown =
202
903k
            read_params.enable_mor_value_predicate_pushdown;
203
903k
    _reader_context.record_rowids = read_params.record_rowids;
204
903k
    _reader_context.rowid_conversion = read_params.rowid_conversion;
205
903k
    _reader_context.is_key_column_group = read_params.is_key_column_group;
206
903k
    _reader_context.common_expr_ctxs_push_down = read_params.common_expr_ctxs_push_down;
207
903k
    _reader_context.output_columns = &read_params.output_columns;
208
903k
    _reader_context.extra_columns = read_params.extra_columns;
209
903k
    _reader_context.push_down_agg_type_opt = read_params.push_down_agg_type_opt;
210
903k
    _reader_context.ttl_seconds = _tablet->ttl_seconds();
211
903k
    _reader_context.score_runtime = read_params.score_runtime;
212
903k
    _reader_context.collection_statistics = read_params.collection_statistics;
213
214
903k
    _reader_context.virtual_column_exprs = read_params.virtual_column_exprs;
215
903k
    _reader_context.ann_topn_runtime = read_params.ann_topn_runtime;
216
217
903k
    _reader_context.condition_cache_digest = read_params.condition_cache_digest;
218
903k
    _reader_context.all_access_paths = read_params.all_access_paths;
219
903k
    _reader_context.predicate_access_paths = read_params.predicate_access_paths;
220
221
    // Force a full read of delete-condition columns: the FE can't see storage deletes and may
222
    // mark them meta-only (OFFSET/NULL), whose content-less read makes the delete predicate
223
    // match nothing and leak deleted rows.
224
903k
    if (!_delete_handler.empty() && !_reader_context.all_access_paths.empty()) {
225
62
        remove_delete_columns_from_access_paths(_delete_handler, *_tablet_schema,
226
62
                                                _reader_context.all_access_paths);
227
62
    }
228
229
    // Propagate general read limit for DUP_KEYS and UNIQUE_KEYS with MOW
230
903k
    _reader_context.general_read_limit = read_params.general_read_limit;
231
232
903k
    return Status::OK();
233
903k
}
234
235
394
TabletColumn TabletReader::materialize_column(const TabletColumn& orig) {
236
394
    if (!orig.is_variant_type()) {
237
383
        return orig;
238
383
    }
239
11
    TabletColumn column_with_cast_type = orig;
240
11
    auto cast_type = _reader_context.target_cast_type_for_variants.at(orig.name());
241
11
    return variant_util::get_column_by_type(cast_type, orig.name(),
242
11
                                            {
243
11
                                                    .unique_id = orig.unique_id(),
244
11
                                                    .parent_unique_id = orig.parent_unique_id(),
245
11
                                                    .path_info = *orig.path_info_ptr(),
246
11
                                            });
247
394
}
248
249
906k
Status TabletReader::_init_params(const ReaderParams& read_params) {
250
906k
    read_params.check_validation();
251
252
906k
    _direct_mode = read_params.direct_mode;
253
906k
    _aggregation = read_params.aggregation;
254
906k
    _reader_type = read_params.reader_type;
255
906k
    _tablet = read_params.tablet;
256
906k
    _tablet_schema = read_params.tablet_schema;
257
906k
    _reader_context.runtime_state = read_params.runtime_state;
258
906k
    _reader_context.target_cast_type_for_variants = read_params.target_cast_type_for_variants;
259
260
906k
    RETURN_IF_ERROR(_init_conditions_param(read_params));
261
262
906k
    Status res = _init_delete_condition(read_params);
263
906k
    if (!res.ok()) {
264
0
        LOG(WARNING) << "fail to init delete param. res = " << res;
265
0
        return res;
266
0
    }
267
268
906k
    res = _init_return_columns(read_params);
269
906k
    if (!res.ok()) {
270
0
        LOG(WARNING) << "fail to init return columns. res = " << res;
271
0
        return res;
272
0
    }
273
274
906k
    res = _init_keys_param(read_params);
275
906k
    if (!res.ok()) {
276
0
        LOG(WARNING) << "fail to init keys param. res=" << res;
277
0
        return res;
278
0
    }
279
906k
    res = _init_orderby_keys_param(read_params);
280
906k
    if (!res.ok()) {
281
0
        LOG(WARNING) << "fail to init orderby keys param. res=" << res;
282
0
        return res;
283
0
    }
284
906k
    if (_tablet_schema->has_sequence_col()) {
285
4.59k
        auto sequence_col_idx = _tablet_schema->sequence_col_idx();
286
4.59k
        DCHECK_NE(sequence_col_idx, -1);
287
17.3k
        for (auto col : _return_columns) {
288
            // query has sequence col
289
17.3k
            if (col == sequence_col_idx) {
290
400
                _sequence_col_idx = sequence_col_idx;
291
400
                break;
292
400
            }
293
17.3k
        }
294
4.59k
    }
295
296
906k
    return res;
297
906k
}
298
299
903k
Status TabletReader::_init_return_columns(const ReaderParams& read_params) {
300
903k
    SCOPED_RAW_TIMER(&_stats.tablet_reader_init_return_columns_timer_ns);
301
903k
    if (read_params.reader_type == ReaderType::READER_QUERY ||
302
903k
        read_params.reader_type == ReaderType::READER_BINLOG) {
303
884k
        _return_columns = read_params.return_columns;
304
884k
        _tablet_columns_convert_to_null_set = read_params.tablet_columns_convert_to_null_set;
305
8.09M
        for (auto id : read_params.return_columns) {
306
8.09M
            if (_tablet_schema->column(id).is_key()) {
307
3.55M
                _key_cids.push_back(id);
308
4.53M
            } else {
309
4.53M
                _value_cids.push_back(id);
310
4.53M
            }
311
8.09M
        }
312
884k
    } else if (read_params.return_columns.empty()) {
313
0
        for (uint32_t i = 0; i < _tablet_schema->num_columns(); ++i) {
314
0
            _return_columns.push_back(i);
315
0
            if (_tablet_schema->column(i).is_key()) {
316
0
                _key_cids.push_back(i);
317
0
            } else {
318
0
                _value_cids.push_back(i);
319
0
            }
320
0
        }
321
0
        VLOG_NOTICE << "return column is empty, using full column as default.";
322
19.1k
    } else if ((read_params.reader_type == ReaderType::READER_CUMULATIVE_COMPACTION ||
323
19.1k
                read_params.reader_type == ReaderType::READER_SEGMENT_COMPACTION ||
324
19.1k
                read_params.reader_type == ReaderType::READER_BASE_COMPACTION ||
325
19.1k
                read_params.reader_type == ReaderType::READER_FULL_COMPACTION ||
326
19.1k
                read_params.reader_type == ReaderType::READER_BINLOG_COMPACTION ||
327
19.1k
                read_params.reader_type == ReaderType::READER_COLD_DATA_COMPACTION ||
328
19.1k
                read_params.reader_type == ReaderType::READER_ALTER_TABLE) &&
329
22.4k
               !read_params.return_columns.empty()) {
330
22.4k
        _return_columns = read_params.return_columns;
331
91.6k
        for (auto id : read_params.return_columns) {
332
91.6k
            if (_tablet_schema->column(id).is_key()) {
333
32.8k
                _key_cids.push_back(id);
334
58.7k
            } else {
335
58.7k
                _value_cids.push_back(id);
336
58.7k
            }
337
91.6k
        }
338
18.4E
    } else if (read_params.reader_type == ReaderType::READER_CHECKSUM) {
339
0
        _return_columns = read_params.return_columns;
340
0
        for (auto id : read_params.return_columns) {
341
0
            if (_tablet_schema->column(id).is_key()) {
342
0
                _key_cids.push_back(id);
343
0
            } else {
344
0
                _value_cids.push_back(id);
345
0
            }
346
0
        }
347
18.4E
    } else {
348
18.4E
        return Status::Error<INVALID_ARGUMENT>(
349
18.4E
                "fail to init return columns. reader_type={}, return_columns_size={}",
350
18.4E
                int(read_params.reader_type), read_params.return_columns.size());
351
18.4E
    }
352
353
907k
    std::sort(_key_cids.begin(), _key_cids.end(), std::greater<>());
354
355
907k
    return Status::OK();
356
903k
}
357
358
905k
Status TabletReader::_init_keys_param(const ReaderParams& read_params) {
359
905k
    SCOPED_RAW_TIMER(&_stats.tablet_reader_init_keys_param_timer_ns);
360
905k
    if (read_params.start_key.empty()) {
361
199k
        return Status::OK();
362
199k
    }
363
364
706k
    _keys_param.start_key_include = read_params.start_key_include;
365
706k
    _keys_param.end_key_include = read_params.end_key_include;
366
367
706k
    size_t start_key_size = read_params.start_key.size();
368
    //_keys_param.start_keys.resize(start_key_size);
369
706k
    std::vector<RowCursor>(start_key_size).swap(_keys_param.start_keys);
370
371
706k
    size_t scan_key_size = read_params.start_key.front().size();
372
706k
    if (scan_key_size > _tablet_schema->num_columns()) {
373
0
        return Status::Error<INVALID_ARGUMENT>(
374
0
                "Input param are invalid. Column count is bigger than num_columns of schema. "
375
0
                "column_count={}, schema.num_columns={}",
376
0
                scan_key_size, _tablet_schema->num_columns());
377
0
    }
378
379
2.02M
    for (size_t i = 0; i < start_key_size; ++i) {
380
1.31M
        if (read_params.start_key[i].size() != scan_key_size) {
381
0
            return Status::Error<INVALID_ARGUMENT>(
382
0
                    "The start_key.at({}).size={}, not equals the scan_key_size={}", i,
383
0
                    read_params.start_key[i].size(), scan_key_size);
384
0
        }
385
386
1.31M
        Status res = _keys_param.start_keys[i].init(_tablet_schema, read_params.start_key[i]);
387
1.31M
        if (!res.ok()) {
388
0
            LOG(WARNING) << "fail to init row cursor. res = " << res;
389
0
            return res;
390
0
        }
391
1.31M
    }
392
393
706k
    size_t end_key_size = read_params.end_key.size();
394
    //_keys_param.end_keys.resize(end_key_size);
395
706k
    std::vector<RowCursor>(end_key_size).swap(_keys_param.end_keys);
396
2.02M
    for (size_t i = 0; i < end_key_size; ++i) {
397
1.31M
        if (read_params.end_key[i].size() != scan_key_size) {
398
0
            return Status::Error<INVALID_ARGUMENT>(
399
0
                    "The end_key.at({}).size={}, not equals the scan_key_size={}", i,
400
0
                    read_params.end_key[i].size(), scan_key_size);
401
0
        }
402
403
1.31M
        Status res = _keys_param.end_keys[i].init(_tablet_schema, read_params.end_key[i]);
404
1.31M
        if (!res.ok()) {
405
0
            LOG(WARNING) << "fail to init row cursor. res = " << res;
406
0
            return res;
407
0
        }
408
1.31M
    }
409
410
    //TODO:check the valid of start_key and end_key.(eg. start_key <= end_key)
411
412
706k
    return Status::OK();
413
706k
}
414
415
905k
Status TabletReader::_init_orderby_keys_param(const ReaderParams& read_params) {
416
905k
    SCOPED_RAW_TIMER(&_stats.tablet_reader_init_orderby_keys_param_timer_ns);
417
    // UNIQUE_KEYS will compare all keys as before
418
905k
    if (_tablet_schema->keys_type() == DUP_KEYS || (_tablet_schema->keys_type() == UNIQUE_KEYS &&
419
861k
                                                    _tablet->enable_unique_key_merge_on_write())) {
420
861k
        if (!_tablet_schema->cluster_key_uids().empty()) {
421
5.47k
            if (read_params.read_orderby_key_num_prefix_columns >
422
5.47k
                _tablet_schema->cluster_key_uids().size()) {
423
0
                return Status::Error<ErrorCode::INTERNAL_ERROR>(
424
0
                        "read_orderby_key_num_prefix_columns={} > cluster_keys.size()={}",
425
0
                        read_params.read_orderby_key_num_prefix_columns,
426
0
                        _tablet_schema->cluster_key_uids().size());
427
0
            }
428
5.48k
            for (uint32_t i = 0; i < read_params.read_orderby_key_num_prefix_columns; i++) {
429
10
                auto cid = _tablet_schema->cluster_key_uids()[i];
430
10
                auto index = _tablet_schema->field_index(cid);
431
10
                if (index < 0) {
432
0
                    return Status::Error<ErrorCode::INTERNAL_ERROR>(
433
0
                            "could not find cluster key column with unique_id=" +
434
0
                            std::to_string(cid) +
435
0
                            " in tablet schema, tablet_id=" + std::to_string(_tablet->tablet_id()));
436
0
                }
437
20
                for (uint32_t idx = 0; idx < _return_columns.size(); idx++) {
438
20
                    if (_return_columns[idx] == index) {
439
10
                        _orderby_key_columns.push_back(idx);
440
10
                        break;
441
10
                    }
442
20
                }
443
10
            }
444
856k
        } else {
445
            // find index in vector _return_columns
446
            //   for the read_orderby_key_num_prefix_columns orderby keys
447
859k
            for (uint32_t i = 0; i < read_params.read_orderby_key_num_prefix_columns; i++) {
448
3.77k
                for (uint32_t idx = 0; idx < _return_columns.size(); idx++) {
449
3.77k
                    if (_return_columns[idx] == i) {
450
3.12k
                        _orderby_key_columns.push_back(idx);
451
3.12k
                        break;
452
3.12k
                    }
453
3.77k
                }
454
3.12k
            }
455
856k
        }
456
861k
        if (read_params.read_orderby_key_num_prefix_columns != _orderby_key_columns.size()) {
457
0
            return Status::Error<ErrorCode::INTERNAL_ERROR>(
458
0
                    "read_orderby_key_num_prefix_columns != _orderby_key_columns.size, "
459
0
                    "read_params.read_orderby_key_num_prefix_columns={}, "
460
0
                    "_orderby_key_columns.size()={}",
461
0
                    read_params.read_orderby_key_num_prefix_columns, _orderby_key_columns.size());
462
0
        }
463
861k
    }
464
465
905k
    return Status::OK();
466
905k
}
467
468
906k
Status TabletReader::_init_conditions_param(const ReaderParams& read_params) {
469
906k
    SCOPED_RAW_TIMER(&_stats.tablet_reader_init_conditions_param_timer_ns);
470
906k
    std::vector<std::shared_ptr<ColumnPredicate>> predicates;
471
906k
    std::copy(read_params.predicates.cbegin(), read_params.predicates.cend(),
472
906k
              std::inserter(predicates, predicates.begin()));
473
    // Function filter push down to storage engine
474
906k
    auto is_like_predicate = [](std::shared_ptr<ColumnPredicate> _pred) {
475
396
        return dynamic_cast<LikeColumnPredicate*>(_pred.get()) != nullptr;
476
396
    };
477
478
906k
    for (const auto& filter : read_params.function_filters) {
479
394
        predicates.emplace_back(_parse_to_predicate(filter));
480
394
        auto pred = predicates.back();
481
482
394
        const auto& col = _tablet_schema->column(pred->column_id());
483
394
        const auto* tablet_index = _tablet_schema->get_ngram_bf_index(col.unique_id());
484
398
        if (is_like_predicate(pred) && tablet_index && config::enable_query_like_bloom_filter) {
485
16
            std::unique_ptr<segment_v2::BloomFilter> ng_bf;
486
16
            std::string pattern = pred->get_search_str();
487
16
            auto gram_bf_size = tablet_index->get_gram_bf_size();
488
16
            auto gram_size = tablet_index->get_gram_size();
489
490
16
            RETURN_IF_ERROR(segment_v2::BloomFilter::create(segment_v2::NGRAM_BLOOM_FILTER, &ng_bf,
491
16
                                                            gram_bf_size));
492
16
            NgramTokenExtractor _token_extractor(gram_size);
493
494
16
            if (_token_extractor.string_like_to_bloom_filter(pattern.data(), pattern.length(),
495
16
                                                             *ng_bf)) {
496
16
                pred->set_page_ng_bf(std::move(ng_bf));
497
16
            }
498
16
        }
499
394
    }
500
501
906k
    int32_t delete_sign_idx = _tablet_schema->delete_sign_idx();
502
906k
    for (auto predicate : predicates) {
503
650k
        auto column = _tablet_schema->column(predicate->column_id());
504
650k
        if (column.aggregation() != FieldAggregationMethod::OLAP_FIELD_AGGREGATION_NONE) {
505
            // When MOR value predicate pushdown is enabled, drop __DORIS_DELETE_SIGN__
506
            // from storage-layer predicates entirely. Delete sign must only be evaluated
507
            // post-merge via VExpr to prevent deleted rows from reappearing.
508
2.93k
            if (read_params.enable_mor_value_predicate_pushdown && delete_sign_idx >= 0 &&
509
2.93k
                predicate->column_id() == static_cast<uint32_t>(delete_sign_idx)) {
510
25
                continue;
511
25
            }
512
2.91k
            _value_col_predicates.push_back(predicate);
513
647k
        } else {
514
647k
            _col_predicates.push_back(predicate);
515
647k
        }
516
650k
    }
517
518
906k
    return Status::OK();
519
906k
}
520
521
std::shared_ptr<ColumnPredicate> TabletReader::_parse_to_predicate(
522
392
        const FunctionFilter& function_filter) {
523
392
    int32_t index = _tablet_schema->field_index(function_filter._col_name);
524
392
    if (index < 0) {
525
0
        throw Exception(Status::InternalError("Column {} not found in tablet schema",
526
0
                                              function_filter._col_name));
527
0
        return nullptr;
528
0
    }
529
392
    const TabletColumn& column = materialize_column(_tablet_schema->column(index));
530
392
    return create_column_predicate(index, std::make_shared<FunctionFilter>(function_filter),
531
392
                                   column.type(), &column);
532
392
}
533
534
904k
Status TabletReader::_init_delete_condition(const ReaderParams& read_params) {
535
904k
    SCOPED_RAW_TIMER(&_stats.tablet_reader_init_delete_condition_param_timer_ns);
536
    // If it's cumu and not allow do delete when cumu
537
904k
    if (read_params.reader_type == ReaderType::READER_SEGMENT_COMPACTION ||
538
907k
        (read_params.reader_type == ReaderType::READER_CUMULATIVE_COMPACTION &&
539
907k
         !config::enable_delete_when_cumu_compaction)) {
540
20.2k
        return Status::OK();
541
20.2k
    }
542
884k
    bool cumu_delete = read_params.reader_type == ReaderType::READER_CUMULATIVE_COMPACTION &&
543
884k
                       config::enable_delete_when_cumu_compaction;
544
    // Delete sign could not be applied when delete on cumu compaction is enabled, bucause it is meant for delete with predicates.
545
    // If delete design is applied on cumu compaction, it will lose effect when doing base compaction.
546
    // `_delete_sign_available` indicates the condition where we could apply delete signs to data.
547
884k
    _delete_sign_available = (((read_params.reader_type == ReaderType::READER_BASE_COMPACTION ||
548
885k
                                read_params.reader_type == ReaderType::READER_FULL_COMPACTION) &&
549
884k
                               config::enable_prune_delete_sign_when_base_compaction) ||
550
885k
                              read_params.reader_type == ReaderType::READER_COLD_DATA_COMPACTION ||
551
885k
                              read_params.reader_type == ReaderType::READER_CHECKSUM);
552
553
    // `_filter_delete` indicates the condition where we should execlude deleted tuples when reading data.
554
    // However, queries will not use this condition but generate special where predicates to filter data.
555
    // (Though a lille bit confused, it is how the current logic working...)
556
885k
    _filter_delete = _delete_sign_available || cumu_delete;
557
884k
    return _delete_handler.init(_tablet_schema, read_params.delete_predicates,
558
884k
                                read_params.version.second);
559
904k
}
560
561
Status TabletReader::init_reader_params_and_create_block(
562
        TabletSharedPtr tablet, ReaderType reader_type,
563
        const std::vector<RowsetSharedPtr>& input_rowsets,
564
0
        TabletReader::ReaderParams* reader_params, Block* block) {
565
0
    reader_params->tablet = tablet;
566
0
    reader_params->reader_type = reader_type;
567
0
    reader_params->version =
568
0
            Version(input_rowsets.front()->start_version(), input_rowsets.back()->end_version());
569
570
0
    TabletReadSource read_source;
571
0
    for (const auto& rowset : input_rowsets) {
572
0
        RowsetReaderSharedPtr rs_reader;
573
0
        RETURN_IF_ERROR(rowset->create_reader(&rs_reader));
574
0
        read_source.rs_splits.emplace_back(std::move(rs_reader));
575
0
    }
576
0
    read_source.fill_delete_predicates();
577
0
    reader_params->set_read_source(std::move(read_source));
578
579
0
    std::vector<RowsetMetaSharedPtr> rowset_metas(input_rowsets.size());
580
0
    std::transform(input_rowsets.begin(), input_rowsets.end(), rowset_metas.begin(),
581
0
                   [](const RowsetSharedPtr& rowset) { return rowset->rowset_meta(); });
582
0
    TabletSchemaSPtr read_tablet_schema =
583
0
            tablet->tablet_schema_with_merged_max_schema_version(rowset_metas);
584
0
    TabletSchemaSPtr merge_tablet_schema = std::make_shared<TabletSchema>();
585
0
    merge_tablet_schema->copy_from(*read_tablet_schema);
586
587
    // Merge the columns in delete predicate that not in latest schema in to current tablet schema
588
0
    for (auto& del_pred : reader_params->delete_predicates) {
589
0
        merge_tablet_schema->merge_dropped_columns(*del_pred->tablet_schema());
590
0
    }
591
0
    reader_params->tablet_schema = merge_tablet_schema;
592
593
0
    reader_params->return_columns.resize(read_tablet_schema->num_columns());
594
0
    std::iota(reader_params->return_columns.begin(), reader_params->return_columns.end(), 0);
595
0
    reader_params->origin_return_columns = &reader_params->return_columns;
596
597
0
    *block = read_tablet_schema->create_block();
598
599
0
    return Status::OK();
600
0
}
601
602
} // namespace doris