Coverage Report

Created: 2026-09-08 17:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exec/common/join_op_utils.h
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
#pragma once
19
20
// Lightweight join-op level types split out of join_utils.h so that
21
// exec/pipeline/dependency.h (which holds JoinOpVariants / AsofIndexVariant
22
// members by value) does not have to see the hash-table machinery.
23
// Everything here depends only on thrift enums and std containers.
24
25
#include <gen_cpp/PlanNodes_types.h>
26
#include <pdqsort.h>
27
28
#include <cstdint>
29
#include <variant>
30
#include <vector>
31
32
#include "common/compiler_util.h"
33
34
namespace doris {
35
36
using JoinOpVariants =
37
        std::variant<std::integral_constant<TJoinOp::type, TJoinOp::INNER_JOIN>,
38
                     std::integral_constant<TJoinOp::type, TJoinOp::LEFT_SEMI_JOIN>,
39
                     std::integral_constant<TJoinOp::type, TJoinOp::LEFT_ANTI_JOIN>,
40
                     std::integral_constant<TJoinOp::type, TJoinOp::LEFT_OUTER_JOIN>,
41
                     std::integral_constant<TJoinOp::type, TJoinOp::FULL_OUTER_JOIN>,
42
                     std::integral_constant<TJoinOp::type, TJoinOp::RIGHT_OUTER_JOIN>,
43
                     std::integral_constant<TJoinOp::type, TJoinOp::CROSS_JOIN>,
44
                     std::integral_constant<TJoinOp::type, TJoinOp::RIGHT_SEMI_JOIN>,
45
                     std::integral_constant<TJoinOp::type, TJoinOp::RIGHT_ANTI_JOIN>,
46
                     std::integral_constant<TJoinOp::type, TJoinOp::NULL_AWARE_LEFT_ANTI_JOIN>,
47
                     std::integral_constant<TJoinOp::type, TJoinOp::NULL_AWARE_LEFT_SEMI_JOIN>,
48
                     std::integral_constant<TJoinOp::type, TJoinOp::ASOF_LEFT_INNER_JOIN>,
49
                     std::integral_constant<TJoinOp::type, TJoinOp::ASOF_LEFT_OUTER_JOIN>>;
50
51
509k
inline bool is_asof_join(TJoinOp::type join_op) {
52
509k
    return join_op == TJoinOp::ASOF_LEFT_INNER_JOIN || join_op == TJoinOp::ASOF_LEFT_OUTER_JOIN;
53
509k
}
54
55
template <int JoinOpType>
56
inline constexpr bool is_asof_join_op_v =
57
        JoinOpType == TJoinOp::ASOF_LEFT_INNER_JOIN || JoinOpType == TJoinOp::ASOF_LEFT_OUTER_JOIN;
58
59
template <int JoinOpType>
60
inline constexpr bool is_asof_outer_join_op_v = JoinOpType == TJoinOp::ASOF_LEFT_OUTER_JOIN;
61
62
// ASOF JOIN index with inline values for cache-friendly branchless binary search.
63
// IntType is the integer representation of the ASOF column value:
64
//   uint32_t for DateV2, uint64_t for DateTimeV2 and TimestampTZ,
65
//   int64_t for TimestampNs, and AsofMixedDateTimeKey for exact mixed
66
//   TimestampNs/DateTimeV2 comparisons.
67
// Rows are sorted by asof_value during build, then materialized into SoA arrays
68
// so probe-side binary search only touches the ASOF values hot path.
69
template <typename IntType>
70
struct AsofIndexGroup {
71
    using int_type = IntType;
72
73
    struct Entry {
74
        IntType asof_value;
75
        uint32_t row_index; // 1-based, 0 = invalid/padding
76
    };
77
78
    std::vector<Entry> entries;
79
    std::vector<IntType> asof_values;
80
    std::vector<uint32_t> row_indexes;
81
82
9.63k
    void add_row(IntType value, uint32_t row_idx) { entries.push_back({value, row_idx}); }
_ZN5doris14AsofIndexGroupIoE7add_rowEoj
Line
Count
Source
82
5
    void add_row(IntType value, uint32_t row_idx) { entries.push_back({value, row_idx}); }
_ZN5doris14AsofIndexGroupIjE7add_rowEjj
Line
Count
Source
82
1.12k
    void add_row(IntType value, uint32_t row_idx) { entries.push_back({value, row_idx}); }
_ZN5doris14AsofIndexGroupImE7add_rowEmj
Line
Count
Source
82
8.40k
    void add_row(IntType value, uint32_t row_idx) { entries.push_back({value, row_idx}); }
_ZN5doris14AsofIndexGroupIlE7add_rowElj
Line
Count
Source
82
107
    void add_row(IntType value, uint32_t row_idx) { entries.push_back({value, row_idx}); }
83
84
2.67k
    void sort_and_finalize() {
85
2.67k
        if (entries.empty()) {
86
4
            return;
87
4
        }
88
2.67k
        if (entries.size() > 1) {
89
2.09k
            pdqsort(entries.begin(), entries.end(),
90
24.0k
                    [](const Entry& a, const Entry& b) { return a.asof_value < b.asof_value; });
_ZZN5doris14AsofIndexGroupIoE17sort_and_finalizeEvENKUlRKNS1_5EntryES4_E_clES4_S4_
Line
Count
Source
90
1
                    [](const Entry& a, const Entry& b) { return a.asof_value < b.asof_value; });
_ZZN5doris14AsofIndexGroupIjE17sort_and_finalizeEvENKUlRKNS1_5EntryES4_E_clES4_S4_
Line
Count
Source
90
2.10k
                    [](const Entry& a, const Entry& b) { return a.asof_value < b.asof_value; });
_ZZN5doris14AsofIndexGroupImE17sort_and_finalizeEvENKUlRKNS1_5EntryES4_E_clES4_S4_
Line
Count
Source
90
21.7k
                    [](const Entry& a, const Entry& b) { return a.asof_value < b.asof_value; });
_ZZN5doris14AsofIndexGroupIlE17sort_and_finalizeEvENKUlRKNS1_5EntryES4_E_clES4_S4_
Line
Count
Source
90
201
                    [](const Entry& a, const Entry& b) { return a.asof_value < b.asof_value; });
