Coverage Report

Created: 2026-11-05 22:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/runtime/runtime_predicate.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
#include <functional>
21
#include <memory>
22
#include <mutex>
23
#include <shared_mutex>
24
#include <string>
25
#include <unordered_set>
26
27
#include "common/status.h"
28
#include "core/arena.h"
29
#include "core/binary_cast.hpp"
30
#include "core/data_type/define_primitive_type.h"
31
#include "core/data_type/primitive_type.h"
32
#include "core/field.h"
33
#include "core/types.h"
34
#include "core/value/vdatetime_value.h"
35
#include "storage/olap_scan_common.h"
36
#include "storage/predicate/shared_predicate.h"
37
#include "storage/tablet/tablet_schema.h"
38
39
namespace doris {
40
class ColumnPredicate;
41
42
class RuntimePredicate {
43
public:
44
    RuntimePredicate(const TTopnFilterDesc& desc,
45
                     const std::unordered_set<int32_t>& strict_target_node_ids);
46
47
    Status init_target(int32_t target_node_id,
48
                       phmap::flat_hash_map<int, SlotDescriptor*> slot_id_to_slot_desc,
49
                       const int column_id);
50
51
22.2k
    bool enable() const {
52
        // when sort node and scan node are not in the same fragment, predicate will be disabled
53
22.2k
        std::shared_lock<std::shared_mutex> rlock(_rwlock);
54
22.2k
        return _detected_source && _detected_target;
55
22.2k
    }
56
57
992
    void set_detected_source() {
58
992
        std::unique_lock<std::shared_mutex> wlock(_rwlock);
59
        // Source detection does not reset bounds. Recursive rebuilds call reset_bounds().
60
992
        _detected_source = true;
61
992
    }
62
63
    // Recursive fragment rebuild calls this after the old tasks finish, before new tasks run.
64
    void reset_bounds();
65
66
1.81k
    std::shared_ptr<ColumnPredicate> get_predicate(int32_t target_node_id) {
67
1.81k
        std::shared_lock<std::shared_mutex> rlock(_rwlock);
68
1.81k
        check_target_node_id(target_node_id);
69
1.81k
        return _contexts.find(target_node_id)->second.predicate;
70
1.81k
    }
71
72
    Status update(const Field& value);
73
74
2.77k
    bool has_value() const {
75
2.77k
        std::shared_lock<std::shared_mutex> rlock(_rwlock);
76
2.77k
        return _has_value;
77
2.77k
    }
78
79
1.60k
    Field get_value() const {
80
1.60k
        std::shared_lock<std::shared_mutex> rlock(_rwlock);
81
1.60k
        return _orderby_extrem;
82
1.60k
    }
83
84
13.4k
    std::string get_col_name(int32_t target_node_id) const {
85
13.4k
        check_target_node_id(target_node_id);
86
13.4k
        return _contexts.find(target_node_id)->second.col_name;
87
13.4k
    }
88
89
460
    bool is_asc() const { return _is_asc; }
90
91
2.55k
    bool is_strict(int32_t target_node_id) const {
92
2.55k
        check_target_node_id(target_node_id);
93
2.55k
        return _contexts.find(target_node_id)->second.is_strict;
94
2.55k
    }
95
96
2.34k
    const char* comparison_function(int32_t target_node_id) const {
97
2.34k
        if (_is_asc) {
98
1.74k
            return is_strict(target_node_id) ? "lt" : "le";
99
1.74k
        }
100
603
        return is_strict(target_node_id) ? "gt" : "ge";
101
2.34k
    }
102
103
18
    TExprOpcode::type comparison_opcode(int32_t target_node_id) const {
104
18
        if (_is_asc) {
105
9
            return is_strict(target_node_id) ? TExprOpcode::LT : TExprOpcode::LE;
106
9
        }
107
9
        return is_strict(target_node_id) ? TExprOpcode::GT : TExprOpcode::GE;
108
18
    }
109
110
653
    bool nulls_first() const { return _nulls_first; }
111
112
16.3k
    bool target_is_slot(int32_t target_node_id) const {
113
16.3k
        check_target_node_id(target_node_id);
114
16.3k
        return _contexts.find(target_node_id)->second.target_is_slot();
115
16.3k
    }
116
117
4.60k
    const TExpr& get_texpr(int32_t target_node_id) const {
118
4.60k
        check_target_node_id(target_node_id);
119
4.60k
        return _contexts.find(target_node_id)->second.expr;
120
4.60k
    }
121
122
private:
123
39.3k
    void check_target_node_id(int32_t target_node_id) const {
124
39.3k
        if (!_contexts.contains(target_node_id)) {
125
0
            std::string msg = "context target node ids: [";
126
0
            bool first = true;
127
0
            for (auto p : _contexts) {
128
0
                if (first) {
129
0
                    first = false;
130
0
                } else {
131
0
                    msg += ',';
132
0
                }
133
0
                msg += std::to_string(p.first);
134
0
            }
135
0
            msg += "], input target node is: " + std::to_string(target_node_id);
136
0
            DCHECK(false) << msg;
137
0
        }
138
39.3k
    }
139
    struct TargetContext {
140
        TExpr expr;
141
        // Fixed before QueryContext is published. Targets share a bound, not its inclusiveness.
142
        bool is_strict = false;
143
        std::string col_name;
144
        DataTypePtr col_data_type;
145
        std::shared_ptr<ColumnPredicate> predicate;
146
        std::function<std::shared_ptr<ColumnPredicate>(const int, const std::string&,
147
                                                       const DataTypePtr&, const Field&, bool)>
148
                pred_constructor;
149
150
16.4k
        bool target_is_slot() const {
151
16.4k
            return expr.nodes[0].node_type == TExprNodeType::SLOT_REF &&
152
16.4k
                   expr.nodes[0].slot_ref.is_virtual_slot == false;
153
16.4k
        }
154
    };
155
156
    bool _init(PrimitiveType type);
157
158
    mutable std::shared_mutex _rwlock;
159
160
    bool _nulls_first;
161
    bool _is_asc;
162
    std::map<int32_t, TargetContext> _contexts;
163
164
    Field _orderby_extrem {PrimitiveType::TYPE_NULL};
165
    bool _detected_source = false;
166
    bool _detected_target = false;
167
    bool _has_value = false;
168
    PrimitiveType _type;
169
};
170
171
} // namespace doris