Coverage Report

Created: 2026-10-17 16:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/doris/be/src/exprs/vtopn_pred.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 "exprs/vtopn_pred.h"
19
20
#include <cstring>
21
22
#include "exprs/expr_zonemap_filter.h"
23
#include "util/simd/parquet_kernels.h"
24
25
namespace doris {
26
27
namespace {
28
29
using simd::RawComparisonOp;
30
31
99
size_t topn_raw_value_size(PrimitiveType type) {
32
99
    switch (type) {
33
0
#define RETURN_TOPN_RAW_SIZE(TYPE) \
34
84
    case TYPE:                     \
35
84
        return sizeof(typename PrimitiveTypeTraits<TYPE>::CppType)
36
2
        RETURN_TOPN_RAW_SIZE(TYPE_BOOLEAN);
37
2
        RETURN_TOPN_RAW_SIZE(TYPE_TINYINT);
38
2
        RETURN_TOPN_RAW_SIZE(TYPE_SMALLINT);
39
29
        RETURN_TOPN_RAW_SIZE(TYPE_INT);
40
2
        RETURN_TOPN_RAW_SIZE(TYPE_BIGINT);
41
2
        RETURN_TOPN_RAW_SIZE(TYPE_LARGEINT);
42
0
        RETURN_TOPN_RAW_SIZE(TYPE_FLOAT);
43
0
        RETURN_TOPN_RAW_SIZE(TYPE_DOUBLE);
44
2
        RETURN_TOPN_RAW_SIZE(TYPE_DATE);
45
2
        RETURN_TOPN_RAW_SIZE(TYPE_DATETIME);
46
2
        RETURN_TOPN_RAW_SIZE(TYPE_DATEV2);
47
2
        RETURN_TOPN_RAW_SIZE(TYPE_DATETIMEV2);
48
5
        RETURN_TOPN_RAW_SIZE(TYPE_TIMESTAMP_NS);
49
2
        RETURN_TOPN_RAW_SIZE(TYPE_TIMESTAMPTZ);
50
0
        RETURN_TOPN_RAW_SIZE(TYPE_TIME);
51
2
        RETURN_TOPN_RAW_SIZE(TYPE_TIMEV2);
52
2
        RETURN_TOPN_RAW_SIZE(TYPE_DECIMAL32);
53
2
        RETURN_TOPN_RAW_SIZE(TYPE_DECIMAL64);
54
2
        RETURN_TOPN_RAW_SIZE(TYPE_DECIMALV2);
55
2
        RETURN_TOPN_RAW_SIZE(TYPE_DECIMAL128I);
56
2
        RETURN_TOPN_RAW_SIZE(TYPE_DECIMAL256);
57
2
        RETURN_TOPN_RAW_SIZE(TYPE_IPV4);
58
2
        RETURN_TOPN_RAW_SIZE(TYPE_IPV6);
59
14
        RETURN_TOPN_RAW_SIZE(TYPE_UUID);
60
0
#undef RETURN_TOPN_RAW_SIZE
61
15
    default:
62
15
        return 0;
63
99
    }
64
99
}
65
66
22
bool topn_binary_type(PrimitiveType type) {
67
22
    return is_string_type(type) || type == TYPE_VARBINARY;
68
22
}
69
70
template <typename T, PrimitiveType PT>
71
void execute_topn_raw_comparison(const uint8_t* values, size_t num_values, const Field& bound,
72
5
                                 RawComparisonOp op, uint8_t* matches) {
73
5
    simd::raw_compare(values, num_values, bound.get<PT>(), op, matches);
74
5
}
vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_127execute_topn_raw_comparisonIiLNS_13PrimitiveTypeE5EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Line
Count
Source
72
5
                                 RawComparisonOp op, uint8_t* matches) {
73
5
    simd::raw_compare(values, num_values, bound.get<PT>(), op, matches);
74
5
}
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_127execute_topn_raw_comparisonIlLNS_13PrimitiveTypeE6EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_127execute_topn_raw_comparisonIfLNS_13PrimitiveTypeE8EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_127execute_topn_raw_comparisonIdLNS_13PrimitiveTypeE9EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
75
76
template <typename T>
77
23
bool topn_raw_scalar_matches(const T& value, const T& bound, RawComparisonOp op) {
78
23
    return op == RawComparisonOp::LE ? value <= bound : value >= bound;
79
23
}
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesIhEEbRKT_S4_NS_4simd15RawComparisonOpE
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesIaEEbRKT_S4_NS_4simd15RawComparisonOpE
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesIsEEbRKT_S4_NS_4simd15RawComparisonOpE
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesInEEbRKT_S4_NS_4simd15RawComparisonOpE
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesINS_16VecDateTimeValueEEEbRKT_S5_NS_4simd15RawComparisonOpE
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesINS_11DateV2ValueINS_15DateV2ValueTypeEEEEEbRKT_S7_NS_4simd15RawComparisonOpE
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesINS_11DateV2ValueINS_19DateTimeV2ValueTypeEEEEEbRKT_S7_NS_4simd15RawComparisonOpE
vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesINS_16TimeStampNsValueEEEbRKT_S5_NS_4simd15RawComparisonOpE
Line
Count
Source
77
3
bool topn_raw_scalar_matches(const T& value, const T& bound, RawComparisonOp op) {
78
3
    return op == RawComparisonOp::LE ? value <= bound : value >= bound;
79
3
}
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesINS_16TimestampTzValueEEEbRKT_S5_NS_4simd15RawComparisonOpE
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesIdEEbRKT_S4_NS_4simd15RawComparisonOpE
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesINS_7DecimalIiEEEEbRKT_S6_NS_4simd15RawComparisonOpE
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesINS_7DecimalIlEEEEbRKT_S6_NS_4simd15RawComparisonOpE
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesINS_14DecimalV2ValueEEEbRKT_S5_NS_4simd15RawComparisonOpE
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesINS_12Decimal128V3EEEbRKT_S5_NS_4simd15RawComparisonOpE
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesINS_7DecimalIN4wide7integerILm256EiEEEEEEbRKT_S9_NS_4simd15RawComparisonOpE
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesIjEEbRKT_S4_NS_4simd15RawComparisonOpE
vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123topn_raw_scalar_matchesIoEEbRKT_S4_NS_4simd15RawComparisonOpE
Line
Count
Source
77
20
bool topn_raw_scalar_matches(const T& value, const T& bound, RawComparisonOp op) {
78
20
    return op == RawComparisonOp::LE ? value <= bound : value >= bound;
79
20
}
80
81
template <PrimitiveType PT>
82
void execute_topn_raw_scalar(const uint8_t* values, size_t num_values, const Field& bound,
83
5
                             RawComparisonOp op, uint8_t* matches) {
84
5
    using T = typename PrimitiveTypeTraits<PT>::CppType;
85
5
    const T& typed_bound = bound.get<PT>();
86
28
    for (size_t row = 0; row < num_values; ++row) {
87
23
        T value;
88
23
        std::memcpy(&value, values + row * sizeof(T), sizeof(T));
89
23
        matches[row] &= topn_raw_scalar_matches(value, typed_bound, op) ? 1 : 0;
90
23
    }
91
5
}
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE2EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE3EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE4EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE7EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE11EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE12EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE25EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE26EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE43EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Line
Count
Source
83
1
                             RawComparisonOp op, uint8_t* matches) {
84
1
    using T = typename PrimitiveTypeTraits<PT>::CppType;
85
1
    const T& typed_bound = bound.get<PT>();
86
4
    for (size_t row = 0; row < num_values; ++row) {
87
3
        T value;
88
3
        std::memcpy(&value, values + row * sizeof(T), sizeof(T));
89
3
        matches[row] &= topn_raw_scalar_matches(value, typed_bound, op) ? 1 : 0;
90
3
    }
91
1
}
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE42EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE21EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE27EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE28EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE29EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE20EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE30EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE35EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE36EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Unexecuted instantiation: vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE37EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
vtopn_pred.cpp:_ZN5doris12_GLOBAL__N_123execute_topn_raw_scalarILNS_13PrimitiveTypeE44EEEvPKhmRKNS_5FieldENS_4simd15RawComparisonOpEPh
Line
Count
Source
83
4
                             RawComparisonOp op, uint8_t* matches) {
84
4
    using T = typename PrimitiveTypeTraits<PT>::CppType;
85
4
    const T& typed_bound = bound.get<PT>();
86
24
    for (size_t row = 0; row < num_values; ++row) {
87
20
        T value;
88
20
        std::memcpy(&value, values + row * sizeof(T), sizeof(T));
89
20
        matches[row] &= topn_raw_scalar_matches(value, typed_bound, op) ? 1 : 0;
90
20
    }
91
4
}
92
93
6
bool topn_string_matches(int comparison, RawComparisonOp op) {
94
6
    return op == RawComparisonOp::LE ? comparison <= 0 : comparison >= 0;
95
6
}
96
97
} // namespace
98
99
46
bool VTopNPred::can_execute_on_raw_fixed_values(const DataTypePtr& data_type, int column_id) const {
100
46
    if (_predicate == nullptr || data_type == nullptr || _children.size() != 1) {
101
0
        return false;
102
0
    }
103
46
    const auto slot = std::dynamic_pointer_cast<VSlotRef>(_children[0]);
104
46
    if (slot == nullptr || slot->column_id() != column_id || slot->data_type() == nullptr) {
105
0
        return false;
106
0
    }
107
46
    const auto raw_type = remove_nullable(data_type);
108
46
    return remove_nullable(slot->data_type())->equals(*raw_type) &&
109
46
           topn_raw_value_size(raw_type->get_primitive_type()) != 0;
110
46
}
111
112
Status VTopNPred::execute_on_raw_fixed_values(const uint8_t* values, size_t num_values,
113
                                              size_t value_width, const DataTypePtr& data_type,
114
11
                                              int column_id, uint8_t* matches) const {
115
11
    if (!can_execute_on_raw_fixed_values(data_type, column_id)) {
116
0
        return Status::NotSupported("TopN predicate cannot evaluate raw fixed-width values");
117
0
    }
118
11
    DORIS_CHECK(values != nullptr || num_values == 0);
119
11
    DORIS_CHECK(matches != nullptr || num_values == 0);
120
11
    const auto primitive_type = remove_nullable(data_type)->get_primitive_type();
121
11
    const size_t expected_width = topn_raw_value_size(primitive_type);
122
11
    if (value_width != expected_width) {
123
0
        return Status::Corruption("Raw TopN width {} does not match expected {}", value_width,
124
0
                                  expected_width);
125
0
    }
126
127
    // The bound is mutable and may arrive after reader initialization. Snapshot it once per batch
128
    // so every row observes one monotonic TopN frontier without invalidating cached capability.
129
11
    const Field bound = _predicate->get_value();
130
11
    if (bound.is_null()) {
131
1
        return Status::OK();
132
1
    }
133
10
    if (!expr_zonemap::field_types_compatible(bound.get_type(), primitive_type)) {
134
0
        return Status::InternalError("TopN bound type {} does not match raw value type {}",
135
0
                                     type_to_string(bound.get_type()),
136
0
                                     type_to_string(primitive_type));
137
0
    }
138
10
    const auto op = _predicate->is_asc() ? RawComparisonOp::LE : RawComparisonOp::GE;
139
10
    switch (primitive_type) {
140
5
    case TYPE_INT:
141
5
        execute_topn_raw_comparison<int32_t, TYPE_INT>(values, num_values, bound, op, matches);
142
5
        break;
143
0
    case TYPE_BIGINT:
144
0
        execute_topn_raw_comparison<int64_t, TYPE_BIGINT>(values, num_values, bound, op, matches);
145
0
        break;
146
0
    case TYPE_FLOAT:
147
0
        execute_topn_raw_comparison<float, TYPE_FLOAT>(values, num_values, bound, op, matches);
148
0
        break;
149
0
    case TYPE_DOUBLE:
150
0
        execute_topn_raw_comparison<double, TYPE_DOUBLE>(values, num_values, bound, op, matches);
151
0
        break;
152
0
#define EXECUTE_TOPN_RAW_SCALAR(TYPE)                                          \
153
5
    case TYPE:                                                                 \
154
5
        execute_topn_raw_scalar<TYPE>(values, num_values, bound, op, matches); \
155
5
        break
156
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_BOOLEAN);
157
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_TINYINT);
158
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_SMALLINT);
159
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_LARGEINT);
160
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_DATE);
161
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_DATETIME);
162
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_DATEV2);
163
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_DATETIMEV2);
164
1
        EXECUTE_TOPN_RAW_SCALAR(TYPE_TIMESTAMP_NS);
