Coverage Report

Created: 2026-03-18 19:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/delete/delete_handler.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/delete/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 "core/data_type_serde/data_type_serde.h"
31
#include "storage/olap_common.h"
32
#include "storage/predicate/block_column_predicate.h"
33
#include "storage/predicate/predicate_creator.h"
34
#include "storage/tablet/tablet_schema.h"
35
#include "storage/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
// Parses a string value into a Field using the serde's from_fe_string, then builds
47
// a HybridSetBase for IN/NOT_IN predicates.
48
// The type-dispatch via switch/case is still needed because build_set<PType>() and
49
// HybridSet::insert(const void*) require compile-time PrimitiveType, and Field::get<PType>()
50
// must be invoked with the correct type to extract the underlying CppType value.
51
template <PrimitiveType PType>
52
936
void insert_field_to_set(const Field& field, HybridSetBase* set) {
53
936
    if constexpr (is_string_type(PType)) {
54
        // StringSet::insert expects const StringRef*, so we must construct a StringRef
55
        // from the std::string returned by Field::get<>.
56
201
        const auto& tmp = field.get<PType>();
57
201
        StringRef ref(tmp.data(), tmp.size());
58
201
        set->insert(reinterpret_cast<const void*>(&ref));
59
735
    } else {
60
735
        auto tmp = field.get<PType>();
61
735
        set->insert(reinterpret_cast<const void*>(&tmp));
62
735
    }
63
936
}
_ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE3EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Line
Count
Source
52
4
void insert_field_to_set(const Field& field, HybridSetBase* set) {
53
    if constexpr (is_string_type(PType)) {
54
        // StringSet::insert expects const StringRef*, so we must construct a StringRef
55
        // from the std::string returned by Field::get<>.
56
        const auto& tmp = field.get<PType>();
57
        StringRef ref(tmp.data(), tmp.size());
58
        set->insert(reinterpret_cast<const void*>(&ref));
59
4
    } else {
60
4
        auto tmp = field.get<PType>();
61
4
        set->insert(reinterpret_cast<const void*>(&tmp));
62
4
    }
63
4
}
_ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE4EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Line
Count
Source
52
2
void insert_field_to_set(const Field& field, HybridSetBase* set) {
53
    if constexpr (is_string_type(PType)) {
54
        // StringSet::insert expects const StringRef*, so we must construct a StringRef
55
        // from the std::string returned by Field::get<>.
56
        const auto& tmp = field.get<PType>();
57
        StringRef ref(tmp.data(), tmp.size());
58
        set->insert(reinterpret_cast<const void*>(&ref));
59
2
    } else {
60
2
        auto tmp = field.get<PType>();
61
2
        set->insert(reinterpret_cast<const void*>(&tmp));
62
2
    }
63
2
}
_ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE5EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Line
Count
Source
52
245
void insert_field_to_set(const Field& field, HybridSetBase* set) {
53
    if constexpr (is_string_type(PType)) {
54
        // StringSet::insert expects const StringRef*, so we must construct a StringRef
55
        // from the std::string returned by Field::get<>.
56
        const auto& tmp = field.get<PType>();
57
        StringRef ref(tmp.data(), tmp.size());
58
        set->insert(reinterpret_cast<const void*>(&ref));
59
245
    } else {
60
245
        auto tmp = field.get<PType>();
61
245
        set->insert(reinterpret_cast<const void*>(&tmp));
62
245
    }
63
245
}
_ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE6EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Line
Count
Source
52
17
void insert_field_to_set(const Field& field, HybridSetBase* set) {
53
    if constexpr (is_string_type(PType)) {
54
        // StringSet::insert expects const StringRef*, so we must construct a StringRef
55
        // from the std::string returned by Field::get<>.
56
        const auto& tmp = field.get<PType>();
57
        StringRef ref(tmp.data(), tmp.size());
58
        set->insert(reinterpret_cast<const void*>(&ref));
59
17
    } else {
60
17
        auto tmp = field.get<PType>();
61
17
        set->insert(reinterpret_cast<const void*>(&tmp));
62
17
    }
63
17
}
Unexecuted instantiation: _ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE7EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Unexecuted instantiation: _ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE8EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Unexecuted instantiation: _ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE9EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Unexecuted instantiation: _ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE11EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Unexecuted instantiation: _ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE12EEEvRKNS_5FieldEPNS_13HybridSetBaseE
_ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE25EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Line
Count
Source
52
2
void insert_field_to_set(const Field& field, HybridSetBase* set) {
53
    if constexpr (is_string_type(PType)) {
54
        // StringSet::insert expects const StringRef*, so we must construct a StringRef
55
        // from the std::string returned by Field::get<>.
56
        const auto& tmp = field.get<PType>();
57
        StringRef ref(tmp.data(), tmp.size());
58
        set->insert(reinterpret_cast<const void*>(&ref));
59
2
    } else {
60
2
        auto tmp = field.get<PType>();
61
2
        set->insert(reinterpret_cast<const void*>(&tmp));
62
2
    }
63
2
}
_ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE26EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Line
Count
Source
52
2
void insert_field_to_set(const Field& field, HybridSetBase* set) {
53
    if constexpr (is_string_type(PType)) {
54
        // StringSet::insert expects const StringRef*, so we must construct a StringRef
55
        // from the std::string returned by Field::get<>.
56
        const auto& tmp = field.get<PType>();
57
        StringRef ref(tmp.data(), tmp.size());
58
        set->insert(reinterpret_cast<const void*>(&ref));
59
2
    } else {
60
2
        auto tmp = field.get<PType>();
61
2
        set->insert(reinterpret_cast<const void*>(&tmp));
62
2
    }
63
2
}
_ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE42EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Line
Count
Source
52
453
void insert_field_to_set(const Field& field, HybridSetBase* set) {
53
    if constexpr (is_string_type(PType)) {
54
        // StringSet::insert expects const StringRef*, so we must construct a StringRef
55
        // from the std::string returned by Field::get<>.
56
        const auto& tmp = field.get<PType>();
57
        StringRef ref(tmp.data(), tmp.size());
58
        set->insert(reinterpret_cast<const void*>(&ref));
59
453
    } else {
60
453
        auto tmp = field.get<PType>();
61
453
        set->insert(reinterpret_cast<const void*>(&tmp));
62
453
    }
63
453
}
Unexecuted instantiation: _ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE2EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Unexecuted instantiation: _ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE36EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Unexecuted instantiation: _ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE37EEEvRKNS_5FieldEPNS_13HybridSetBaseE
_ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE20EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Line
Count
Source
52
8
void insert_field_to_set(const Field& field, HybridSetBase* set) {
53
    if constexpr (is_string_type(PType)) {
54
        // StringSet::insert expects const StringRef*, so we must construct a StringRef
55
        // from the std::string returned by Field::get<>.
56
        const auto& tmp = field.get<PType>();
57
        StringRef ref(tmp.data(), tmp.size());
58
        set->insert(reinterpret_cast<const void*>(&ref));
59
8
    } else {
60
8
        auto tmp = field.get<PType>();
61
8
        set->insert(reinterpret_cast<const void*>(&tmp));
62
8
    }
63
8
}
Unexecuted instantiation: _ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE28EEEvRKNS_5FieldEPNS_13HybridSetBaseE
_ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE29EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Line
Count
Source
52
2
void insert_field_to_set(const Field& field, HybridSetBase* set) {
53
    if constexpr (is_string_type(PType)) {
54
        // StringSet::insert expects const StringRef*, so we must construct a StringRef
55
        // from the std::string returned by Field::get<>.
56
        const auto& tmp = field.get<PType>();
57
        StringRef ref(tmp.data(), tmp.size());
58
        set->insert(reinterpret_cast<const void*>(&ref));
59
2
    } else {
60
2
        auto tmp = field.get<PType>();
61
2
        set->insert(reinterpret_cast<const void*>(&tmp));
62
2
    }
63
2
}
Unexecuted instantiation: _ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE30EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Unexecuted instantiation: _ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE35EEEvRKNS_5FieldEPNS_13HybridSetBaseE
_ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE15EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Line
Count
Source
52
4
void insert_field_to_set(const Field& field, HybridSetBase* set) {
53
4
    if constexpr (is_string_type(PType)) {
54
        // StringSet::insert expects const StringRef*, so we must construct a StringRef
55
        // from the std::string returned by Field::get<>.
56
4
        const auto& tmp = field.get<PType>();
57
4
        StringRef ref(tmp.data(), tmp.size());
58
4
        set->insert(reinterpret_cast<const void*>(&ref));
59
    } else {
60
        auto tmp = field.get<PType>();
61
        set->insert(reinterpret_cast<const void*>(&tmp));
62
    }
63
4
}
_ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE10EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Line
Count
Source
52
195
void insert_field_to_set(const Field& field, HybridSetBase* set) {
53
195
    if constexpr (is_string_type(PType)) {
54
        // StringSet::insert expects const StringRef*, so we must construct a StringRef
55
        // from the std::string returned by Field::get<>.
56
195
        const auto& tmp = field.get<PType>();
57
195
        StringRef ref(tmp.data(), tmp.size());
58
195
        set->insert(reinterpret_cast<const void*>(&ref));
59
    } else {
60
        auto tmp = field.get<PType>();
61
        set->insert(reinterpret_cast<const void*>(&tmp));
62
    }
63
195
}
_ZN5doris19insert_field_to_setILNS_13PrimitiveTypeE23EEEvRKNS_5FieldEPNS_13HybridSetBaseE
Line
Count
Source
52
2
void insert_field_to_set(const Field& field, HybridSetBase* set) {
53
2
    if constexpr (is_string_type(PType)) {
54
        // StringSet::insert expects const StringRef*, so we must construct a StringRef
55
        // from the std::string returned by Field::get<>.
56
2
        const auto& tmp = field.get<PType>();
57
2
        StringRef ref(tmp.data(), tmp.size());
58
2
        set->insert(reinterpret_cast<const void*>(&ref));
59
    } else {
60
        auto tmp = field.get<PType>();
61
        set->insert(reinterpret_cast<const void*>(&tmp));
62
    }
63
2
}
64
65
#define FROM_FE_STRING_CASE(PType)                            \
66
292
    case PType: {                                             \
67
292
        set = build_set<PType>();                             \
68
936
        for (const auto& s : str) {                           \
69
936
            Field field;                                      \
70
936
            RETURN_IF_ERROR(serde->from_fe_string(s, field)); \
71
936
            insert_field_to_set<PType>(field, set.get());     \
72
936
        }                                                     \
73
292
        return Status::OK();                                  \
74
292
    }
