Coverage Report

Created: 2025-04-30 15:20

/root/doris/be/src/olap/delete_handler.cpp
Line
Count
Source (jump to first uncovered line)
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 "olap/delete_handler.h"
19
20
#include <gen_cpp/PaloInternalService_types.h>
21
#include <gen_cpp/olap_file.pb.h>
22
#include <thrift/protocol/TDebugProtocol.h>
23
24
#include <string>
25
#include <vector>
26
27
#include "common/config.h"
28
#include "common/logging.h"
29
#include "common/status.h"
30
#include "olap/block_column_predicate.h"
31
#include "olap/column_predicate.h"
32
#include "olap/olap_common.h"
33
#include "olap/predicate_creator.h"
34
#include "olap/tablet_schema.h"
35
#include "olap/utils.h"
36
#include "util/debug_points.h"
37
38
using apache::thrift::ThriftDebugString;
39
using std::vector;
40
using std::string;
41
42
using ::google::protobuf::RepeatedPtrField;
43
44
namespace doris {
45
46
// construct sub condition from TCondition
47
174
std::string construct_sub_predicate(const TCondition& condition) {
48
174
    string op = condition.condition_op;
49
174
    if (op == "<") {
50
100
        op += "<";
51
100
    } else if (op == ">") {
52
6
        op += ">";
53
6
    }
54
174
    string condition_str;
55
174
    if ("IS" == op) {
56
        // ATTN: tricky! Surround IS with spaces to make it "special"
57
2
        condition_str = condition.column_name + " IS " + condition.condition_values[0];
58
172
    } else { // multi-elements IN expr has been processed with InPredicatePB
59
172
        if (op == "*=") {
60
2
            op = "=";
61
170
        } else if (op == "!*=") {
62
2
            op = "!=";
63
2
        }
64
172
        condition_str = condition.column_name + op + "'" + condition.condition_values[0] + "'";
65
172
    }
66
174
    return condition_str;
67
174
}
68
69
// make operators from FE adaptive to BE
70
174
std::string trans_op(const std::string& opt) {
71
174
    std::string op = string(opt);
72
174
    if (op == "<") {
73
100
        op += "<";
74
100
    } else if (op == ">") {
75
6
        op += ">";
76
6
    }
77
174
    if ("IS" != op) {
78
172
        if (op == "*=") {
79
2
            op = "=";
80
170
        } else if (op == "!*=") {
81
2
            op = "!=";
82
2
        }
83
172
    }
84
174
    return op;
85
174
}
86
87
Status DeleteHandler::generate_delete_predicate(const TabletSchema& schema,
88
                                                const std::vector<TCondition>& conditions,
89
194
                                                DeletePredicatePB* del_pred) {
90
194
    DBUG_EXECUTE_IF("DeleteHandler::generate_delete_predicate.inject_failure", {
91
194
        return Status::Error<false>(dp->param<int>("error_code"),
92
194
                                    dp->param<std::string>("error_msg"));
93
194
    })
94
194
    if (conditions.empty()) {
95
2
        return Status::Error<ErrorCode::INVALID_ARGUMENT>(
96
2
                "invalid parameters for store_cond. condition_size={}", conditions.size());
97
2
    }
98
99
    // Check whether the delete condition meets the requirements
100
226
    for (const TCondition& condition : conditions) {
101
226
        RETURN_IF_ERROR(check_condition_valid(schema, condition));
102
226
    }
103
104
    // Store delete condition
105
176
    for (const TCondition& condition : conditions) {
106
176
        if (condition.condition_values.size() > 1) {
107
2
            InPredicatePB* in_pred = del_pred->add_in_predicates();
108
2
            if (condition.__isset.column_unique_id) {
109
0
                in_pred->set_column_unique_id(condition.column_unique_id);
110
0
            }
111
2
            in_pred->set_column_name(condition.column_name);
112
2
            bool is_not_in = condition.condition_op == "!*=";
113
2
            in_pred->set_is_not_in(is_not_in);
114
4
            for (const auto& condition_value : condition.condition_values) {
115
4
                in_pred->add_values(condition_value);
116
4
            }
117
118
2
            LOG(INFO) << "store one sub-delete condition. condition name=" << in_pred->column_name()
119
2
                      << "condition size=" << in_pred->values().size();
120
174
        } else {
121
            // write sub predicate v1 for compactbility
122
174
            std::string condition_str = construct_sub_predicate(condition);
123
174
            VLOG_NOTICE << __PRETTY_FUNCTION__ << " condition_str: " << condition_str;
124
174
            del_pred->add_sub_predicates(condition_str);
125
174
            DeleteSubPredicatePB* sub_predicate = del_pred->add_sub_predicates_v2();
126
174
            if (condition.__isset.column_unique_id) {
127
                // only light schema change capable table set this field
128
0
                sub_predicate->set_column_unique_id(condition.column_unique_id);
129
174
            } else if (TCondition tmp; !DeleteHandler::parse_condition(condition_str, &tmp)) {
130
                // for non light shema change tables, check regex match for condition str
131
0
                LOG(WARNING) << "failed to parse condition_str, condtion="
132
0
                             << ThriftDebugString(condition);
133
0
                return Status::Error<ErrorCode::INVALID_ARGUMENT>(
134
0
                        "failed to parse condition_str, condtion={}", ThriftDebugString(condition));
135
0
            }
136
137
174
            sub_predicate->set_column_name(condition.column_name);
138
174
            sub_predicate->set_op(trans_op(condition.condition_op));
139
174
            sub_predicate->set_cond_value(condition.condition_values[0]);
140
174
            LOG(INFO) << "store one sub-delete condition. condition="
141
174
                      << fmt::format(" {} {} {}", condition.column_name, condition.condition_op,
142
174
                                     condition.condition_values[0]);
143
174
        }
144
176
    }
145
142
    del_pred->set_version(-1);
146
147
142
    return Status::OK();
148
142
}
149
150
Status DeleteHandler::convert_to_sub_pred_v2(DeletePredicatePB* delete_pred,
151
0
                                             TabletSchemaSPtr schema) {
152
0
    if (!delete_pred->sub_predicates().empty() && delete_pred->sub_predicates_v2().empty()) {
153
0
        for (const auto& condition_str : delete_pred->sub_predicates()) {
154
0
            auto* sub_pred = delete_pred->add_sub_predicates_v2();
155
0
            TCondition condition;
156
0
            static_cast<void>(parse_condition(condition_str, &condition));
157
0
            const auto& column = *DORIS_TRY(schema->column(condition.column_name));
158
0
            sub_pred->set_column_unique_id(column.unique_id());
159
0
            sub_pred->set_column_name(condition.column_name);
160
0
            sub_pred->set_op(condition.condition_op);
161
0
            sub_pred->set_cond_value(condition.condition_values[0]);
162
0
        }
163
0
    }
164
165
0
    auto* in_pred_list = delete_pred->mutable_in_predicates();
166
0
    for (auto& in_pred : *in_pred_list) {
167
0
        const auto& column = *DORIS_TRY(schema->column(in_pred.column_name()));
168
0
        in_pred.set_column_unique_id(column.unique_id());
169
0
    }
170
0
    return Status::OK();
171
0
}
172
173
bool DeleteHandler::is_condition_value_valid(const TabletColumn& column,
174
                                             const std::string& condition_op,
175
226
                                             const string& value_str) {
176
226
    if ("IS" == condition_op && ("NULL" == value_str || "NOT NULL" == value_str)) {
177
2
        return true;
178
2
    }
179
180
224
    FieldType field_type = column.type();
181
224
    switch (field_type) {
182
22
    case FieldType::OLAP_FIELD_TYPE_TINYINT:
183
22
        return valid_signed_number<int8_t>(value_str);
184
26
    case FieldType::OLAP_FIELD_TYPE_SMALLINT:
185
26
        return valid_signed_number<int16_t>(value_str);
186
108
    case FieldType::OLAP_FIELD_TYPE_INT:
187
108
        return valid_signed_number<int32_t>(value_str);
188
10
    case FieldType::OLAP_FIELD_TYPE_BIGINT:
189
10
        return valid_signed_number<int64_t>(value_str);
190
8
    case FieldType::OLAP_FIELD_TYPE_LARGEINT:
191
8
        return valid_signed_number<int128_t>(value_str);
192
0
    case FieldType::OLAP_FIELD_TYPE_UNSIGNED_TINYINT:
193
0
        return valid_unsigned_number<uint8_t>(value_str);
194
0
    case FieldType::OLAP_FIELD_TYPE_UNSIGNED_SMALLINT:
195
0
        return valid_unsigned_number<uint16_t>(value_str);
196
0
    case FieldType::OLAP_FIELD_TYPE_UNSIGNED_INT:
197
0
        return valid_unsigned_number<uint32_t>(value_str);
198
0
    case FieldType::OLAP_FIELD_TYPE_UNSIGNED_BIGINT:
199
0
        return valid_unsigned_number<uint64_t>(value_str);
200
14
    case FieldType::OLAP_FIELD_TYPE_DECIMAL:
201
14
        return valid_decimal(value_str, column.precision(), column.frac());
202
0
    case FieldType::OLAP_FIELD_TYPE_DECIMAL32:
203
0
        return valid_decimal(value_str, column.precision(), column.frac());
204
0
    case FieldType::OLAP_FIELD_TYPE_DECIMAL64:
205
0
        return valid_decimal(value_str, column.precision(), column.frac());
206
0
    case FieldType::OLAP_FIELD_TYPE_DECIMAL128I:
207
0
        return valid_decimal(value_str, column.precision(), column.frac());
208
0
    case FieldType::OLAP_FIELD_TYPE_DECIMAL256:
209
0
        return valid_decimal(value_str, column.precision(), column.frac());
210
6
    case FieldType::OLAP_FIELD_TYPE_CHAR:
211
14
    case FieldType::OLAP_FIELD_TYPE_VARCHAR:
212
14
        return value_str.size() <= column.length();
213
0
    case FieldType::OLAP_FIELD_TYPE_STRING:
214
0
        return value_str.size() <= config::string_type_length_soft_limit_bytes;
215
10
    case FieldType::OLAP_FIELD_TYPE_DATE:
216
22
    case FieldType::OLAP_FIELD_TYPE_DATETIME:
217
22
    case FieldType::OLAP_FIELD_TYPE_DATEV2:
218
22
    case FieldType::OLAP_FIELD_TYPE_DATETIMEV2:
219
22
        return valid_datetime(value_str, column.frac());
220
0
    case FieldType::OLAP_FIELD_TYPE_BOOL:
221
0
        return valid_bool(value_str);
222
0
    case FieldType::OLAP_FIELD_TYPE_IPV4:
223
0
        return valid_ipv4(value_str);
224
0
    case FieldType::OLAP_FIELD_TYPE_IPV6:
225
0
        return valid_ipv6(value_str);
226
0
    default:
227
0
        LOG(WARNING) << "unknown field type. [type=" << int(field_type) << "]";
228
224
    }
229
0
    return false;
230
224
}
231
232
226
Status DeleteHandler::check_condition_valid(const TabletSchema& schema, const TCondition& cond) {
233
    // Check whether the column exists
234
226
    int32_t field_index = schema.field_index(cond.column_name);
235
226
    if (field_index < 0) {
236
2
        return Status::Error<ErrorCode::INVALID_ARGUMENT>("field is not existent. [field_index={}]",
237
2
                                                          field_index);
238
2
    }
239
240
    // Delete condition should only applied on key columns or duplicate key table, and
241
    // the condition column type should not be float or double.
242
224
    const TabletColumn& column = schema.column(field_index);
243
244
224
    if (column.type() == FieldType::OLAP_FIELD_TYPE_DOUBLE ||
245
224
        column.type() == FieldType::OLAP_FIELD_TYPE_FLOAT) {
246
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>("data type is float or double.");
247
0
    }
248
249
    // Check operator and operands size are matched.
250
224
    if ("*=" != cond.condition_op && "!*=" != cond.condition_op &&
251
224
        cond.condition_values.size() != 1) {
252
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>("invalid condition value size. [size={}]",
253
0
                                                          cond.condition_values.size());
254
0
    }
255
256
    // Check each operand is valid
257
226
    for (const auto& condition_value : cond.condition_values) {
258
226
        if (!is_condition_value_valid(column, cond.condition_op, condition_value)) {
259
48
            return Status::Error<ErrorCode::INVALID_ARGUMENT>("invalid condition value. [value={}]",
260
48
                                                              condition_value);
261
48
        }
262
226
    }
263
264
176
    if (!cond.__isset.column_unique_id) {
265
176
        LOG(WARNING) << "column=" << cond.column_name
266
176
                     << " in predicate does not have uid, table id=" << schema.table_id();
267
        // TODO(tsy): make it fail here after FE forbidding hard-link-schema-change
268
176
        return Status::OK();
269
176
    }
270
0
    if (schema.field_index(cond.column_unique_id) == -1) {
271
0
        const auto& err_msg =
272
0
                fmt::format("column id does not exists in table={}, schema version={},",
273
0
                            schema.table_id(), schema.schema_version());
274
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>(err_msg);
275
0
    }
276
0
    if (!iequal(schema.column_by_uid(cond.column_unique_id).name(), cond.column_name)) {
277
0
        const auto& err_msg = fmt::format(
278
0
                "colum name={} does not belongs to column uid={}, which "
279
0
                "column name={}, "
280
0
                "delete_cond.column_name ={}",
281
0
                cond.column_name, cond.column_unique_id,
282
0
                schema.column_by_uid(cond.column_unique_id).name(), cond.column_name);
283
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>(err_msg);
284
0
    }
285
286
0
    return Status::OK();
287
0
}
288
289
180
Status DeleteHandler::parse_condition(const DeleteSubPredicatePB& sub_cond, TCondition* condition) {
290
180
    if (!sub_cond.has_column_name() || !sub_cond.has_op() || !sub_cond.has_cond_value()) {
291
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>(
292
0
                "fail to parse condition. condition={} {} {}", sub_cond.column_name(),
293
0
                sub_cond.op(), sub_cond.cond_value());
294
0
    }
295
180
    if (sub_cond.has_column_unique_id()) {
296
0
        condition->column_unique_id = sub_cond.column_unique_id();
297
0
    }
298
180
    condition->column_name = sub_cond.column_name();
299
180
    condition->condition_op = sub_cond.op();
300
180
    condition->condition_values.push_back(sub_cond.cond_value());
301
180
    return Status::OK();
302
180
}
303
304
// clang-format off
305
// Condition string format, the format is (column_name)(op)(value)
306
// eg: condition_str="c1 = 1597751948193618247 and length(source)<1;\n;\n"
307
// column_name: matches "c1", must include FeNameFormat.java COLUMN_NAME_REGEX
308
//              and compactible with any the lagacy
309
// operator: matches "="
310
// value: matches "1597751948193618247  and length(source)<1;\n;\n"
311
//
312
// For more info, see DeleteHandler::construct_sub_predicates
313
// FIXME(gavin): This is a tricky implementation, it should not be the final resolution, refactor it.
314
const char* const CONDITION_STR_PATTERN =
315
    // .----------------- column-name --------------------------.   .----------------------- operator ------------------------.   .------------ value ----------.
316
    R"(([_a-zA-Z@0-9\s/\p{L}][.a-zA-Z0-9_+-/?@#$%^&*"\s,:\p{L}]*)\s*((?:=)|(?:!=)|(?:>>)|(?:<<)|(?:>=)|(?:<=)|(?:\*=)|(?: IS ))\s*('((?:[\s\S]+)?)'|(?:[\s\S]+)?))";