91
2.09k
        }
92
93
2.67k
        asof_values.resize(entries.size());
94
2.67k
        row_indexes.resize(entries.size());
95
12.3k
        for (size_t i = 0; i < entries.size(); ++i) {
96
9.66k
            asof_values[i] = entries[i].asof_value;
97
9.66k
            row_indexes[i] = entries[i].row_index;
98
9.66k
        }
99
100
2.67k
        std::vector<Entry>().swap(entries);
101
2.67k
    }
_ZN5doris14AsofIndexGroupIoE17sort_and_finalizeEv
Line
Count
Source
84
4
    void sort_and_finalize() {
85
4
        if (entries.empty()) {
86
0
            return;
87
0
        }
88
4
        if (entries.size() > 1) {
89
1
            pdqsort(entries.begin(), entries.end(),
90
1
                    [](const Entry& a, const Entry& b) { return a.asof_value < b.asof_value; });
91
1
        }
92
93
4
        asof_values.resize(entries.size());
94
4
        row_indexes.resize(entries.size());
95
9
        for (size_t i = 0; i < entries.size(); ++i) {
96
5
            asof_values[i] = entries[i].asof_value;
97
5
            row_indexes[i] = entries[i].row_index;
98
5
        }
99
100
4
        std::vector<Entry>().swap(entries);
101
4
    }
_ZN5doris14AsofIndexGroupIjE17sort_and_finalizeEv
Line
Count
Source
84
52
    void sort_and_finalize() {
85
52
        if (entries.empty()) {
86
4
            return;
87
4
        }
88
48
        if (entries.size() > 1) {
89
29
            pdqsort(entries.begin(), entries.end(),
90
29
                    [](const Entry& a, const Entry& b) { return a.asof_value < b.asof_value; });
91
29
        }
92
93
48
        asof_values.resize(entries.size());
94
48
        row_indexes.resize(entries.size());
95
1.16k
        for (size_t i = 0; i < entries.size(); ++i) {
96
1.12k
            asof_values[i] = entries[i].asof_value;
97
1.12k
            row_indexes[i] = entries[i].row_index;
98
1.12k
        }
99
100
48
        std::vector<Entry>().swap(entries);
101
48
    }
