Coverage Report

Created: 2026-10-15 19:35

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