317
    // '----------------- group 1 ------------------------------'   '--------------------- group 2 ---------------------------'   | '-- group 4--'              |
318
    //                                                                   match any of: = != >> << >= <= *= " IS "                 '----------- group 3 ---------'
319
    //                                                                                                                             match **ANY THING** without(4)
320
    //                                                                                                                             or with(3) single quote
321
// clang-format on
322
RE2 DELETE_HANDLER_REGEX(CONDITION_STR_PATTERN);
323
324
378
Status DeleteHandler::parse_condition(const std::string& condition_str, TCondition* condition) {
325
378
    std::string col_name, op, value, g4;
326
327
378
    bool matched = RE2::FullMatch(condition_str, DELETE_HANDLER_REGEX, &col_name, &op, &value,
328
378
                                  &g4); // exact match
329
330
378
    if (!matched) {
331
6
        return Status::InvalidArgument("fail to sub condition. condition={}", condition_str);
332
6
    }
333
334
372
    condition->column_name = col_name;
335
372
    condition->condition_op = op == " IS " ? "IS" : op;
336
    // match string with single quotes, a = b  or a = 'b'
337
372
    if (!g4.empty()) {
338
258
        condition->condition_values.push_back(g4);
339
258
    } else {
340
114
        condition->condition_values.push_back(value);
341
114
    }
342
372
    VLOG_NOTICE << "parsed condition_str: col_name={" << condition->column_name << "} op={"
343
0
                << condition->condition_op << "} val={" << condition->condition_values.back()
344
0
                << "}";
345
372
    return Status::OK();
346
378
}
347
348
template <typename SubPredType>
349
    requires(std::is_same_v<SubPredType, DeleteSubPredicatePB> or
350
             std::is_same_v<SubPredType, std::string>)