_ZN5doris14AsofIndexGroupImE17sort_and_finalizeEv
Line
Count
Source
84
2.59k
    void sort_and_finalize() {
85
2.59k
        if (entries.empty()) {
86
0
            return;
87
0
        }
88
2.59k
        if (entries.size() > 1) {
89
2.03k
            pdqsort(entries.begin(), entries.end(),
90
2.03k
                    [](const Entry& a, const Entry& b) { return a.asof_value < b.asof_value; });
91
2.03k
        }
92
93
2.59k
        asof_values.resize(entries.size());
94
2.59k
        row_indexes.resize(entries.size());
95
11.0k
        for (size_t i = 0; i < entries.size(); ++i) {
96
8.43k
            asof_values[i] = entries[i].asof_value;
97
8.43k
            row_indexes[i] = entries[i].row_index;
98
8.43k
        }
99
100
2.59k
        std::vector<Entry>().swap(entries);
101
2.59k
    }
_ZN5doris14AsofIndexGroupIlE17sort_and_finalizeEv
Line
Count
Source
84
26
    void sort_and_finalize() {
85
26
        if (entries.empty()) {
86
0
            return;
87
0
        }
88
26
        if (entries.size() > 1) {
89
21
            pdqsort(entries.begin(), entries.end(),
90
21
                    [](const Entry& a, const Entry& b) { return a.asof_value < b.asof_value; });
91
21
        }
92
93
26
        asof_values.resize(entries.size());
94
26
        row_indexes.resize(entries.size());
95
133
        for (size_t i = 0; i < entries.size(); ++i) {
96
107
            asof_values[i] = entries[i].asof_value;
97
107
            row_indexes[i] = entries[i].row_index;
98
107
        }
99
100
26
        std::vector<Entry>().swap(entries);
101
26
    }
102
103
821
    const IntType* values_data() const { return asof_values.data(); }
_ZNK5doris14AsofIndexGroupIjE11values_dataEv
Line
Count
Source
103
1
    const IntType* values_data() const { return asof_values.data(); }
_ZNK5doris14AsofIndexGroupImE11values_dataEv
Line
Count
Source
103
816
    const IntType* values_data() const { return asof_values.data(); }
_ZNK5doris14AsofIndexGroupIlE11values_dataEv
Line
Count
Source
103
4
    const IntType* values_data() const { return asof_values.data(); }
Unexecuted instantiation: _ZNK5doris14AsofIndexGroupIoE11values_dataEv
104
105
    // Branchless lower_bound: first i where asof_values[i] >= target
106
466
    ALWAYS_INLINE size_t lower_bound(IntType target) const {
107
466
        size_t lo = 0, n = asof_values.size();
108
2.34k
        while (n > 1) {
109
1.88k
            size_t half = n / 2;
110
1.88k
            lo += half * (asof_values[lo + half] < target);
111
1.88k
            n -= half;
112
1.88k
        }
113
466
        if (lo < asof_values.size()) {
114
465
            lo += (asof_values[lo] < target);
115
465
        }
116
466
        return lo;
117
466
    }
_ZNK5doris14AsofIndexGroupIjE11lower_boundEj
Line
Count
Source
106
33
    ALWAYS_INLINE size_t lower_bound(IntType target) const {
107
33
        size_t lo = 0, n = asof_values.size();
108
163
        while (n > 1) {
109
130
            size_t half = n / 2;
110
130
            lo += half * (asof_values[lo + half] < target);
111
130
            n -= half;
112
130
        }
113
33
        if (lo < asof_values.size()) {
114
32
            lo += (asof_values[lo] < target);
115
32
        }
116
33
        return lo;
117
33
    }