75
Status convert(const DataTypePtr& data_type, const std::list<std::string>& str,
76
292
               std::shared_ptr<HybridSetBase>& set) {
77
292
    auto serde = data_type->get_serde();
78
292
    switch (data_type->get_primitive_type()) {
79
1
        FROM_FE_STRING_CASE(TYPE_TINYINT);
80
1
        FROM_FE_STRING_CASE(TYPE_SMALLINT);
81
87
        FROM_FE_STRING_CASE(TYPE_INT);
82
6
        FROM_FE_STRING_CASE(TYPE_BIGINT);
83
0
        FROM_FE_STRING_CASE(TYPE_LARGEINT);
84
0
        FROM_FE_STRING_CASE(TYPE_FLOAT);
85
0
        FROM_FE_STRING_CASE(TYPE_DOUBLE);
86
0
        FROM_FE_STRING_CASE(TYPE_DATE);
87
0
        FROM_FE_STRING_CASE(TYPE_DATETIME);
88
1
        FROM_FE_STRING_CASE(TYPE_DATEV2);
89
1
        FROM_FE_STRING_CASE(TYPE_DATETIMEV2);
90
129
        FROM_FE_STRING_CASE(TYPE_TIMESTAMPTZ);
91
0
        FROM_FE_STRING_CASE(TYPE_BOOLEAN);
92
0
        FROM_FE_STRING_CASE(TYPE_IPV4);
93
0
        FROM_FE_STRING_CASE(TYPE_IPV6);
94
2
        FROM_FE_STRING_CASE(TYPE_DECIMALV2);
95
0
        FROM_FE_STRING_CASE(TYPE_DECIMAL32);
96
1
        FROM_FE_STRING_CASE(TYPE_DECIMAL64);
97
0
        FROM_FE_STRING_CASE(TYPE_DECIMAL128I);
98
0
        FROM_FE_STRING_CASE(TYPE_DECIMAL256);
99
2
        FROM_FE_STRING_CASE(TYPE_CHAR);
100
60
        FROM_FE_STRING_CASE(TYPE_VARCHAR);
101
1
        FROM_FE_STRING_CASE(TYPE_STRING);
102
0
    default:
103
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>(
104
0
                "unsupported data type in delete handler. type={}",
105
0
                type_to_string(data_type->get_primitive_type()));
106
292
    }
107
0
    return Status::OK();
108
292
}
109
#undef FROM_FE_STRING_CASE
110
111
// Parses a single condition value string into a Field and creates a comparison predicate.
112
// Uses serde->from_fe_string to do the parsing, which handles all type-specific
113
// conversions (including decimal scale, etc.).
114
// For CHAR type, the value is padded with '\0' to the declared column length, consistent
115
// with the IN list path in convert() above.
116
// For VARCHAR/STRING, the Field is created directly from the raw string.
117
Status parse_to_predicate(const uint32_t index, const std::string col_name, const DataTypePtr& type,
118
                          DeleteHandler::ConditionParseResult& res, Arena& arena,
119
7.89k
                          std::shared_ptr<ColumnPredicate>& predicate) {
120
7.89k
    DCHECK_EQ(res.value_str.size(), 1);
121
7.89k
    if (res.condition_op == PredicateType::IS_NULL ||
122
7.89k
        res.condition_op == PredicateType::IS_NOT_NULL) {
123
582
        predicate = NullPredicate::create_shared(index, col_name,
124
582
                                                 res.condition_op == PredicateType::IS_NOT_NULL,
125
582
                                                 type->get_primitive_type());
126
582
        return Status::OK();
127
582
    }
128
129
7.31k
    Field v;
130
7.31k
    if (type->get_primitive_type() == TYPE_CHAR) {
131
        // CHAR type: create Field and pad with '\0' to the declared column length,
132
        // consistent with IN list path (convert() above) and create_comparison_predicate.
133
4
        const auto& str = res.value_str.front();
134
4
        auto char_len = cast_set<size_t>(
135
4
                assert_cast<const DataTypeString*>(remove_nullable(type).get())->len());
136
4
        auto target = std::max(char_len, str.size());
137
4
        if (target > str.size()) {
138
0
            std::string padded(target, '\0');
139
0
            memcpy(padded.data(), str.data(), str.size());
140
0
            v = Field::create_field<TYPE_CHAR>(std::move(padded));
141
4
        } else {
142
4
            v = Field::create_field<TYPE_CHAR>(str);
143
4
        }
144
7.31k
    } else if (is_string_type(type->get_primitive_type())) {
145
        // VARCHAR/STRING: create Field directly from the raw string, no padding needed.
146
678
        v = Field::create_field<TYPE_STRING>(res.value_str.front());
147
6.63k
    } else {
148
6.63k
        auto serde = type->get_serde();
149
6.63k
        RETURN_IF_ERROR(serde->from_fe_string(res.value_str.front(), v));
150
6.63k
    }
151
152
7.30k
    switch (res.condition_op) {
153
3.86k
    case PredicateType::EQ:
154
3.86k
        predicate = create_comparison_predicate<PredicateType::EQ>(index, col_name, type, v, true);
155
3.86k
        return Status::OK();
156
947
    case PredicateType::NE:
157
947
        predicate = create_comparison_predicate<PredicateType::NE>(index, col_name, type, v, true);
158
947
        return Status::OK();
159
554
    case PredicateType::GT:
160
554
        predicate = create_comparison_predicate<PredicateType::GT>(index, col_name, type, v, true);
161
554
        return Status::OK();
162
421
    case PredicateType::GE:
163
421
        predicate = create_comparison_predicate<PredicateType::GE>(index, col_name, type, v, true);
164
421
        return Status::OK();
165
819
    case PredicateType::LT:
166
819
        predicate = create_comparison_predicate<PredicateType::LT>(index, col_name, type, v, true);
167
819
        return Status::OK();
168
722
    case PredicateType::LE:
169
722
        predicate = create_comparison_predicate<PredicateType::LE>(index, col_name, type, v, true);
170
722
        return Status::OK();
171
0
    default:
172
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>("invalid condition operator. operator={}",
173
0
                                                          type_to_op_str(res.condition_op));
174
7.30k
    }
175
7.30k
}
176
177
Status parse_to_in_predicate(const uint32_t index, const std::string& col_name,
178
                             const DataTypePtr& type, DeleteHandler::ConditionParseResult& res,
179
291
                             Arena& arena, std::shared_ptr<ColumnPredicate>& predicate) {
180
291
    DCHECK_GT(res.value_str.size(), 1);
181
291
    switch (res.condition_op) {
182
222
    case PredicateType::IN_LIST: {
183
222
        std::shared_ptr<HybridSetBase> set;
184
222
        RETURN_IF_ERROR(convert(type, res.value_str, set));
185
222
        predicate =
186
222
                create_in_list_predicate<PredicateType::IN_LIST>(index, col_name, type, set, true);
187
222
        break;
188
222
    }
189
70
    case PredicateType::NOT_IN_LIST: {
190
70
        std::shared_ptr<HybridSetBase> set;
191
70
        RETURN_IF_ERROR(convert(type, res.value_str, set));
192
70
        predicate = create_in_list_predicate<PredicateType::NOT_IN_LIST>(index, col_name, type, set,
193
70
                                                                         true);
194
70
        break;
195
70
    }
196
0
    default:
197
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>("invalid condition operator. operator={}",
198
0
                                                          type_to_op_str(res.condition_op));
199
291
    }
200
293
    return Status::OK();
201
291
}
202
203
// construct sub condition from TCondition
204
3.16k
std::string construct_sub_predicate(const TCondition& condition) {
205
3.16k
    string op = condition.condition_op;
206
3.16k
    if (op == "<") {
207
312
        op += "<";
208
2.85k
    } else if (op == ">") {
209
233
        op += ">";
210
233
    }
211
3.16k
    string condition_str;
212
3.16k
    if ("IS" == op) {
213
        // ATTN: tricky! Surround IS with spaces to make it "special"
214
406
        condition_str = condition.column_name + " IS " + condition.condition_values[0];
215
2.76k
    } else { // multi-elements IN expr has been processed with InPredicatePB
216
2.76k
        if (op == "*=") {
217
2
            op = "=";
218
2.75k
        } else if (op == "!*=") {
219
2
            op = "!=";
220
2
        }
221
2.76k
        condition_str = condition.column_name + op + "'" + condition.condition_values[0] + "'";
222
2.76k
    }
223
3.16k
    return condition_str;
224
3.16k
}
225
226
// make operators from FE adaptive to BE
227
3.11k
std::string trans_op(const std::string& opt) {
228
3.11k
    std::string op = string(opt);
229
3.11k
    if (op == "<") {
230
309
        op += "<";
231
2.80k
    } else if (op == ">") {
232
227
        op += ">";
233
227
    }
234
3.11k
    if ("IS" != op) {
235
2.76k
        if (op == "*=") {
236
2
            op = "=";
237
2.76k
        } else if (op == "!*=") {
238
2
            op = "!=";
239
2
        }
240
2.76k
    }
241
3.11k
    return op;
242
3.11k
}
243
244
Status DeleteHandler::generate_delete_predicate(const TabletSchema& schema,
245
                                                const std::vector<TCondition>& conditions,
246
3.30k
                                                DeletePredicatePB* del_pred) {
247
3.30k
    DBUG_EXECUTE_IF("DeleteHandler::generate_delete_predicate.inject_failure", {
248
3.30k
        return Status::Error<false>(dp->param<int>("error_code"),
249
3.30k
                                    dp->param<std::string>("error_msg"));
250
3.30k
    })
251
3.30k
    if (conditions.empty()) {
252
1
        return Status::Error<ErrorCode::INVALID_ARGUMENT>(
253
1
                "invalid parameters for store_cond. condition_size={}", conditions.size());
254
1
    }
255
256
    // Check whether the delete condition meets the requirements
257
3.42k
    for (const TCondition& condition : conditions) {
258
3.42k
        RETURN_IF_ERROR(check_condition_valid(schema, condition));
259
3.42k
    }
260
261
    // Store delete condition
262
3.39k
    for (const TCondition& condition : conditions) {
263
3.39k
        if (condition.condition_values.size() > 1) {
264
194
            InPredicatePB* in_pred = del_pred->add_in_predicates();
265
194
            if (condition.__isset.column_unique_id) {
266
190
                in_pred->set_column_unique_id(condition.column_unique_id);
267
190
            }
268
194
            in_pred->set_column_name(condition.column_name);
269
194
            bool is_not_in = condition.condition_op == "!*=";
270
194
            in_pred->set_is_not_in(is_not_in);
271
621
            for (const auto& condition_value : condition.condition_values) {
272
621
                in_pred->add_values(condition_value);
273
621
            }
274
275
194
            LOG(INFO) << "store one sub-delete condition. condition name=" << in_pred->column_name()
276
194
                      << "condition size=" << in_pred->values().size();
277
3.20k
        } else {
278
            // write sub predicate v1 for compactbility
279
3.20k
            std::string condition_str = construct_sub_predicate(condition);
280
3.20k
            VLOG_NOTICE << __PRETTY_FUNCTION__ << " condition_str: " << condition_str;
281
3.20k
            del_pred->add_sub_predicates(condition_str);
282
3.20k
            DeleteSubPredicatePB* sub_predicate = del_pred->add_sub_predicates_v2();
283
3.20k
            if (condition.__isset.column_unique_id) {
284
                // only light schema change capable table set this field
285
3.09k
                sub_predicate->set_column_unique_id(condition.column_unique_id);
286
3.09k
            } else {
287
106
                try {
288
106
                    [[maybe_unused]] auto parsed_cond = parse_condition(condition_str);
289
106
                } catch (const Exception& e) {
290
0
                    return Status::Error<ErrorCode::INVALID_ARGUMENT>(
291
0
                            "failed to parse condition_str, condition={}, error={}",
292
0
                            ThriftDebugString(condition), e.to_string());
293
0
                }
294
106
            }
295
296
3.19k
            sub_predicate->set_column_name(condition.column_name);
297
3.19k
            sub_predicate->set_op(trans_op(condition.condition_op));
298
3.19k
            sub_predicate->set_cond_value(condition.condition_values[0]);
299
3.19k
            LOG(INFO) << "store one sub-delete condition. condition="
300
3.19k
                      << fmt::format(" {} {} {}", condition.column_name, condition.condition_op,
301
3.19k
                                     condition.condition_values[0]);
302
3.19k
        }
303
3.39k
    }
304
3.26k
    del_pred->set_version(-1);
305
306
3.26k
    return Status::OK();
307
3.27k
}
308
309
Status DeleteHandler::convert_to_sub_pred_v2(DeletePredicatePB* delete_pred,
310
256
                                             TabletSchemaSPtr schema) {
311
256
    if (!delete_pred->sub_predicates().empty() && delete_pred->sub_predicates_v2().empty()) {
312
0
        for (const auto& condition_str : delete_pred->sub_predicates()) {
313
0
            auto* sub_pred = delete_pred->add_sub_predicates_v2();
314
0
            auto condition = parse_condition(condition_str);
315
0
            const auto& column = *DORIS_TRY(schema->column(condition.column_name));
316
0
            sub_pred->set_column_unique_id(column.unique_id());
317
0
            sub_pred->set_column_name(condition.column_name);
318
0
            sub_pred->set_op(type_to_op_str(condition.condition_op));
319
0
            sub_pred->set_cond_value(condition.value_str.front());
320
0
        }
321
0
    }
322
323
256
    auto* in_pred_list = delete_pred->mutable_in_predicates();
324
256
    for (auto& in_pred : *in_pred_list) {
325
256
        const auto& column = *DORIS_TRY(schema->column(in_pred.column_name()));
326
256
        in_pred.set_column_unique_id(column.unique_id());
327
256
    }
328
256
    return Status::OK();
329
256
}
330
331
bool DeleteHandler::is_condition_value_valid(const TabletColumn& column,
332
                                             const std::string& condition_op,
333
3.81k
                                             const string& value_str) {
334
3.81k
    if ("IS" == condition_op && ("NULL" == value_str || "NOT NULL" == value_str)) {
335
412
        return true;
336
412
    }
337
338
3.39k
    FieldType field_type = column.type();
339
3.39k
    switch (field_type) {
340
25
    case FieldType::OLAP_FIELD_TYPE_TINYINT:
341
25
        return valid_signed_number<int8_t>(value_str);
342
17
    case FieldType::OLAP_FIELD_TYPE_SMALLINT:
343
17
        return valid_signed_number<int16_t>(value_str);
344
807
    case FieldType::OLAP_FIELD_TYPE_INT:
345
807
        return valid_signed_number<int32_t>(value_str);
346
58
    case FieldType::OLAP_FIELD_TYPE_BIGINT:
347
58
        return valid_signed_number<int64_t>(value_str);
348
161
    case FieldType::OLAP_FIELD_TYPE_LARGEINT:
349
161
        return valid_signed_number<int128_t>(value_str);
350
0
    case FieldType::OLAP_FIELD_TYPE_UNSIGNED_TINYINT:
351
0
        return valid_unsigned_number<uint8_t>(value_str);
352
0
    case FieldType::OLAP_FIELD_TYPE_UNSIGNED_SMALLINT:
353
0
        return valid_unsigned_number<uint16_t>(value_str);
354
0
    case FieldType::OLAP_FIELD_TYPE_UNSIGNED_INT:
355
0
        return valid_unsigned_number<uint32_t>(value_str);
356
0
    case FieldType::OLAP_FIELD_TYPE_UNSIGNED_BIGINT:
357
0
        return valid_unsigned_number<uint64_t>(value_str);
358
15
    case FieldType::OLAP_FIELD_TYPE_DECIMAL:
359
15
        return valid_decimal(value_str, column.precision(), column.frac());
360
8
    case FieldType::OLAP_FIELD_TYPE_DECIMAL32:
361
8
        return valid_decimal(value_str, column.precision(), column.frac());
362
10
    case FieldType::OLAP_FIELD_TYPE_DECIMAL64:
363
10
        return valid_decimal(value_str, column.precision(), column.frac());
364
0
    case FieldType::OLAP_FIELD_TYPE_DECIMAL128I:
365
0
        return valid_decimal(value_str, column.precision(), column.frac());
366
1
    case FieldType::OLAP_FIELD_TYPE_DECIMAL256:
367
1
        return valid_decimal(value_str, column.precision(), column.frac());
368
11
    case FieldType::OLAP_FIELD_TYPE_CHAR:
369
230
    case FieldType::OLAP_FIELD_TYPE_VARCHAR:
370
230
        return value_str.size() <= column.length();
371
45
    case FieldType::OLAP_FIELD_TYPE_STRING:
372
45
        return value_str.size() <= config::string_type_length_soft_limit_bytes;
373
14
    case FieldType::OLAP_FIELD_TYPE_DATE:
374
29
    case FieldType::OLAP_FIELD_TYPE_DATETIME:
375
62
    case FieldType::OLAP_FIELD_TYPE_DATEV2:
376
94
    case FieldType::OLAP_FIELD_TYPE_DATETIMEV2:
377
1.98k
    case FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ:
378
1.98k
        return valid_datetime(value_str, column.frac());
379
5
    case FieldType::OLAP_FIELD_TYPE_BOOL:
380
5
        return valid_bool(value_str);
381
9
    case FieldType::OLAP_FIELD_TYPE_IPV4:
382
9
        return valid_ipv4(value_str);
383
36
    case FieldType::OLAP_FIELD_TYPE_IPV6:
384
36
        return valid_ipv6(value_str);
385
0
    default:
386
0
        LOG(WARNING) << "unknown field type. [type=" << int(field_type) << "]";
387
3.39k
    }
388
0
    return false;
389
3.39k
}
390
391
3.41k
Status DeleteHandler::check_condition_valid(const TabletSchema& schema, const TCondition& cond) {
392
    // Check whether the column exists
393
3.41k
    int32_t field_index = schema.field_index(cond.column_name);
394
3.41k
    if (field_index < 0) {
395
1
        return Status::Error<ErrorCode::INVALID_ARGUMENT>("field is not existent. [field_index={}]",
396
1
                                                          field_index);
397
1
    }
398
399
    // Delete condition should only applied on key columns or duplicate key table, and
400
    // the condition column type should not be float or double.
401
3.40k
    const TabletColumn& column = schema.column(field_index);
402
403
3.40k
    if (column.type() == FieldType::OLAP_FIELD_TYPE_DOUBLE ||
404
3.40k
        column.type() == FieldType::OLAP_FIELD_TYPE_FLOAT) {
405
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>("data type is float or double.");
406
0
    }
407
408
    // Check operator and operands size are matched.
409
3.40k
    if ("*=" != cond.condition_op && "!*=" != cond.condition_op &&
410
3.40k
        cond.condition_values.size() != 1) {
411
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>("invalid condition value size. [size={}]",
412
0
                                                          cond.condition_values.size());
413
0
    }
414
415
    // Check each operand is valid
416
3.84k
    for (const auto& condition_value : cond.condition_values) {
417
3.84k
        if (!is_condition_value_valid(column, cond.condition_op, condition_value)) {
418
29
            return Status::Error<ErrorCode::INVALID_ARGUMENT>("invalid condition value. [value={}]",
419
29
                                                              condition_value);
420
29
        }
421
3.84k
    }
422
423
3.38k
    if (!cond.__isset.column_unique_id) {
424
105
        LOG(WARNING) << "column=" << cond.column_name
425
105
                     << " in predicate does not have uid, table id=" << schema.table_id();
426
        // TODO(tsy): make it fail here after FE forbidding hard-link-schema-change
427
105
        return Status::OK();
428
105
    }
429
3.27k
    if (schema.field_index(cond.column_unique_id) == -1) {
430
0
        const auto& err_msg =
431
0
                fmt::format("column id does not exists in table={}, schema version={},",
432
0
                            schema.table_id(), schema.schema_version());
433
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>(err_msg);
434
0
    }
435
3.27k
    if (!iequal(schema.column_by_uid(cond.column_unique_id).name(), cond.column_name)) {
436
0
        const auto& err_msg = fmt::format(
437
0
                "colum name={} does not belongs to column uid={}, which "
438
0
                "column name={}, "
439
0
                "delete_cond.column_name ={}",
440
0
                cond.column_name, cond.column_unique_id,
441
0
                schema.column_by_uid(cond.column_unique_id).name(), cond.column_name);
442
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>(err_msg);
443
0
    }
444
445
3.27k
    return Status::OK();
446
3.27k
}
447
448
PredicateType DeleteHandler::parse_condition_op(const std::string& op_str,
449
8.02k
                                                const std::list<std::string>& cond_values) {
450
8.02k
    if (trim(to_lower(op_str)) == "=") {
451
3.92k
        return PredicateType::EQ;
452
4.10k
    } else if (trim(to_lower(op_str)) == "!=") {
453
957
        return PredicateType::NE;
454
3.14k
    } else if (trim(to_lower(op_str)) == ">>") {
455
562
        return PredicateType::GT;
456
2.58k
    } else if (trim(to_lower(op_str)) == "<<") {
457
875
        return PredicateType::LT;
458
1.71k
    } else if (trim(to_lower(op_str)) == ">=") {
459
425
        return PredicateType::GE;
460
1.28k
    } else if (trim(to_lower(op_str)) == "<=") {
461
730
        return PredicateType::LE;
462
730
    } else if (trim(to_lower(op_str)) == "*=") {
463
0
        return cond_values.size() > 1 ? PredicateType::IN_LIST : PredicateType::EQ;
464
557
    } else if (trim(to_lower(op_str)) == "!*=") {
465
0
        return cond_values.size() > 1 ? PredicateType::NOT_IN_LIST : PredicateType::NE;
466
587
    } else if (trim(to_lower(op_str)) == "is") {
467
587
        return to_lower(cond_values.front()) == "null" ? PredicateType::IS_NULL
468
587
                                                       : PredicateType::IS_NOT_NULL;
469
18.4E
    } else {
470
18.4E
        throw Exception(Status::Error<ErrorCode::INVALID_ARGUMENT>(
471
18.4E
                "invalid condition operator. operator={}", op_str));
472
18.4E
    }
473
0
    return PredicateType::UNKNOWN;
474
8.02k
}
475
476
DeleteHandler::ConditionParseResult DeleteHandler::parse_condition(
477
7.85k
        const DeleteSubPredicatePB& sub_cond) {
478
7.85k
    ConditionParseResult res;
479
7.86k
    if (!sub_cond.has_column_name() || !sub_cond.has_op() || !sub_cond.has_cond_value()) {
480
0
        throw Exception(Status::Error<ErrorCode::INVALID_ARGUMENT>(
481
0
                "fail to parse condition. condition={} {} {}", sub_cond.column_name(),
482
0
                sub_cond.op(), sub_cond.cond_value()));
483
0
    }
484
7.85k
    if (sub_cond.has_column_unique_id()) {
485
7.75k
        res.col_unique_id = sub_cond.column_unique_id();
486
7.75k
    }
487
7.85k
    res.column_name = sub_cond.column_name();
488
7.85k
    res.value_str.push_back(sub_cond.cond_value());
489
7.85k
    res.condition_op = parse_condition_op(sub_cond.op(), res.value_str);
490
7.85k
    return res;
491
7.85k
}
492
493
// clang-format off
494
// Condition string format, the format is (column_name)(op)(value)
495
// eg: condition_str="c1 = 1597751948193618247 and length(source)<1;\n;\n"
496
// column_name: matches "c1", must include FeNameFormat.java COLUMN_NAME_REGEX
497
//              and compactible with any the lagacy
498
// operator: matches "="
499
// value: matches "1597751948193618247  and length(source)<1;\n;\n"
500
//
501
// For more info, see DeleteHandler::construct_sub_predicates
502
// FIXME(gavin): This is a tricky implementation, it should not be the final resolution, refactor it.
503
const char* const CONDITION_STR_PATTERN =
504
    // .----------------- column-name --------------------------.   .----------------------- operator ------------------------.   .------------ value ----------.