351
Status DeleteHandler::_parse_column_pred(TabletSchemaSPtr complete_schema,
352
                                         TabletSchemaSPtr delete_pred_related_schema,
353
                                         const RepeatedPtrField<SubPredType>& sub_pred_list,
354
322
                                         DeleteConditions* delete_conditions) {
355
344
    for (const auto& sub_predicate : sub_pred_list) {
356
344
        TCondition condition;
357
344
        RETURN_IF_ERROR(parse_condition(sub_predicate, &condition));
358
344
        int32_t col_unique_id = -1;
359
344
        if constexpr (std::is_same_v<SubPredType, DeleteSubPredicatePB>) {
360
180
            if (sub_predicate.has_column_unique_id()) [[likely]] {
361
0
                col_unique_id = sub_predicate.column_unique_id();
362
0
            }
363
180
        }
364
344
        if (col_unique_id < 0) {
365
344
            const auto& column =
366
344
                    *DORIS_TRY(delete_pred_related_schema->column(condition.column_name));
367
344
            col_unique_id = column.unique_id();
368
344
        }
369
344
        condition.__set_column_unique_id(col_unique_id);
370
344
        const auto& column = complete_schema->column_by_uid(col_unique_id);
371
344
        uint32_t index = complete_schema->field_index(col_unique_id);
372
344
        auto* predicate =
373
344
                parse_to_predicate(column, index, condition, _predicate_arena.get(), true);
374
344
        if (predicate != nullptr) {
375
344
            delete_conditions->column_predicate_vec.push_back(predicate);
376
344
        }
377
344
    }
378
322
    return Status::OK();
379
322
}
_ZN5doris13DeleteHandler18_parse_column_predINS_20DeleteSubPredicatePBEEENS_6StatusESt10shared_ptrINS_12TabletSchemaEES6_RKN6google8protobuf16RepeatedPtrFieldIT_EEPNS_16DeleteConditionsE
Line
Count
Source
354
170
                                         DeleteConditions* delete_conditions) {
355
180
    for (const auto& sub_predicate : sub_pred_list) {
356
180
        TCondition condition;
357
180
        RETURN_IF_ERROR(parse_condition(sub_predicate, &condition));
358
180
        int32_t col_unique_id = -1;
359
180
        if constexpr (std::is_same_v<SubPredType, DeleteSubPredicatePB>) {
360
180
            if (sub_predicate.has_column_unique_id()) [[likely]] {
361
0
                col_unique_id = sub_predicate.column_unique_id();
362
0
            }
363
180
        }
364
180
        if (col_unique_id < 0) {
365
180
            const auto& column =
366
180
                    *DORIS_TRY(delete_pred_related_schema->column(condition.column_name));
367
180
            col_unique_id = column.unique_id();
368
180
        }
369
180
        condition.__set_column_unique_id(col_unique_id);
370
180
        const auto& column = complete_schema->column_by_uid(col_unique_id);
371
180
        uint32_t index = complete_schema->field_index(col_unique_id);
372
180
        auto* predicate =
373
180
                parse_to_predicate(column, index, condition, _predicate_arena.get(), true);
374
180
        if (predicate != nullptr) {
375
180
            delete_conditions->column_predicate_vec.push_back(predicate);
376
180
        }
377
180
    }
378
170
    return Status::OK();
379
170
}
_ZN5doris13DeleteHandler18_parse_column_predINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEENS_6StatusESt10shared_ptrINS_12TabletSchemaEESB_RKN6google8protobuf16RepeatedPtrFieldIT_EEPNS_16DeleteConditionsE
Line
Count
Source
354
152
                                         DeleteConditions* delete_conditions) {
355
164
    for (const auto& sub_predicate : sub_pred_list) {
356
164
        TCondition condition;
357
164
        RETURN_IF_ERROR(parse_condition(sub_predicate, &condition));
358
164
        int32_t col_unique_id = -1;
359
164
        if constexpr (std::is_same_v<SubPredType, DeleteSubPredicatePB>) {
360
164
            if (sub_predicate.has_column_unique_id()) [[likely]] {
361
164
                col_unique_id = sub_predicate.column_unique_id();
362
164
            }
363
164
        }
364
164
        if (col_unique_id < 0) {
365
164
            const auto& column =
366
164
                    *DORIS_TRY(delete_pred_related_schema->column(condition.column_name));
367
164
            col_unique_id = column.unique_id();
368
164
        }
369
164
        condition.__set_column_unique_id(col_unique_id);
370
164
        const auto& column = complete_schema->column_by_uid(col_unique_id);
371
164
        uint32_t index = complete_schema->field_index(col_unique_id);
372
164
        auto* predicate =
373
164
                parse_to_predicate(column, index, condition, _predicate_arena.get(), true);
374
164
        if (predicate != nullptr) {
375
164
            delete_conditions->column_predicate_vec.push_back(predicate);
376
164
        }
377
164
    }
378
152
    return Status::OK();
379
152
}
380
381
template Status DeleteHandler::_parse_column_pred<DeleteSubPredicatePB>(
382
        TabletSchemaSPtr complete_schema, TabletSchemaSPtr delete_pred_related_schema,
383
        const ::google::protobuf::RepeatedPtrField<DeleteSubPredicatePB>& sub_pred_list,
384
        DeleteConditions* delete_conditions);