_ZNK5doris14AsofIndexGroupImE11lower_boundEm
Line
Count
Source
106
421
    ALWAYS_INLINE size_t lower_bound(IntType target) const {
107
421
        size_t lo = 0, n = asof_values.size();
108
2.14k
        while (n > 1) {
109
1.72k
            size_t half = n / 2;
110
1.72k
            lo += half * (asof_values[lo + half] < target);
111
1.72k
            n -= half;
112
1.72k
        }
113
421
        if (lo < asof_values.size()) {
114
421
            lo += (asof_values[lo] < target);
115
421
        }
116
421
        return lo;
117
421
    }
_ZNK5doris14AsofIndexGroupIlE11lower_boundEl
Line
Count
Source
106
10
    ALWAYS_INLINE size_t lower_bound(IntType target) const {
107
10
        size_t lo = 0, n = asof_values.size();
108
40
        while (n > 1) {
109
30
            size_t half = n / 2;
110
30
            lo += half * (asof_values[lo + half] < target);
111
30
            n -= half;
112
30
        }
113
10
        if (lo < asof_values.size()) {
114
10
            lo += (asof_values[lo] < target);
115
10
        }
116
10
        return lo;
117
10
    }
_ZNK5doris14AsofIndexGroupIoE11lower_boundEo
Line
Count
Source
106
2
    ALWAYS_INLINE size_t lower_bound(IntType target) const {
107
2
        size_t lo = 0, n = asof_values.size();
108
4
        while (n > 1) {
109
2
            size_t half = n / 2;
110
2
            lo += half * (asof_values[lo + half] < target);
111
2
            n -= half;
112
2
        }
113
2
        if (lo < asof_values.size()) {
114
2
            lo += (asof_values[lo] < target);
115
2
        }
116
2
        return lo;
117
2
    }
118
119
    // Branchless upper_bound: first i where asof_values[i] > target
120
961
    ALWAYS_INLINE size_t upper_bound(IntType target) const {
121
961
        size_t lo = 0, n = asof_values.size();
122
4.11k
        while (n > 1) {
123
3.15k
            size_t half = n / 2;
124
3.15k
            lo += half * (asof_values[lo + half] <= target);
125
3.15k
            n -= half;
126
3.15k
        }
127
961
        if (lo < asof_values.size()) {
128
960
            lo += (asof_values[lo] <= target);
129
960
        }
130
961
        return lo;
131
961
    }
_ZNK5doris14AsofIndexGroupIjE11upper_boundEj
Line
Count
Source
120
41
    ALWAYS_INLINE size_t upper_bound(IntType target) const {
121
41
        size_t lo = 0, n = asof_values.size();
122
215
        while (n > 1) {
123
174
            size_t half = n / 2;
124
174
            lo += half * (asof_values[lo + half] <= target);
125
174
            n -= half;
126
174
        }
127
41
        if (lo < asof_values.size()) {
128
40
            lo += (asof_values[lo] <= target);
129
40
        }
130
41
        return lo;
131
41
    }
_ZNK5doris14AsofIndexGroupImE11upper_boundEm
Line
Count
Source
120
906
    ALWAYS_INLINE size_t upper_bound(IntType target) const {
121
906
        size_t lo = 0, n = asof_values.size();
122
3.85k
        while (n > 1) {
123
2.94k
            size_t half = n / 2;
124
2.94k
            lo += half * (asof_values[lo + half] <= target);
125
2.94k
            n -= half;
126
2.94k
        }
127
906
        if (lo < asof_values.size()) {
128
906
            lo += (asof_values[lo] <= target);
129
906
        }
130
906
        return lo;
131
906
    }
_ZNK5doris14AsofIndexGroupIlE11upper_boundEl
Line
Count
Source
120
11
    ALWAYS_INLINE size_t upper_bound(IntType target) const {
121
11
        size_t lo = 0, n = asof_values.size();
122
41
        while (n > 1) {
123
30
            size_t half = n / 2;
124
30
            lo += half * (asof_values[lo + half] <= target);
125
30
            n -= half;
126
30
        }
127
11
        if (lo < asof_values.size()) {
128
11
            lo += (asof_values[lo] <= target);
129
11
        }
130
11
        return lo;
131
11
    }
