Coverage Report

Created: 2026-03-15 22:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/format/table/paimon_predicate_converter.cpp
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#include "format/table/paimon_predicate_converter.h"
19
20
#include <algorithm>
21
#include <cctype>
22
#include <utility>
23
24
#include "core/column/column_const.h"
25
#include "core/column/column_nullable.h"
26
#include "core/data_type/data_type.h"
27
#include "core/data_type/data_type_nullable.h"
28
#include "core/field.h"
29
#include "core/types.h"
30
#include "core/value/decimalv2_value.h"
31
#include "core/value/timestamptz_value.h"
32
#include "core/value/vdatetime_value.h"
33
#include "exprs/vcompound_pred.h"
34
#include "exprs/vdirect_in_predicate.h"
35
#include "exprs/vectorized_fn_call.h"
36
#include "exprs/vexpr.h"
37
#include "exprs/vin_predicate.h"
38
#include "exprs/vliteral.h"
39
#include "exprs/vslot_ref.h"
40
#include "paimon/data/decimal.h"
41
#include "paimon/data/timestamp.h"
42
#include "paimon/predicate/predicate_builder.h"
43
#include "runtime/descriptors.h"
44
#include "runtime/runtime_state.h"
45
#include "util/timezone_utils.h"
46
47
namespace doris {
48
#include "common/compile_check_begin.h"
49
50
PaimonPredicateConverter::PaimonPredicateConverter(
51
        const std::vector<SlotDescriptor*>& file_slot_descs, RuntimeState* state)
52
0
        : _state(state) {
53
0
    _field_index_by_name.reserve(file_slot_descs.size());
54
0
    for (size_t i = 0; i < file_slot_descs.size(); ++i) {
55
0
        const auto& name = file_slot_descs[i]->col_name();
56
0
        auto normalized = _normalize_name(name);
57
0
        if (_field_index_by_name.find(normalized) == _field_index_by_name.end()) {
58
0
            _field_index_by_name.emplace(std::move(normalized), static_cast<int32_t>(i));
59
0
        }
60
0
    }
61
62
0
    if (!TimezoneUtils::find_cctz_time_zone("GMT", _gmt_tz)) {
63
0
        TimezoneUtils::find_cctz_time_zone(TimezoneUtils::default_time_zone, _gmt_tz);
64
0
    }
65
0
}
66
67
std::shared_ptr<paimon::Predicate> PaimonPredicateConverter::build(
68
0
        const VExprContextSPtrs& conjuncts) {
69
0
    std::vector<std::shared_ptr<paimon::Predicate>> predicates;
70
0
    predicates.reserve(conjuncts.size());
71
0
    for (const auto& conjunct : conjuncts) {
72
0
        if (!conjunct || !conjunct->root()) {
73
0
            continue;
74
0
        }
75
0
        auto root = conjunct->root();
76
0
        if (root->is_rf_wrapper()) {
77
0
            if (auto impl = root->get_impl()) {
78
0
                root = impl;
79
0
            }
80
0
        }
81
0
        auto predicate = _convert_expr(root);
82
0
        if (predicate) {
83
0
            predicates.emplace_back(std::move(predicate));
84
0
        }
85
0
    }
86
87
0
    if (predicates.empty()) {
88
0
        return nullptr;
89
0
    }
90
0
    if (predicates.size() == 1) {
91
0
        return predicates.front();
92
0
    }
93
0
    auto and_result = paimon::PredicateBuilder::And(predicates);
94
0
    if (!and_result.ok()) {
95
0
        return nullptr;
96
0
    }
97
0
    return std::move(and_result).value();
98
0
}
99
100
0
std::shared_ptr<paimon::Predicate> PaimonPredicateConverter::_convert_expr(const VExprSPtr& expr) {
101
0
    if (!expr) {
102
0
        return nullptr;
103
0
    }
104
105
0
    auto uncast = VExpr::expr_without_cast(expr);
106
107
0
    if (auto* direct_in = dynamic_cast<VDirectInPredicate*>(uncast.get())) {
108
0
        VExprSPtr in_expr;
109
0
        if (direct_in->get_slot_in_expr(in_expr)) {
110
0
            return _convert_in(in_expr);
111
0
        }
112
0
        return nullptr;
113
0
    }
114
115
0
    if (dynamic_cast<VInPredicate*>(uncast.get()) != nullptr) {
116
0
        return _convert_in(uncast);
117
0
    }
118
119
0
    switch (uncast->op()) {
120
0
    case TExprOpcode::COMPOUND_AND:
121
0
    case TExprOpcode::COMPOUND_OR:
122
0
        return _convert_compound(uncast);
123
0
    case TExprOpcode::COMPOUND_NOT:
124
0
        return nullptr;
125
0
    case TExprOpcode::EQ:
126
0
    case TExprOpcode::EQ_FOR_NULL:
127
0
    case TExprOpcode::NE:
128
0
    case TExprOpcode::GE:
129
0
    case TExprOpcode::GT:
130
0
    case TExprOpcode::LE:
131
0
    case TExprOpcode::LT:
132
0
        return _convert_binary(uncast);
133
0
    default:
134
0
        break;
135
0
    }
136
137
0
    if (auto* fn = dynamic_cast<VectorizedFnCall*>(uncast.get())) {
138
0
        auto fn_name = _normalize_name(fn->function_name());
139
0
        if (fn_name == "is_null_pred" || fn_name == "is_not_null_pred") {
140
0
            return _convert_is_null(uncast, fn_name);
141
0
        }
142
0
        if (fn_name == "like") {
143
0
            return _convert_like_prefix(uncast);
144
0
        }
145
0
    }
146
147
0
    return nullptr;
148
0
}
149
150
std::shared_ptr<paimon::Predicate> PaimonPredicateConverter::_convert_compound(
151
0
        const VExprSPtr& expr) {
152
0
    if (!expr || expr->get_num_children() != 2) {
153
0
        return nullptr;
154
0
    }
155
0
    auto left = _convert_expr(expr->get_child(0));
156
0
    if (!left) {
157
0
        return nullptr;
158
0
    }
159
0
    auto right = _convert_expr(expr->get_child(1));
160
0
    if (!right) {
161
0
        return nullptr;
162
0
    }
163
164
0
    if (expr->op() == TExprOpcode::COMPOUND_AND) {
165
0
        auto and_result = paimon::PredicateBuilder::And({left, right});
166
0
        return and_result.ok() ? std::move(and_result).value() : nullptr;
167
0
    }
168
0
    if (expr->op() == TExprOpcode::COMPOUND_OR) {
169
0
        auto or_result = paimon::PredicateBuilder::Or({left, right});
170
0
        return or_result.ok() ? std::move(or_result).value() : nullptr;
171
0
    }
172
0
    return nullptr;
173
0
}
174
175
0
std::shared_ptr<paimon::Predicate> PaimonPredicateConverter::_convert_in(const VExprSPtr& expr) {
176
0
    auto* in_pred = dynamic_cast<VInPredicate*>(expr.get());
177
0
    if (!in_pred || expr->get_num_children() < 2) {
178
0
        return nullptr;
179
0
    }
180
0
    auto field_meta = _resolve_field(expr->get_child(0));
181
0
    if (!field_meta) {
182
0
        return nullptr;
183
0
    }
184
185
0
    std::vector<paimon::Literal> literals;
186
0
    literals.reserve(expr->get_num_children() - 1);
187
0
    for (uint16_t i = 1; i < expr->get_num_children(); ++i) {
188
0
        auto literal = _convert_literal(expr->get_child(i), *field_meta->slot_desc,
189
0
                                        field_meta->field_type);
190
0
        if (!literal) {
191
0
            return nullptr;
192
0
        }
193
0
        literals.emplace_back(std::move(*literal));
194
0
    }
195
196
0
    if (literals.empty()) {
197
0
        return nullptr;
198
0
    }
199
0
    if (in_pred->is_not_in()) {
200
0
        return paimon::PredicateBuilder::NotIn(field_meta->index, field_meta->slot_desc->col_name(),
201
0
                                               field_meta->field_type, literals);
202
0
    }
203
0
    return paimon::PredicateBuilder::In(field_meta->index, field_meta->slot_desc->col_name(),
204
0
                                        field_meta->field_type, literals);
205
0
}
206
207
std::shared_ptr<paimon::Predicate> PaimonPredicateConverter::_convert_binary(
208
0
        const VExprSPtr& expr) {
209
0
    if (!expr || expr->get_num_children() != 2) {
210
0
        return nullptr;
211
0
    }
212
0
    auto field_meta = _resolve_field(expr->get_child(0));
213
0
    if (!field_meta) {
214
0
        return nullptr;
215
0
    }
216
217
0
    if (expr->op() == TExprOpcode::EQ_FOR_NULL) {
218
0
        return paimon::PredicateBuilder::IsNull(
219
0
                field_meta->index, field_meta->slot_desc->col_name(), field_meta->field_type);
220
0
    }
221
222
0
    auto literal =
223
0
            _convert_literal(expr->get_child(1), *field_meta->slot_desc, field_meta->field_type);
224
0
    if (!literal) {
225
0
        return nullptr;
226
0
    }
227
228
0
    switch (expr->op()) {
229
0
    case TExprOpcode::EQ:
230
0
        return paimon::PredicateBuilder::Equal(field_meta->index, field_meta->slot_desc->col_name(),
231
0
                                               field_meta->field_type, *literal);
232
0
    case TExprOpcode::NE:
233
0
        return paimon::PredicateBuilder::NotEqual(field_meta->index,
234
0
                                                  field_meta->slot_desc->col_name(),
235
0
                                                  field_meta->field_type, *literal);
236
0
    case TExprOpcode::GE:
237
0
        return paimon::PredicateBuilder::GreaterOrEqual(field_meta->index,
238
0
                                                        field_meta->slot_desc->col_name(),
239
0
                                                        field_meta->field_type, *literal);
240
0
    case TExprOpcode::GT:
241
0
        return paimon::PredicateBuilder::GreaterThan(field_meta->index,
242
0
                                                     field_meta->slot_desc->col_name(),
243
0
                                                     field_meta->field_type, *literal);
244
0
    case TExprOpcode::LE:
245
0
        return paimon::PredicateBuilder::LessOrEqual(field_meta->index,
246
0
                                                     field_meta->slot_desc->col_name(),
247
0
                                                     field_meta->field_type, *literal);
248
0
    case TExprOpcode::LT:
249
0
        return paimon::PredicateBuilder::LessThan(field_meta->index,
250
0
                                                  field_meta->slot_desc->col_name(),
251
0
                                                  field_meta->field_type, *literal);
252
0
    default:
253
0
        break;
254
0
    }
255
0
    return nullptr;
256
0
}
257
258
std::shared_ptr<paimon::Predicate> PaimonPredicateConverter::_convert_is_null(
259
0
        const VExprSPtr& expr, const std::string& fn_name) {
260
0
    if (!expr || expr->get_num_children() != 1) {
261
0
        return nullptr;
262
0
    }
263
0
    auto field_meta = _resolve_field(expr->get_child(0));
264
0
    if (!field_meta) {
265
0
        return nullptr;
266
0
    }
267
0
    if (fn_name == "is_not_null_pred") {
268
0
        return paimon::PredicateBuilder::IsNotNull(
269
0
                field_meta->index, field_meta->slot_desc->col_name(), field_meta->field_type);
270
0
    }
271
0
    return paimon::PredicateBuilder::IsNull(field_meta->index, field_meta->slot_desc->col_name(),
272
0
                                            field_meta->field_type);
273
0
}
274
275
std::shared_ptr<paimon::Predicate> PaimonPredicateConverter::_convert_like_prefix(
276
0
        const VExprSPtr& expr) {
277
0
    if (!expr || expr->get_num_children() != 2) {
278
0
        return nullptr;
279
0
    }
280
0
    auto field_meta = _resolve_field(expr->get_child(0));
281
0
    if (!field_meta || field_meta->field_type != paimon::FieldType::STRING) {
282
0
        return nullptr;
283
0
    }
284
285
0
    auto pattern_opt = _extract_string_literal(expr->get_child(1));
286
0
    if (!pattern_opt) {
287
0
        return nullptr;
288
0
    }
289
0
    const std::string& pattern = *pattern_opt;
290
0
    if (!pattern.empty() && pattern.front() == '%') {
291
0
        return nullptr;
292
0
    }
293
0
    if (pattern.empty() || pattern.back() != '%') {
294
0
        return nullptr;
295
0
    }
296
297
0
    std::string prefix = pattern.substr(0, pattern.size() - 1);
298
0
    paimon::Literal lower_literal(paimon::FieldType::STRING, prefix.data(), prefix.size());
299
0
    auto lower_pred = paimon::PredicateBuilder::GreaterOrEqual(
300
0
            field_meta->index, field_meta->slot_desc->col_name(), field_meta->field_type,
301
0
            lower_literal);
302
303
0
    auto upper_prefix = _next_prefix(prefix);
304
0
    if (!upper_prefix) {
305
0
        return lower_pred;
306
0
    }
307
308
0
    paimon::Literal upper_literal(paimon::FieldType::STRING, upper_prefix->data(),
309
0
                                  upper_prefix->size());
310
0
    auto upper_pred =
311
0
            paimon::PredicateBuilder::LessThan(field_meta->index, field_meta->slot_desc->col_name(),
312
0
                                               field_meta->field_type, upper_literal);
313
0
    auto and_result = paimon::PredicateBuilder::And({lower_pred, upper_pred});
314
0
    return and_result.ok() ? std::move(and_result).value() : nullptr;
315
0
}
316
317
std::optional<PaimonPredicateConverter::FieldMeta> PaimonPredicateConverter::_resolve_field(
318
0
        const VExprSPtr& expr) const {
319
0
    if (!_state || !expr) {
320
0
        return std::nullopt;
321
0
    }
322
0
    auto slot_expr = VExpr::expr_without_cast(expr);
323
0
    auto* slot_ref = dynamic_cast<VSlotRef*>(slot_expr.get());
324
0
    if (!slot_ref) {
325
0
        return std::nullopt;
326
0
    }
327
0
    auto* slot_desc = _state->desc_tbl().get_slot_descriptor(slot_ref->slot_id());
328
0
    if (!slot_desc) {
329
0
        return std::nullopt;
330
0
    }
331
0
    auto normalized = _normalize_name(slot_desc->col_name());
332
0
    auto it = _field_index_by_name.find(normalized);
333
0
    if (it == _field_index_by_name.end()) {
334
0
        return std::nullopt;
335
0
    }
336
0
    auto slot_type = slot_desc->type();
337
0
    auto field_type =
338
0
            _to_paimon_field_type(slot_type->get_primitive_type(), slot_type->get_precision());
339
0
    if (!field_type) {
340
0
        return std::nullopt;
341
0
    }
342
0
    return FieldMeta {it->second, *field_type, slot_desc};
343
0
}
344
345
std::optional<paimon::Literal> PaimonPredicateConverter::_convert_literal(
346
        const VExprSPtr& expr, const SlotDescriptor& slot_desc,
347
0
        paimon::FieldType field_type) const {
348
0
    auto literal_expr = VExpr::expr_without_cast(expr);
349
0
    auto* literal = dynamic_cast<VLiteral*>(literal_expr.get());
350
0
    if (!literal) {
351
0
        return std::nullopt;
352
0
    }
353
354
0
    auto literal_type = remove_nullable(literal->get_data_type());
355
0
    PrimitiveType literal_primitive = literal_type->get_primitive_type();
356
0
    PrimitiveType slot_primitive = slot_desc.type()->get_primitive_type();
357
358
0
    ColumnPtr col = literal->get_column_ptr()->convert_to_full_column_if_const();
359
0
    if (const auto* nullable = check_and_get_column<ColumnNullable>(*col)) {
360
0
        if (nullable->is_null_at(0)) {
361
0
            return std::nullopt;
362
0
        }
363
0
        col = nullable->get_nested_column_ptr();
364
0
    }
365
366
0
    Field field;
367
0
    col->get(0, field);
368
369
0
    switch (slot_primitive) {
370
0
    case TYPE_BOOLEAN: {
371
0
        if (literal_primitive != TYPE_BOOLEAN) {
372
0
            return std::nullopt;
373
0
        }
374
0
        return paimon::Literal(static_cast<bool>(field.get<TYPE_BOOLEAN>()));
375
0
    }
376
0
    case TYPE_TINYINT:
377
0
    case TYPE_SMALLINT:
378
0
    case TYPE_INT:
379
0
    case TYPE_BIGINT: {
380
0
        if (!_is_integer_type(literal_primitive)) {
381
0
            return std::nullopt;
382
0
        }
383
0
        int64_t value = 0;
384
0
        switch (literal_primitive) {
385
0
        case TYPE_TINYINT:
386
0
            value = field.get<TYPE_TINYINT>();
387
0
            break;
388
0
        case TYPE_SMALLINT:
389
0
            value = field.get<TYPE_SMALLINT>();
390
0
            break;
391
0
        case TYPE_INT:
392
0
            value = field.get<TYPE_INT>();
393
0
            break;
394
0
        case TYPE_BIGINT:
395
0
            value = field.get<TYPE_BIGINT>();
396
0
            break;
397
0
        default:
398
0
            return std::nullopt;
399
0
        }
400
0
        if (slot_primitive == TYPE_TINYINT) {
401
0
            return paimon::Literal(static_cast<int8_t>(value));
402
0
        }
403
0
        if (slot_primitive == TYPE_SMALLINT) {
404
0
            return paimon::Literal(static_cast<int16_t>(value));
405
0
        }
406
0
        if (slot_primitive == TYPE_INT) {
407
0
            return paimon::Literal(static_cast<int32_t>(value));
408
0
        }
409
0
        return paimon::Literal(static_cast<int64_t>(value));
410
0
    }
411
0
    case TYPE_DOUBLE: {
412
0
        if (literal_primitive != TYPE_DOUBLE && literal_primitive != TYPE_FLOAT) {
413
0
            return std::nullopt;
414
0
        }
415
0
        double value = 0;
416
0
        if (literal_primitive == TYPE_FLOAT) {
417
0
            value = static_cast<double>(field.get<TYPE_FLOAT>());
418
0
        } else {
419
0
            value = field.get<TYPE_DOUBLE>();
420
0
        }
421
0
        return paimon::Literal(value);
422
0
    }
423
0
    case TYPE_DATE:
424
0
    case TYPE_DATEV2: {
425
0
        if (!_is_date_type(literal_primitive)) {
426
0
            return std::nullopt;
427
0
        }
428
0
        int64_t seconds = 0;
429
0
        if (literal_primitive == TYPE_DATE) {
430
0
            const auto& dt = field.get<TYPE_DATE>();
431
0
            if (!dt.is_valid_date()) {
432
0
                return std::nullopt;
433
0
            }
434
0
            dt.unix_timestamp(&seconds, _gmt_tz);
435
0
        } else if (literal_primitive == TYPE_DATEV2) {
436
0
            const auto& dt = field.get<TYPE_DATEV2>();
437
0
            if (!dt.is_valid_date()) {
438
0
                return std::nullopt;
439
0
            }
440
0
            dt.unix_timestamp(&seconds, _gmt_tz);
441
0
        }
442
0
        int32_t days = _seconds_to_days(seconds);
443
0
        return paimon::Literal(paimon::FieldType::DATE, days);
444
0
    }
445
0
    case TYPE_DATETIME:
446
0
    case TYPE_DATETIMEV2: {
447
0
        if (!_is_datetime_type(literal_primitive)) {
448
0
            return std::nullopt;
449
0
        }
450
0
        if (literal_primitive == TYPE_DATETIME) {
451
0
            const auto& dt = field.get<TYPE_DATETIME>();
452
0
            if (!dt.is_valid_date()) {
453
0
                return std::nullopt;
454
0
            }
455
0
            int64_t seconds = 0;
456
0
            dt.unix_timestamp(&seconds, _gmt_tz);
457
0
            return paimon::Literal(paimon::Timestamp::FromEpochMillis(seconds * 1000));
458
0
        }
459
0
        std::pair<int64_t, int64_t> ts;
460
0
        const auto& dt = field.get<TYPE_DATETIMEV2>();
461
0
        if (!dt.is_valid_date()) {
462
0
            return std::nullopt;
463
0
        }
464
0
        dt.unix_timestamp(&ts, _gmt_tz);
465
0
        int64_t millis = ts.first * 1000 + ts.second / 1000;
466
0
        return paimon::Literal(paimon::Timestamp::FromEpochMillis(millis));
467
0
    }
468
0
    case TYPE_VARCHAR:
469
0
    case TYPE_STRING: {
470
0
        if (!_is_string_type(literal_primitive)) {
471
0
            return std::nullopt;
472
0
        }
473
0
        const auto& value = field.get<TYPE_STRING>();
474
0
        return paimon::Literal(field_type, value.data(), value.size());
475
0
    }
476
0
    case TYPE_DECIMALV2:
477
0
    case TYPE_DECIMAL32:
478
0
    case TYPE_DECIMAL64:
479
0
    case TYPE_DECIMAL128I:
480
0
    case TYPE_DECIMAL256: {
481
0
        if (!_is_decimal_type(literal_primitive)) {
482
0
            return std::nullopt;
483
0
        }
484
0
        int32_t precision = static_cast<int32_t>(literal_type->get_precision());
485
0
        int32_t scale = static_cast<int32_t>(literal_type->get_scale());
486
0
        if (precision <= 0 || precision > paimon::Decimal::MAX_PRECISION) {
487
0
            return std::nullopt;
488
0
        }
489
490
0
        paimon::Decimal::int128_t value = 0;
491
0
        switch (literal_primitive) {
492
0
        case TYPE_DECIMALV2: {
493
0
            const auto& dec = field.get<TYPE_DECIMALV2>();
494
0
            value = dec.value();
495
0
            break;
496
0
        }
497
0
        case TYPE_DECIMAL32: {
498
0
            const auto& dec = field.get<TYPE_DECIMAL32>();
499
0
            value = dec.value;
500
0
            break;
501
0
        }
502
0
        case TYPE_DECIMAL64: {
503
0
            const auto& dec = field.get<TYPE_DECIMAL64>();
504
0
            value = dec.value;
505
0
            break;
506
0
        }
507
0
        case TYPE_DECIMAL128I: {
508
0
            const auto& dec = field.get<TYPE_DECIMAL128I>();
509
0
            value = dec.value;
510
0
            break;
511
0
        }
512
0
        default:
513
0
            return std::nullopt;
514
0
        }
515
0
        return paimon::Literal(paimon::Decimal(precision, scale, value));
516
0
    }
517
0
    default:
518
0
        break;
519
0
    }
520
0
    return std::nullopt;
521
0
}
522
523
std::optional<std::string> PaimonPredicateConverter::_extract_string_literal(
524
0
        const VExprSPtr& expr) const {
525
0
    auto literal_expr = VExpr::expr_without_cast(expr);
526
0
    auto* literal = dynamic_cast<VLiteral*>(literal_expr.get());
527
0
    if (!literal) {
528
0
        return std::nullopt;
529
0
    }
530
0
    auto literal_type = remove_nullable(literal->get_data_type());
531
0
    PrimitiveType literal_primitive = literal_type->get_primitive_type();
532
0
    if (!_is_string_type(literal_primitive)) {
533
0
        return std::nullopt;
534
0
    }
535
536
0
    ColumnPtr col = literal->get_column_ptr()->convert_to_full_column_if_const();
537
0
    if (const auto* nullable = check_and_get_column<ColumnNullable>(*col)) {
538
0
        if (nullable->is_null_at(0)) {
539
0
            return std::nullopt;
540
0
        }
541
0
        col = nullable->get_nested_column_ptr();
542
0
    }
543
0
    Field field;
544
0
    col->get(0, field);
545
0
    const auto& value = field.get<TYPE_STRING>();
546
0
    return value;
547
0
}
548
549
0
std::string PaimonPredicateConverter::_normalize_name(std::string_view name) {
550
0
    std::string out(name);
551
0
    std::transform(out.begin(), out.end(), out.begin(),
552
0
                   [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
553
0
    return out;
554
0
}
555
556
0
std::optional<std::string> PaimonPredicateConverter::_next_prefix(const std::string& prefix) {
557
0
    if (prefix.empty()) {
558
0
        return std::nullopt;
559
0
    }
560
0
    std::string upper = prefix;
561
0
    for (int i = static_cast<int>(upper.size()) - 1; i >= 0; --i) {
562
0
        auto c = static_cast<unsigned char>(upper[i]);
563
0
        if (c != 0xFF) {
564
0
            upper[i] = static_cast<char>(c + 1);
565
0
            upper.resize(i + 1);
566
0
            return upper;
567
0
        }
568
0
    }
569
0
    return std::nullopt;
570
0
}
571
572
0
int32_t PaimonPredicateConverter::_seconds_to_days(int64_t seconds) {
573
0
    static constexpr int64_t kSecondsPerDay = 24 * 60 * 60;
574
0
    int64_t days = seconds / kSecondsPerDay;
575
0
    if (seconds < 0 && seconds % kSecondsPerDay != 0) {
576
0
        --days;
577
0
    }
578
0
    return static_cast<int32_t>(days);
579
0
}
580
581
0
bool PaimonPredicateConverter::_is_integer_type(PrimitiveType type) {
582
0
    switch (type) {
583
0
    case TYPE_TINYINT:
584
0
    case TYPE_SMALLINT:
585
0
    case TYPE_INT:
586
0
    case TYPE_BIGINT:
587
0
        return true;
588
0
    default:
589
0
        return false;
590
0
    }
591
0
}
592
593
0
bool PaimonPredicateConverter::_is_string_type(PrimitiveType type) {
594
0
    return type == TYPE_CHAR || type == TYPE_VARCHAR || type == TYPE_STRING;
595
0
}
596
597
0
bool PaimonPredicateConverter::_is_decimal_type(PrimitiveType type) {
598
0
    switch (type) {
599
0
    case TYPE_DECIMALV2:
600
0
    case TYPE_DECIMAL32:
601
0
    case TYPE_DECIMAL64:
602
0
    case TYPE_DECIMAL128I:
603
0
    case TYPE_DECIMAL256:
604
0
        return true;
605
0
    default:
606
0
        return false;
607
0
    }
608
0
}
609
610
0
bool PaimonPredicateConverter::_is_date_type(PrimitiveType type) {
611
0
    return type == TYPE_DATE || type == TYPE_DATEV2;
612
0
}
613
614
0
bool PaimonPredicateConverter::_is_datetime_type(PrimitiveType type) {
615
0
    return type == TYPE_DATETIME || type == TYPE_DATETIMEV2;
616
0
}
617
618
std::optional<paimon::FieldType> PaimonPredicateConverter::_to_paimon_field_type(
619
0
        PrimitiveType type, uint32_t precision) {
620
0
    switch (type) {
621
0
    case TYPE_BOOLEAN:
622
0
        return paimon::FieldType::BOOLEAN;
623
0
    case TYPE_TINYINT:
624
0
        return paimon::FieldType::TINYINT;
625
0
    case TYPE_SMALLINT:
626
0
        return paimon::FieldType::SMALLINT;
627
0
    case TYPE_INT:
628
0
        return paimon::FieldType::INT;
629
0
    case TYPE_BIGINT:
630
0
        return paimon::FieldType::BIGINT;
631
0
    case TYPE_DOUBLE:
632
0
        return paimon::FieldType::DOUBLE;
633
0
    case TYPE_VARCHAR:
634
0
    case TYPE_STRING:
635
0
        return paimon::FieldType::STRING;
636
0
    case TYPE_DATE:
637
0
    case TYPE_DATEV2:
638
0
        return paimon::FieldType::DATE;
639
0
    case TYPE_DATETIME:
640
0
    case TYPE_DATETIMEV2:
641
0
        return paimon::FieldType::TIMESTAMP;
642
0
    case TYPE_DECIMALV2:
643
0
    case TYPE_DECIMAL32:
644
0
    case TYPE_DECIMAL64:
645
0
    case TYPE_DECIMAL128I:
646
0
    case TYPE_DECIMAL256:
647
0
        if (precision > 0 && precision > paimon::Decimal::MAX_PRECISION) {
648
0
            return std::nullopt;
649
0
        }
650
0
        return paimon::FieldType::DECIMAL;
651
0
    case TYPE_FLOAT:
652
0
    case TYPE_CHAR:
653
0
    default:
654
0
        return std::nullopt;
655
0
    }
656
0
}
657
658
#include "common/compile_check_end.h"
659
} // namespace doris