165
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_TIMESTAMPTZ);
166
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_TIME);
167
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_TIMEV2);
168
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_DECIMAL32);
169
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_DECIMAL64);
170
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_DECIMALV2);
171
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_DECIMAL128I);
172
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_DECIMAL256);
173
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_IPV4);
174
0
        EXECUTE_TOPN_RAW_SCALAR(TYPE_IPV6);
175
4
        EXECUTE_TOPN_RAW_SCALAR(TYPE_UUID);
176
0
#undef EXECUTE_TOPN_RAW_SCALAR
177
0
    default:
178
0
        return Status::NotSupported("TopN raw fixed-width type {} is unsupported",
179
0
                                    type_to_string(primitive_type));
180
10
    }
181
10
    return Status::OK();
182
10
}
183
184
bool VTopNPred::can_execute_on_raw_binary_values(const DataTypePtr& data_type,
185
8
                                                 int column_id) const {
186
8
    if (_predicate == nullptr || data_type == nullptr || _children.size() != 1) {
187
0
        return false;
188
0
    }
189
8
    const auto raw_type = remove_nullable(data_type);
190
8
    const auto raw_primitive_type = raw_type->get_primitive_type();
191
8
    if (!topn_binary_type(raw_primitive_type)) {
192
1
        return false;
193
1
    }
194
7
    const auto slot = std::dynamic_pointer_cast<VSlotRef>(_children[0]);
195
7
    if (slot == nullptr || slot->column_id() != column_id || slot->data_type() == nullptr) {
196
0
        return false;
197
0
    }
198
7
    const auto slot_primitive_type = remove_nullable(slot->data_type())->get_primitive_type();
199
7
    return (is_string_type(raw_primitive_type) && is_string_type(slot_primitive_type)) ||
200
7
           (raw_primitive_type == TYPE_VARBINARY && slot_primitive_type == TYPE_VARBINARY);
201
7
}
202
203
Status VTopNPred::execute_on_raw_binary_values(const StringRef* values, size_t num_values,
204
                                               const DataTypePtr& data_type, int column_id,
205
2
                                               uint8_t* matches) const {
206
2
    if (!can_execute_on_raw_binary_values(data_type, column_id)) {
207
0
        return Status::NotSupported("TopN predicate cannot evaluate raw binary values");
208
0
    }
209
2
    DORIS_CHECK(values != nullptr || num_values == 0);
210
2
    DORIS_CHECK(matches != nullptr || num_values == 0);
211
2
    const Field bound = _predicate->get_value();
212
2
    if (bound.is_null()) {
213
0
        return Status::OK();
214
0
    }
215
2
    const auto primitive_type = remove_nullable(data_type)->get_primitive_type();
216
2
    StringRef bound_ref;
217
2
    if (is_string_type(primitive_type) && is_string_type(bound.get_type())) {
218
1
        const auto& value = bound.get<TYPE_STRING>();
219
1
        bound_ref = StringRef(value.data(), value.size());
220
1
    } else if (primitive_type == TYPE_VARBINARY && bound.get_type() == TYPE_VARBINARY) {
221
1
        bound_ref = bound.get<TYPE_VARBINARY>().to_string_ref();
222
1
    } else {
223
0
        return Status::InternalError("TopN bound type {} does not match raw binary type {}",
224
0
                                     type_to_string(bound.get_type()),
225
0
                                     type_to_string(primitive_type));
226
0
    }
227
2
    const auto op = _predicate->is_asc() ? RawComparisonOp::LE : RawComparisonOp::GE;
228
8
    for (size_t row = 0; row < num_values; ++row) {
229
6
        matches[row] &= topn_string_matches(values[row].compare(bound_ref), op) ? 1 : 0;
230
6
    }
231
2
    return Status::OK();
232
2
}
233
234
43
bool VTopNPred::can_evaluate_dictionary_filter() const {
235
43
    if (_predicate == nullptr || _predicate->nulls_first() || _children.size() != 1) {
236
1
        return false;
237
1
    }
238
42
    const auto slot = std::dynamic_pointer_cast<VSlotRef>(_children[0]);
239
42
    if (slot == nullptr || slot->data_type() == nullptr) {
240
0
        return false;
241
0
    }
242
42
    const auto primitive_type = remove_nullable(slot->data_type())->get_primitive_type();
243
42
    return topn_raw_value_size(primitive_type) != 0 || topn_binary_type(primitive_type);
244
42
}
245
246
7
ZoneMapFilterResult VTopNPred::evaluate_dictionary_filter(const DictionaryEvalContext& ctx) const {
247
7
    if (!can_evaluate_dictionary_filter()) {
248
0
        return ZoneMapFilterResult::kUnsupported;
249
0
    }
250
7
    const auto slot = std::dynamic_pointer_cast<VSlotRef>(_children[0]);
251
7
    DORIS_CHECK(slot != nullptr);
252
7
    const auto* dictionary = ctx.slot(slot->column_id());
253
7
    if (dictionary == nullptr ||
254
7
        !expr_zonemap::data_types_compatible(dictionary->data_type, slot->data_type())) {
255
0
        return ZoneMapFilterResult::kUnsupported;
256
0
    }
257
7
    const Field bound = _predicate->get_value();
258
7
    if (bound.is_null()) {
259
3
        return ZoneMapFilterResult::kMayMatch;
260
3
    }
261
4
    const auto primitive_type = remove_nullable(dictionary->data_type)->get_primitive_type();
262
4
    if (!expr_zonemap::field_types_compatible(bound.get_type(), primitive_type)) {
263
0
        return ZoneMapFilterResult::kUnsupported;
264
0
    }
265
8
    for (const Field& value : dictionary->values) {
266
8
        if (value.is_null()) {
267
0
            continue;
268
0
        }
269
8
        if (!expr_zonemap::field_types_compatible(value.get_type(), primitive_type)) {
270
0
            return ZoneMapFilterResult::kUnsupported;
271
0
        }
272
8
        if ((_predicate->is_asc() && value <= bound) || (!_predicate->is_asc() && value >= bound)) {
273
2
            return ZoneMapFilterResult::kMayMatch;
274
2
        }
275
8
    }
276
2
    return ZoneMapFilterResult::kNoMatch;
277
4
}
278
279
} // namespace doris