505
    R"(([_a-zA-Z@0-9\s/\p{L}][.a-zA-Z0-9_+-/?@#$%^&*"\s,:\p{L}]*)\s*((?:=)|(?:!=)|(?:>>)|(?:<<)|(?:>=)|(?:<=)|(?:\*=)|(?: IS ))\s*('((?:[\s\S]+)?)'|(?:[\s\S]+)?))";
506
    // '----------------- group 1 ------------------------------'   '--------------------- group 2 ---------------------------'   | '-- group 4--'              |
507
    //                                                                   match any of: = != >> << >= <= *= " IS "                 '----------- group 3 ---------'
508
    //                                                                                                                             match **ANY THING** without(4)
509
    //                                                                                                                             or with(3) single quote
510
// clang-format on
511
RE2 DELETE_HANDLER_REGEX(CONDITION_STR_PATTERN);
512
513
DeleteHandler::ConditionParseResult DeleteHandler::parse_condition(
514
182
        const std::string& condition_str) {
515
182
    ConditionParseResult res;
516
182
    std::string col_name, op, value, g4;
517
518
182
    bool matched = RE2::FullMatch(condition_str, DELETE_HANDLER_REGEX, &col_name, &op, &value,
519
182
                                  &g4); // exact match
520
521
182
    if (!matched) {
522
0
        throw Exception(
523
0
                Status::InvalidArgument("fail to sub condition. condition={}", condition_str));
524
0
    }
525
526
182
    res.column_name = col_name;
527
528
    // match string with single quotes, a = b  or a = 'b'
529
182
    if (!g4.empty()) {
530
141
        res.value_str.push_back(g4);
531
141
    } else {
532
41
        res.value_str.push_back(value);
533
41
    }
534
182
    res.condition_op = DeleteHandler::parse_condition_op(op, res.value_str);
535
182
    VLOG_NOTICE << "parsed condition_str: col_name={" << col_name << "} op={" << op << "} val={"
536
48
                << res.value_str.back() << "}";
537
182
    return res;
538
182
}
539
540
template <typename SubPredType>
541
    requires(std::is_same_v<SubPredType, DeleteSubPredicatePB> or
542
             std::is_same_v<SubPredType, std::string>)