385
386
template Status DeleteHandler::_parse_column_pred<std::string>(
387
        TabletSchemaSPtr complete_schema, TabletSchemaSPtr delete_pred_related_schema,
388
        const ::google::protobuf::RepeatedPtrField<std::string>& sub_pred_list,
389
        DeleteConditions* delete_conditions);
390
391
Status DeleteHandler::init(TabletSchemaSPtr tablet_schema,
392
718
                           const std::vector<RowsetMetaSharedPtr>& delete_preds, int64_t version) {
393
718
    DCHECK(!_is_inited) << "reinitialize delete handler.";
394
718
    DCHECK(version >= 0) << "invalid parameters. version=" << version;
395
718
    _predicate_arena = std::make_unique<vectorized::Arena>();
396
397
718
    for (const auto& delete_pred : delete_preds) {
398
        // Skip the delete condition with large version
399
322
        if (delete_pred->version().first > version) {
400
0
            continue;
401
0
        }
402
        // Need the tablet schema at the delete condition to parse the accurate column
403
322
        const auto& delete_pred_related_schema = delete_pred->tablet_schema();
404
322
        const auto& delete_condition = delete_pred->delete_predicate();
405
322
        DeleteConditions temp;
406
322
        temp.filter_version = delete_pred->version().first;
407
322
        if (!delete_condition.sub_predicates_v2().empty()) {
408
170
            RETURN_IF_ERROR(_parse_column_pred(tablet_schema, delete_pred_related_schema,
409
170
                                               delete_condition.sub_predicates_v2(), &temp));
410
170
        } else {
411
            // make it compatible with the former versions
412
152
            RETURN_IF_ERROR(_parse_column_pred(tablet_schema, delete_pred_related_schema,
413
152
                                               delete_condition.sub_predicates(), &temp));
414
152
        }
415
322
        for (const auto& in_predicate : delete_condition.in_predicates()) {
416
0
            TCondition condition;
417
0
            condition.__set_column_name(in_predicate.column_name());
418
419
0
            int32_t col_unique_id = -1;
420
0
            if (in_predicate.has_column_unique_id()) {
421
0
                col_unique_id = in_predicate.column_unique_id();
422
0
            } else {
423
                // if upgrade from version 2.0.x, column_unique_id maybe not set
424
0
                const auto& pre_column =
425
0
                        *DORIS_TRY(delete_pred_related_schema->column(condition.column_name));
426
0
                col_unique_id = pre_column.unique_id();
427
0
            }
428
0
            if (col_unique_id == -1) {
429
0
                return Status::Error<ErrorCode::DELETE_INVALID_CONDITION>(
430
0
                        "cannot get column_unique_id for column {}", condition.column_name);
431
0
            }
432
0
            condition.__set_column_unique_id(col_unique_id);
433
434
0
            if (in_predicate.is_not_in()) {
435
0
                condition.__set_condition_op("!*=");
436
0
            } else {
437
0
                condition.__set_condition_op("*=");
438
0
            }
439
0
            for (const auto& value : in_predicate.values()) {
440
0
                condition.condition_values.push_back(value);
441
0
            }
442
0
            const auto& column = tablet_schema->column_by_uid(col_unique_id);
443
0
            uint32_t index = tablet_schema->field_index(col_unique_id);
444
0
            temp.column_predicate_vec.push_back(
445
0
                    parse_to_predicate(column, index, condition, _predicate_arena.get(), true));
446
0
        }
447
448
322
        _del_conds.emplace_back(std::move(temp));
449
322
    }
450
451
718
    _is_inited = true;
452
453
718
    return Status::OK();
454
718
}
455
456
720
DeleteHandler::~DeleteHandler() {
457
720
    if (!_is_inited) {
458
2
        return;
459
2
    }
460
461
718
    for (auto& cond : _del_conds) {
462
344
        for (const auto* pred : cond.column_predicate_vec) {
463
344
            delete pred;
464
344
        }
465
322
    }
466
467
718
    _del_conds.clear();
468
718
    _is_inited = false;
469
718
}
470
471
void DeleteHandler::get_delete_conditions_after_version(
472
        int64_t version, AndBlockColumnPredicate* and_block_column_predicate_ptr,
473
        std::unordered_map<int32_t, std::vector<const ColumnPredicate*>>*
474
2.10k
                del_predicates_for_zone_map) const {
475
2.10k
    for (const auto& del_cond : _del_conds) {
476
1.11k
        if (del_cond.filter_version > version) {
477
            // now, only query support delete column predicate operator
478
812
            if (!del_cond.column_predicate_vec.empty()) {
479
812
                if (del_cond.column_predicate_vec.size() == 1) {
480
812
                    auto single_column_block_predicate = SingleColumnBlockPredicate::create_unique(
481
812
                            del_cond.column_predicate_vec[0]);
482
812
                    and_block_column_predicate_ptr->add_column_predicate(
483
812
                            std::move(single_column_block_predicate));
484
812
                    if (del_predicates_for_zone_map->count(
485
812
                                del_cond.column_predicate_vec[0]->column_id()) < 1) {
486
812
                        del_predicates_for_zone_map->insert(
487
812
                                {del_cond.column_predicate_vec[0]->column_id(),
488
812
                                 std::vector<const ColumnPredicate*> {}});
489
812
                    }
490
812
                    (*del_predicates_for_zone_map)[del_cond.column_predicate_vec[0]->column_id()]
491
812
                            .push_back(del_cond.column_predicate_vec[0]);
492
812
                } else {
493
0
                    auto or_column_predicate = OrBlockColumnPredicate::create_unique();
494
495
                    // build or_column_predicate
496
                    // when delete from where a = 1 and b = 2, we can not use del_predicates_for_zone_map to filter zone page,
497
                    // so here do not put predicate to del_predicates_for_zone_map,
498
                    // refer #17145 for more details.
499
                    // // TODO: need refactor design and code to use more version delete and more column delete to filter zone page.
500
0
                    std::for_each(del_cond.column_predicate_vec.cbegin(),
501
0
                                  del_cond.column_predicate_vec.cend(),
502
0
                                  [&or_column_predicate](const ColumnPredicate* predicate) {
503
0
                                      or_column_predicate->add_column_predicate(
504
0
                                              SingleColumnBlockPredicate::create_unique(predicate));
505
0
                                  });
506
0
                    and_block_column_predicate_ptr->add_column_predicate(
507
0
                            std::move(or_column_predicate));
508
0
                }
509
812
            }
510
812
        }
511
1.11k
    }
512
2.10k
}
513
514
} // namespace doris