_ZNK5doris14AsofIndexGroupIoE11upper_boundEo
Line
Count
Source
120
3
    ALWAYS_INLINE size_t upper_bound(IntType target) const {
121
3
        size_t lo = 0, n = asof_values.size();
122
4
        while (n > 1) {
123
1
            size_t half = n / 2;
124
1
            lo += half * (asof_values[lo + half] <= target);
125
1
            n -= half;
126
1
        }
127
3
        if (lo < asof_values.size()) {
128
3
            lo += (asof_values[lo] <= target);
129
3
        }
130
3
        return lo;
131
3
    }
132
133
    // Semantics by (is_greater, is_strict):
134
    //   (true,  false): probe >= build  ->  find largest  build value <= probe
135
    //   (true,  true):  probe >  build  ->  find largest  build value <  probe
136
    //   (false, false): probe <= build  ->  find smallest build value >= probe
137
    //   (false, true):  probe <  build  ->  find smallest build value >  probe
138
    // Returns the build row index of the best match, or 0 if no match.
139
    template <bool IsGreater, bool IsStrict>
140
1.41k
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
1.41k
        if (asof_values.empty()) {
142
4
            return 0;
143
4
        }
144
1.40k
        if constexpr (IsGreater) {
145
959
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
959
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
959
        } else {
148
450
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
450
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
450
        }
151
1.40k
    }
_ZNK5doris14AsofIndexGroupIjE15find_best_matchILb1ELb1EEEjj
Line
Count
Source
140
15
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
15
        if (asof_values.empty()) {
142
1
            return 0;
143
1
        }
144
14
        if constexpr (IsGreater) {
145
14
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
14
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
        } else {
148
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
        }
151
14
    }
_ZNK5doris14AsofIndexGroupIjE15find_best_matchILb1ELb0EEEjj
Line
Count
Source
140
22
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
22
        if (asof_values.empty()) {
142
1
            return 0;
143
1
        }
144
21
        if constexpr (IsGreater) {
145
21
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
21
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
        } else {
148
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
        }
151
21
    }
_ZNK5doris14AsofIndexGroupIjE15find_best_matchILb0ELb1EEEjj
Line
Count
Source
140
16
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
16
        if (asof_values.empty()) {
142
1
            return 0;
143
1
        }
144
        if constexpr (IsGreater) {
145
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
15
        } else {
148
15
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
15
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
15
        }
151
15
    }
_ZNK5doris14AsofIndexGroupIjE15find_best_matchILb0ELb0EEEjj
Line
Count
Source
140
15
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
15
        if (asof_values.empty()) {
142
1
            return 0;
143
1
        }
144
        if constexpr (IsGreater) {
145
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
14
        } else {
148
14
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
14
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
14
        }
151
14
    }
_ZNK5doris14AsofIndexGroupImE15find_best_matchILb1ELb1EEEjm
Line
Count
Source
140
205
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
205
        if (asof_values.empty()) {
142
0
            return 0;
143
0
        }
144
205
        if constexpr (IsGreater) {
145
205
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
205
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
        } else {
148
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
        }
151
205
    }
_ZNK5doris14AsofIndexGroupImE15find_best_matchILb1ELb0EEEjm
Line
Count
Source
140
704
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
704
        if (asof_values.empty()) {
142
0
            return 0;
143
0
        }
144
704
        if constexpr (IsGreater) {
145
704
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
704
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
        } else {
148
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
        }
151
704
    }
_ZNK5doris14AsofIndexGroupImE15find_best_matchILb0ELb1EEEjm
Line
Count
Source
140
198
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
198
        if (asof_values.empty()) {
142
0
            return 0;
143
0
        }
144
        if constexpr (IsGreater) {
145
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
198
        } else {
148
198
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
198
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
198
        }
151
198
    }