543
Status DeleteHandler::_parse_column_pred(TabletSchemaSPtr complete_schema,
544
                                         TabletSchemaSPtr delete_pred_related_schema,
545
                                         const RepeatedPtrField<SubPredType>& sub_pred_list,
546
7.86k
                                         DeleteConditions* delete_conditions) {
547
7.93k
    for (const auto& sub_predicate : sub_pred_list) {
548
7.93k
        auto condition = parse_condition(sub_predicate);
549
7.93k
        int32_t col_unique_id = -1;
550
7.93k
        if constexpr (std::is_same_v<SubPredType, DeleteSubPredicatePB>) {
551
7.85k
            if (sub_predicate.has_column_unique_id()) [[likely]] {
552
7.75k
                col_unique_id = sub_predicate.column_unique_id();
553
7.75k
            }
554
7.85k
        }
555
7.93k
        if (col_unique_id < 0) {
556
181
            const auto& column =
557
181
                    *DORIS_TRY(delete_pred_related_schema->column(condition.column_name));
558
181
            col_unique_id = column.unique_id();
559
181
        }
560
7.93k
        condition.col_unique_id = col_unique_id;
561
7.93k
        const auto& column = complete_schema->column_by_uid(col_unique_id);
562
7.93k
        uint32_t index = complete_schema->field_index(col_unique_id);
563
7.93k
        std::shared_ptr<ColumnPredicate> predicate;
564
7.93k
        RETURN_IF_ERROR(parse_to_predicate(index, column.name(), column.get_vec_type(), condition,
565
7.93k
                                           _predicate_arena, predicate));
566
7.92k
        if (predicate != nullptr) {
567
7.89k
            delete_conditions->column_predicate_vec.push_back(predicate);
568
7.89k
        }
569
7.92k
    }
570
7.85k
    return Status::OK();
571
7.86k
}
_ZN5doris13DeleteHandler18_parse_column_predINS_20DeleteSubPredicatePBEQoosr3stdE9is_same_vIT_S2_Esr3stdE9is_same_vIS3_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEENS_6StatusESt10shared_ptrINS_12TabletSchemaEESD_RKN6google8protobuf16RepeatedPtrFieldIS3_EEPNS_16DeleteConditionsE
Line
Count
Source
546
7.55k
                                         DeleteConditions* delete_conditions) {
547
7.85k
    for (const auto& sub_predicate : sub_pred_list) {
548
7.85k
        auto condition = parse_condition(sub_predicate);
549
7.85k
        int32_t col_unique_id = -1;
550
7.85k
        if constexpr (std::is_same_v<SubPredType, DeleteSubPredicatePB>) {
551
7.85k
            if (sub_predicate.has_column_unique_id()) [[likely]] {
552
7.75k
                col_unique_id = sub_predicate.column_unique_id();
553
7.75k
            }
554
7.85k
        }
555
7.85k
        if (col_unique_id < 0) {
556
100
            const auto& column =
557
100
                    *DORIS_TRY(delete_pred_related_schema->column(condition.column_name));
558
100
            col_unique_id = column.unique_id();
559
100
        }
560
7.85k
        condition.col_unique_id = col_unique_id;
561
7.85k
        const auto& column = complete_schema->column_by_uid(col_unique_id);
562
7.85k
        uint32_t index = complete_schema->field_index(col_unique_id);
563
7.85k
        std::shared_ptr<ColumnPredicate> predicate;
564
7.85k
        RETURN_IF_ERROR(parse_to_predicate(index, column.name(), column.get_vec_type(), condition,
565
7.85k
                                           _predicate_arena, predicate));
566
7.85k
        if (predicate != nullptr) {
567
7.81k
            delete_conditions->column_predicate_vec.push_back(predicate);
568
7.81k
        }
569
7.85k
    }
570
7.55k
    return Status::OK();
571
7.55k
}
_ZN5doris13DeleteHandler18_parse_column_predINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEQoosr3stdE9is_same_vIT_NS_20DeleteSubPredicatePBEEsr3stdE9is_same_vIS8_S7_EEENS_6StatusESt10shared_ptrINS_12TabletSchemaEESD_RKN6google8protobuf16RepeatedPtrFieldIS8_EEPNS_16DeleteConditionsE
Line
Count
Source
546
314
                                         DeleteConditions* delete_conditions) {
547
314
    for (const auto& sub_predicate : sub_pred_list) {
548
81
        auto condition = parse_condition(sub_predicate);
549
81
        int32_t col_unique_id = -1;
550
        if constexpr (std::is_same_v<SubPredType, DeleteSubPredicatePB>) {
551
            if (sub_predicate.has_column_unique_id()) [[likely]] {
552
                col_unique_id = sub_predicate.column_unique_id();
553
            }
554
        }
555
81
        if (col_unique_id < 0) {
556
81
            const auto& column =
557
81
                    *DORIS_TRY(delete_pred_related_schema->column(condition.column_name));
558
81
            col_unique_id = column.unique_id();
559
81
        }
560
81
        condition.col_unique_id = col_unique_id;
561
81
        const auto& column = complete_schema->column_by_uid(col_unique_id);
562
81
        uint32_t index = complete_schema->field_index(col_unique_id);
563
81
        std::shared_ptr<ColumnPredicate> predicate;
564
81
        RETURN_IF_ERROR(parse_to_predicate(index, column.name(), column.get_vec_type(), condition,
565
81
                                           _predicate_arena, predicate));
566
74
        if (predicate != nullptr) {
567
74
            delete_conditions->column_predicate_vec.push_back(predicate);
568
74
        }
569
74
    }
570
307
    return Status::OK();
571
314
}
572
573
Status DeleteHandler::init(TabletSchemaSPtr tablet_schema,
574
984k
                           const std::vector<RowsetMetaSharedPtr>& delete_preds, int64_t version) {
575
18.4E
    DCHECK(!_is_inited) << "reinitialize delete handler.";
576
18.4E
    DCHECK(version >= 0) << "invalid parameters. version=" << version;
577
578
984k
    for (const auto& delete_pred : delete_preds) {
579
        // Skip the delete condition with large version
580
7.86k
        if (delete_pred->version().first > version) {
581
0
            continue;
582
0
        }
583
        // Need the tablet schema at the delete condition to parse the accurate column
584
7.86k
        const auto& delete_pred_related_schema = delete_pred->tablet_schema();
585
7.86k
        const auto& delete_condition = delete_pred->delete_predicate();
586
7.86k
        DeleteConditions temp;
587
7.86k
        temp.filter_version = delete_pred->version().first;
588
7.86k
        if (!delete_condition.sub_predicates_v2().empty()) {
589
7.58k
            RETURN_IF_ERROR(_parse_column_pred(tablet_schema, delete_pred_related_schema,
590
7.58k
                                               delete_condition.sub_predicates_v2(), &temp));
591
7.58k
        } else {
592
            // make it compatible with the former versions
593
282
            RETURN_IF_ERROR(_parse_column_pred(tablet_schema, delete_pred_related_schema,
594
282
                                               delete_condition.sub_predicates(), &temp));
595
282
        }
596
7.85k
        for (const auto& in_predicate : delete_condition.in_predicates()) {
597
291
            ConditionParseResult condition;
598
291
            condition.column_name = in_predicate.column_name();
599
600
291
            int32_t col_unique_id = -1;
601
291
            if (in_predicate.has_column_unique_id()) {
602
291
                col_unique_id = in_predicate.column_unique_id();
603
291
            } else {
604
                // if upgrade from version 2.0.x, column_unique_id maybe not set
605
0
                const auto& pre_column =
606
0
                        *DORIS_TRY(delete_pred_related_schema->column(condition.column_name));
607
0
                col_unique_id = pre_column.unique_id();
608
0
            }
609
291
            if (col_unique_id == -1) {
610
0
                return Status::Error<ErrorCode::DELETE_INVALID_CONDITION>(
611
0
                        "cannot get column_unique_id for column {}", condition.column_name);
612
0
            }
613
291
            condition.col_unique_id = col_unique_id;
614
615
291
            condition.condition_op =
616
291
                    in_predicate.is_not_in() ? PredicateType::NOT_IN_LIST : PredicateType::IN_LIST;
617
934
            for (const auto& value : in_predicate.values()) {
618
934
                condition.value_str.push_back(value);
619
934
            }
620
291
            const auto& column = tablet_schema->column_by_uid(col_unique_id);
621
291
            uint32_t index = tablet_schema->field_index(col_unique_id);
622
291
            std::shared_ptr<ColumnPredicate> predicate;
623
291
            RETURN_IF_ERROR(parse_to_in_predicate(index, column.name(), column.get_vec_type(),
624
291
                                                  condition, _predicate_arena, predicate));
625
291
            temp.column_predicate_vec.push_back(predicate);
626
291
        }
627
628
7.85k
        _del_conds.emplace_back(std::move(temp));
629
7.85k
    }
630
631
983k
    _is_inited = true;
632
633
983k
    return Status::OK();
634
984k
}
635
636
1.00M
DeleteHandler::~DeleteHandler() {
637
1.00M
    if (!_is_inited) {
638
21.5k
        return;
639
21.5k
    }
640
641
985k
    _del_conds.clear();
642
985k
    _is_inited = false;
643
985k
}
644
645
void DeleteHandler::get_delete_conditions_after_version(
646
        int64_t version, AndBlockColumnPredicate* and_block_column_predicate_ptr,
647
        std::unordered_map<int32_t, std::vector<std::shared_ptr<const ColumnPredicate>>>*
648
3.59M
                del_predicates_for_zone_map) const {
649
3.59M
    for (const auto& del_cond : _del_conds) {
650
82.5k
        if (del_cond.filter_version > version) {
651
            // now, only query support delete column predicate operator
652
46.2k
            if (!del_cond.column_predicate_vec.empty()) {
653
46.2k
                if (del_cond.column_predicate_vec.size() == 1) {
654
45.1k
                    auto single_column_block_predicate = SingleColumnBlockPredicate::create_unique(
655
45.1k
                            del_cond.column_predicate_vec[0]);
656
45.1k
                    and_block_column_predicate_ptr->add_column_predicate(
657
45.1k
                            std::move(single_column_block_predicate));
658
45.1k
                    if (del_predicates_for_zone_map->count(
659
45.1k
                                del_cond.column_predicate_vec[0]->column_id()) < 1) {
660
19.2k
                        del_predicates_for_zone_map->insert(
661
19.2k
                                {del_cond.column_predicate_vec[0]->column_id(),
662
19.2k
                                 std::vector<std::shared_ptr<const ColumnPredicate>> {}});
663
19.2k
                    }
664
45.1k
                    (*del_predicates_for_zone_map)[del_cond.column_predicate_vec[0]->column_id()]
665
45.1k
                            .push_back(del_cond.column_predicate_vec[0]);
666
45.1k
                } else {
667
1.12k
                    auto or_column_predicate = OrBlockColumnPredicate::create_unique();
668
669
                    // build or_column_predicate
670
                    // when delete from where a = 1 and b = 2, we can not use del_predicates_for_zone_map to filter zone page,
671
                    // so here do not put predicate to del_predicates_for_zone_map,
672
                    // refer #17145 for more details.
673
                    // // TODO: need refactor design and code to use more version delete and more column delete to filter zone page.
674
1.12k
                    std::for_each(del_cond.column_predicate_vec.cbegin(),
675
1.12k
                                  del_cond.column_predicate_vec.cend(),
676
1.12k
                                  [&or_column_predicate](
677
2.45k
                                          const std::shared_ptr<const ColumnPredicate> predicate) {
678
2.45k
                                      or_column_predicate->add_column_predicate(
679
2.45k
                                              SingleColumnBlockPredicate::create_unique(predicate));
680
2.45k
                                  });
681
1.12k
                    and_block_column_predicate_ptr->add_column_predicate(
682
1.12k
                            std::move(or_column_predicate));
683
1.12k
                }
684
46.2k
            }
685
46.2k
        }
686
82.5k
    }
687
3.59M
}
688
689
} // namespace doris