_ZNK5doris14AsofIndexGroupImE15find_best_matchILb0ELb0EEEjm
Line
Count
Source
140
212
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
212
        if (asof_values.empty()) {
142
0
            return 0;
143
0
        }
144
        if constexpr (IsGreater) {
145
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
212
        } else {
148
212
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
212
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
212
        }
151
212
    }
_ZNK5doris14AsofIndexGroupIlE15find_best_matchILb1ELb1EEEjl
Line
Count
Source
140
5
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
5
        if (asof_values.empty()) {
142
0
            return 0;
143
0
        }
144
5
        if constexpr (IsGreater) {
145
5
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
5
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
        } else {
148
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
        }
151
5
    }
_ZNK5doris14AsofIndexGroupIlE15find_best_matchILb1ELb0EEEjl
Line
Count
Source
140
6
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
6
        if (asof_values.empty()) {
142
0
            return 0;
143
0
        }
144
6
        if constexpr (IsGreater) {
145
6
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
6
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
        } else {
148
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
        }
151
6
    }
_ZNK5doris14AsofIndexGroupIlE15find_best_matchILb0ELb1EEEjl
Line
Count
Source
140
5
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
5
        if (asof_values.empty()) {
142
0
            return 0;
143
0
        }
144
        if constexpr (IsGreater) {
145
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
5
        } else {
148
5
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
5
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
5
        }
151
5
    }
_ZNK5doris14AsofIndexGroupIlE15find_best_matchILb0ELb0EEEjl
Line
Count
Source
140
5
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
5
        if (asof_values.empty()) {
142
0
            return 0;
143
0
        }
144
        if constexpr (IsGreater) {
145
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
5
        } else {
148
5
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
5
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
5
        }
151
5
    }
_ZNK5doris14AsofIndexGroupIoE15find_best_matchILb1ELb1EEEjo
Line
Count
Source
140
1
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
1
        if (asof_values.empty()) {
142
0
            return 0;
143
0
        }
144
1
        if constexpr (IsGreater) {
145
1
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
1
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
        } else {
148
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
        }
151
1
    }
_ZNK5doris14AsofIndexGroupIoE15find_best_matchILb1ELb0EEEjo
Line
Count
Source
140
3
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
3
        if (asof_values.empty()) {
142
0
            return 0;
143
0
        }
144
3
        if constexpr (IsGreater) {
145
3
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
3
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
        } else {
148
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
        }
151
3
    }
Unexecuted instantiation: _ZNK5doris14AsofIndexGroupIoE15find_best_matchILb0ELb1EEEjo
_ZNK5doris14AsofIndexGroupIoE15find_best_matchILb0ELb0EEEjo
Line
Count
Source
140
1
    ALWAYS_INLINE uint32_t find_best_match(IntType probe_value) const {
141
1
        if (asof_values.empty()) {
142
0
            return 0;
143
0
        }
144
        if constexpr (IsGreater) {
145
            size_t pos = IsStrict ? lower_bound(probe_value) : upper_bound(probe_value);
146
            return pos > 0 ? row_indexes[pos - 1] : 0;
147
1
        } else {
148
1
            size_t pos = IsStrict ? upper_bound(probe_value) : lower_bound(probe_value);
149
1
            return pos < asof_values.size() ? row_indexes[pos] : 0;
150
1
        }
151
1
    }
152
};
153
154
using AsofMixedDateTimeKey = unsigned __int128;
155
156
// Type-erased container for all ASOF index groups.
157
// DateV2 -> uint32_t, DateTimeV2/TimestampTZ -> uint64_t, TimestampNs -> int64_t.
158
// Mixed TimestampNs/DateTimeV2 uses a wider packed civil key with three extra
159
// nanosecond digits, so neither side is narrowed to the other's physical type.
160
using AsofIndexVariant =
161
        std::variant<std::monostate, std::vector<AsofIndexGroup<uint32_t>>,
162
                     std::vector<AsofIndexGroup<uint64_t>>, std::vector<AsofIndexGroup<int64_t>>,
163
                     std::vector<AsofIndexGroup<AsofMixedDateTimeKey>>>;
164
165
} // namespace doris