Coverage Report

Created: 2026-05-14 20:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exprs/function/functions_logical.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
// This file is copied from
18
// https://github.com/ClickHouse/ClickHouse/blob/master/src/Functions/FunctionsLogical.cpp
19
// and modified by Doris
20
21
#include "exprs/function/functions_logical.h"
22
23
#include <glog/logging.h>
24
25
#include <algorithm>
26
#include <ranges>
27
#include <utility>
28
29
#include "common/compiler_util.h" // IWYU pragma: keep
30
#include "common/status.h"
31
#include "core/assert_cast.h"
32
#include "core/block/block.h"
33
#include "core/block/column_with_type_and_name.h"
34
#include "core/column/column.h"
35
#include "core/column/column_const.h"
36
#include "core/column/column_nullable.h"
37
#include "core/column/column_vector.h"
38
#include "core/data_type/data_type_nullable.h"
39
#include "core/data_type/data_type_number.h"
40
#include "core/string_ref.h"
41
#include "exprs/aggregate/aggregate_function.h"
42
#include "exprs/function/simple_function_factory.h"
43
44
namespace doris {
45
class FunctionContext;
46
} // namespace doris
47
48
namespace doris {
49
50
namespace {
51
using namespace FunctionsLogicalDetail;
52
53
template <class Op>
54
0
void vector_const(const IColumn* left, const ColumnConst* right, IColumn* res, size_t rows) {
55
0
    const auto* __restrict l_datas = assert_cast<const ColumnUInt8*>(left)->get_data().data();
56
0
    auto r_data = (uint8_t)right->get_bool(0);
57
0
    auto* __restrict res_datas = assert_cast<ColumnUInt8*>(res)->get_data().data();
58
59
0
    for (size_t i = 0; i < rows; ++i) {
60
0
        res_datas[i] = Op::apply(l_datas[i], r_data);
61
0
    }
62
0
}
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_112vector_constINS_22FunctionsLogicalDetail7AndImplEEEvPKNS_7IColumnEPKNS_11ColumnConstEPS4_m
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_112vector_constINS_22FunctionsLogicalDetail6OrImplEEEvPKNS_7IColumnEPKNS_11ColumnConstEPS4_m
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_112vector_constINS_22FunctionsLogicalDetail7XorImplEEEvPKNS_7IColumnEPKNS_11ColumnConstEPS4_m
63
64
template <class Op>
65
0
void vector_vector(const IColumn* left, const IColumn* right, IColumn* res, size_t rows) {
66
0
    const auto* __restrict l_datas = assert_cast<const ColumnUInt8*>(left)->get_data().data();
67
0
    const auto* __restrict r_datas = assert_cast<const ColumnUInt8*>(right)->get_data().data();
68
0
    auto* __restrict res_datas = assert_cast<ColumnUInt8*>(res)->get_data().data();
69
70
0
    for (size_t i = 0; i < rows; ++i) {
71
0
        res_datas[i] = Op::apply(l_datas[i], r_datas[i]);
72
0
    }
73
0
}
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_113vector_vectorINS_22FunctionsLogicalDetail7AndImplEEEvPKNS_7IColumnES6_PS4_m
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_113vector_vectorINS_22FunctionsLogicalDetail6OrImplEEEvPKNS_7IColumnES6_PS4_m
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_113vector_vectorINS_22FunctionsLogicalDetail7XorImplEEEvPKNS_7IColumnES6_PS4_m
74
75
0
std::pair<const IColumn*, ColumnPtr> get_nested_and_null_column(const IColumn* column) {
76
0
    auto null_column = check_and_get_column<const ColumnNullable>(column);
77
0
    if (null_column) {
78
0
        return {null_column->get_nested_column_ptr().get(), null_column->get_null_map_column_ptr()};
79
0
    } else {
80
0
        return {column, ColumnUInt8::create(column->size(), 0)};
81
0
    }
82
0
}
83
84
template <class Op>
85
void vector_const_null(const IColumn* left, const ColumnConst* right, IColumn* res, IColumn* nulls,
86
0
                       size_t rows) {
87
0
    auto [data_column, null_column_ptr] = get_nested_and_null_column(left);
88
0
    const auto* __restrict l_datas =
89
0
            assert_cast<const ColumnUInt8*>(data_column)->get_data().data();
90
0
    const auto* __restrict l_nulls =
91
0
            assert_cast<const ColumnUInt8*>(null_column_ptr.get())->get_data().data();
92
93
0
    auto* __restrict res_datas = assert_cast<ColumnUInt8*>(res)->get_data().data();
94
0
    auto* __restrict res_nulls = assert_cast<ColumnUInt8*>(nulls)->get_data().data();
95
96
0
    auto r_data_ptr = right->get_data_at(0);
97
98
0
    if (r_data_ptr.data == nullptr) {
99
0
        for (size_t i = 0; i < rows; ++i) {
100
0
            res_nulls[i] = Op::apply_null(l_datas[i], l_nulls[i], 1, true);
101
0
            res_datas[i] = Op::apply(l_datas[i], 1);
102
0
        }
103
0
    } else {
104
0
        UInt8 r_data = *(UInt8*)r_data_ptr.data;
105
0
        for (size_t i = 0; i < rows; ++i) {
106
0
            res_nulls[i] = Op::apply_null(l_datas[i], l_nulls[i], r_data, false);
107
0
            res_datas[i] = Op::apply(l_datas[i], r_data);
108
0
        }
109
0
    }
110
0
}
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_117vector_const_nullINS_22FunctionsLogicalDetail7AndImplEEEvPKNS_7IColumnEPKNS_11ColumnConstEPS4_SA_m
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_117vector_const_nullINS_22FunctionsLogicalDetail6OrImplEEEvPKNS_7IColumnEPKNS_11ColumnConstEPS4_SA_m
111
112
template <class Op>
113
void vector_vector_null(const IColumn* left, const IColumn* right, IColumn* res, IColumn* nulls,
114
0
                        size_t rows) {
115
0
    auto [l_datas_ptr, l_nulls_ptr] = get_nested_and_null_column(left);
116
0
    auto [r_datas_ptr, r_nulls_ptr] = get_nested_and_null_column(right);
117
118
0
    const auto* __restrict l_datas =
119
0
            assert_cast<const ColumnUInt8*>(l_datas_ptr)->get_data().data();
120
0
    const auto* __restrict r_datas =
121
0
            assert_cast<const ColumnUInt8*>(r_datas_ptr)->get_data().data();
122
0
    const auto* __restrict l_nulls =
123
0
            assert_cast<const ColumnUInt8*>(l_nulls_ptr.get())->get_data().data();
124
0
    const auto* __restrict r_nulls =
125
0
            assert_cast<const ColumnUInt8*>(r_nulls_ptr.get())->get_data().data();
126
127
0
    auto* __restrict res_datas = assert_cast<ColumnUInt8*>(res)->get_data().data();
128
0
    auto* __restrict res_nulls = assert_cast<ColumnUInt8*>(nulls)->get_data().data();
129
130
0
    for (size_t i = 0; i < rows; ++i) {
131
0
        res_nulls[i] = Op::apply_null(l_datas[i], l_nulls[i], r_datas[i], r_nulls[i]);
132
0
        res_datas[i] = Op::apply(l_datas[i], r_datas[i]);
133
0
    }
134
0
}
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_118vector_vector_nullINS_22FunctionsLogicalDetail7AndImplEEEvPKNS_7IColumnES6_PS4_S7_m
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_118vector_vector_nullINS_22FunctionsLogicalDetail6OrImplEEEvPKNS_7IColumnES6_PS4_S7_m
135
136
template <class Op>
137
void basic_execute_impl(ColumnRawPtrs arguments, ColumnWithTypeAndName& result_info,
138
0
                        size_t input_rows_count) {
139
0
    auto col_res = ColumnUInt8::create(input_rows_count);
140
0
    if (auto l = check_and_get_column<ColumnConst>(arguments[0])) {
141
0
        vector_const<Op>(arguments[1], l.get(), col_res.get(), input_rows_count);
142
0
    } else if (auto r = check_and_get_column<ColumnConst>(arguments[1])) {
143
0
        vector_const<Op>(arguments[0], r.get(), col_res.get(), input_rows_count);
144
0
    } else {
145
0
        vector_vector<Op>(arguments[0], arguments[1], col_res.get(), input_rows_count);
146
0
    }
147
0
    result_info.column = std::move(col_res);
148
0
}
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_118basic_execute_implINS_22FunctionsLogicalDetail7AndImplEEEvSt6vectorIPKNS_7IColumnESaIS7_EERNS_21ColumnWithTypeAndNameEm
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_118basic_execute_implINS_22FunctionsLogicalDetail6OrImplEEEvSt6vectorIPKNS_7IColumnESaIS7_EERNS_21ColumnWithTypeAndNameEm
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_118basic_execute_implINS_22FunctionsLogicalDetail7XorImplEEEvSt6vectorIPKNS_7IColumnESaIS7_EERNS_21ColumnWithTypeAndNameEm
149
150
template <class Op>
151
void null_execute_impl(ColumnRawPtrs arguments, ColumnWithTypeAndName& result_info,
152
0
                       size_t input_rows_count) {
153
0
    auto col_nulls = ColumnUInt8::create(input_rows_count);
154
0
    auto col_res = ColumnUInt8::create(input_rows_count);
155
0
    if (auto l = check_and_get_column<ColumnConst>(arguments[0])) {
156
0
        vector_const_null<Op>(arguments[1], l.get(), col_res.get(), col_nulls.get(),
157
0
                              input_rows_count);
158
0
    } else if (auto r = check_and_get_column<ColumnConst>(arguments[1])) {
159
0
        vector_const_null<Op>(arguments[0], r.get(), col_res.get(), col_nulls.get(),
160
0
                              input_rows_count);
161
0
    } else {
162
0
        vector_vector_null<Op>(arguments[0], arguments[1], col_res.get(), col_nulls.get(),
163
0
                               input_rows_count);
164
0
    }
165
0
    result_info.column = ColumnNullable::create(std::move(col_res), std::move(col_nulls));
166
0
}
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_117null_execute_implINS_22FunctionsLogicalDetail7AndImplEEEvSt6vectorIPKNS_7IColumnESaIS7_EERNS_21ColumnWithTypeAndNameEm
Unexecuted instantiation: functions_logical.cpp:_ZN5doris12_GLOBAL__N_117null_execute_implINS_22FunctionsLogicalDetail6OrImplEEEvSt6vectorIPKNS_7IColumnESaIS7_EERNS_21ColumnWithTypeAndNameEm
167
168
} // namespace
169
170
34
bool is_native_number(PrimitiveType type) {
171
34
    return (is_int_or_bool(type) && type != TYPE_LARGEINT) || is_float_or_double(type);
172
34
}
173
174
template <typename Impl, typename Name>
175
DataTypePtr FunctionAnyArityLogical<Impl, Name>::get_return_type_impl(
176
17
        const DataTypes& arguments) const {
177
17
    if (arguments.size() < 2) {
178
0
        throw doris::Exception(
179
0
                ErrorCode::INVALID_ARGUMENT,
180
0
                "Number of arguments for function \"{}\" should be at least 2: passed {}",
181
0
                get_name(), arguments.size());
182
0
    }
183
184
17
    bool has_nullable_arguments = false;
185
51
    for (size_t i = 0; i < arguments.size(); ++i) {
186
34
        const auto& arg_type = arguments[i];
187
188
34
        if (!has_nullable_arguments) {
189
19
            has_nullable_arguments = arg_type->is_nullable();
190
19
            if (has_nullable_arguments && !Impl::special_implementation_for_nulls()) {
191
0
                LOG(WARNING) << fmt::format(
192
0
                        "Logical error: Unexpected type of argument for function \"{}\" argument "
193
0
                        "{} is of type {}",
194
0
                        get_name(), i + 1, arg_type->get_name());
195
0
            }
196
19
        }
197
198
34
        auto arg_primitive_type = arg_type->get_primitive_type();
199
34
        if (!(is_native_number(arg_primitive_type) ||
200
34
              (Impl::special_implementation_for_nulls() && is_native_number(arg_primitive_type)))) {
201
0
            throw doris::Exception(ErrorCode::INVALID_ARGUMENT,
202
0
                                   "Illegal type ({}) of {} argument of function {}",
203
0
                                   arg_type->get_name(), i + 1, get_name());
204
0
        }
205
34
    }
206
207
17
    auto result_type = std::make_shared<DataTypeUInt8>();
208
17
    return has_nullable_arguments ? make_nullable(result_type) : result_type;
209
17
}
_ZNK5doris22FunctionsLogicalDetail23FunctionAnyArityLogicalINS0_7AndImplENS_7NameAndEE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS9_EE
Line
Count
Source
176
8
        const DataTypes& arguments) const {
177
8
    if (arguments.size() < 2) {
178
0
        throw doris::Exception(
179
0
                ErrorCode::INVALID_ARGUMENT,
180
0
                "Number of arguments for function \"{}\" should be at least 2: passed {}",
181
0
                get_name(), arguments.size());
182
0
    }
183
184
8
    bool has_nullable_arguments = false;
185
24
    for (size_t i = 0; i < arguments.size(); ++i) {
186
16
        const auto& arg_type = arguments[i];
187
188
16
        if (!has_nullable_arguments) {
189
8
            has_nullable_arguments = arg_type->is_nullable();
190
8
            if (has_nullable_arguments && !Impl::special_implementation_for_nulls()) {
191
0
                LOG(WARNING) << fmt::format(
192
0
                        "Logical error: Unexpected type of argument for function \"{}\" argument "
193
0
                        "{} is of type {}",
194
0
                        get_name(), i + 1, arg_type->get_name());
195
0
            }
196
8
        }
197
198
16
        auto arg_primitive_type = arg_type->get_primitive_type();
199
16
        if (!(is_native_number(arg_primitive_type) ||
200
16
              (Impl::special_implementation_for_nulls() && is_native_number(arg_primitive_type)))) {
201
0
            throw doris::Exception(ErrorCode::INVALID_ARGUMENT,
202
0
                                   "Illegal type ({}) of {} argument of function {}",
203
0
                                   arg_type->get_name(), i + 1, get_name());
204
0
        }
205
16
    }
206
207
8
    auto result_type = std::make_shared<DataTypeUInt8>();
208
8
    return has_nullable_arguments ? make_nullable(result_type) : result_type;
209
8
}
_ZNK5doris22FunctionsLogicalDetail23FunctionAnyArityLogicalINS0_6OrImplENS_6NameOrEE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS9_EE
Line
Count
Source
176
9
        const DataTypes& arguments) const {
177
9
    if (arguments.size() < 2) {
178
0
        throw doris::Exception(
179
0
                ErrorCode::INVALID_ARGUMENT,
180
0
                "Number of arguments for function \"{}\" should be at least 2: passed {}",
181
0
                get_name(), arguments.size());
182
0
    }
183
184
9
    bool has_nullable_arguments = false;
185
27
    for (size_t i = 0; i < arguments.size(); ++i) {
186
18
        const auto& arg_type = arguments[i];
187
188
18
        if (!has_nullable_arguments) {
189
11
            has_nullable_arguments = arg_type->is_nullable();
190
11
            if (has_nullable_arguments && !Impl::special_implementation_for_nulls()) {
191
0
                LOG(WARNING) << fmt::format(
192
0
                        "Logical error: Unexpected type of argument for function \"{}\" argument "
193
0
                        "{} is of type {}",
194
0
                        get_name(), i + 1, arg_type->get_name());
195
0
            }
196
11
        }
197
198
18
        auto arg_primitive_type = arg_type->get_primitive_type();
199
18
        if (!(is_native_number(arg_primitive_type) ||
200
18
              (Impl::special_implementation_for_nulls() && is_native_number(arg_primitive_type)))) {
201
0
            throw doris::Exception(ErrorCode::INVALID_ARGUMENT,
202
0
                                   "Illegal type ({}) of {} argument of function {}",
203
0
                                   arg_type->get_name(), i + 1, get_name());
204
0
        }
205
18
    }
206
207
9
    auto result_type = std::make_shared<DataTypeUInt8>();
208
9
    return has_nullable_arguments ? make_nullable(result_type) : result_type;
209
9
}
Unexecuted instantiation: _ZNK5doris22FunctionsLogicalDetail23FunctionAnyArityLogicalINS0_7XorImplENS_7NameXorEE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS9_EE
210
211
template <typename Impl, typename Name>
212
Status FunctionAnyArityLogical<Impl, Name>::execute_impl(FunctionContext* context, Block& block,
213
                                                         const ColumnNumbers& arguments,
214
                                                         uint32_t result_index,
215
0
                                                         size_t input_rows_count) const {
216
0
    ColumnRawPtrs args_in;
217
0
    for (const auto arg_index : arguments)
218
0
        args_in.push_back(block.get_by_position(arg_index).column.get());
219
220
0
    auto& result_info = block.get_by_position(result_index);
221
0
    if constexpr (Impl::special_implementation_for_nulls()) {
222
0
        if (result_info.type->is_nullable()) {
223
0
            null_execute_impl<Impl>(std::move(args_in), result_info, input_rows_count);
224
0
        } else {
225
0
            basic_execute_impl<Impl>(std::move(args_in), result_info, input_rows_count);
226
0
        }
227
0
    } else {
228
0
        DCHECK(std::ranges::all_of(args_in, [](const auto& arg) { return !arg->is_nullable(); }));
229
0
        basic_execute_impl<Impl>(std::move(args_in), result_info, input_rows_count);
230
0
    }
231
0
    return Status::OK();
232
0
}
Unexecuted instantiation: _ZNK5doris22FunctionsLogicalDetail23FunctionAnyArityLogicalINS0_7AndImplENS_7NameAndEE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Unexecuted instantiation: _ZNK5doris22FunctionsLogicalDetail23FunctionAnyArityLogicalINS0_6OrImplENS_6NameOrEE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Unexecuted instantiation: _ZNK5doris22FunctionsLogicalDetail23FunctionAnyArityLogicalINS0_7XorImplENS_7NameXorEE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
233
234
template <PrimitiveType A, typename Op>
235
struct UnaryOperationImpl {
236
    using ArrayA = typename ColumnVector<A>::Container;
237
    using ArrayC = typename ColumnVector<Op::ResultType>::Container;
238
239
0
    static void NO_INLINE vector(const ArrayA& a, ArrayC& c) {
240
0
        std::transform(a.cbegin(), a.cend(), c.begin(), [](const auto x) { return Op::apply(x); });
241
0
    }
242
};
243
244
template <template <PrimitiveType> class Impl, typename Name>
245
DataTypePtr FunctionUnaryLogical<Impl, Name>::get_return_type_impl(
246
0
        const DataTypes& arguments) const {
247
0
    if (!is_native_number(arguments[0]->get_primitive_type())) {
248
0
        throw doris::Exception(ErrorCode::INVALID_ARGUMENT,
249
0
                               "Illegal type ({}) of argument of function {}",
250
0
                               arguments[0]->get_name(), get_name());
251
0
    }
252
253
0
    return std::make_shared<DataTypeUInt8>();
254
0
}
255
256
template <template <PrimitiveType> class Impl, PrimitiveType T>
257
0
bool functionUnaryExecuteType(Block& block, const ColumnNumbers& arguments, size_t result) {
258
0
    if (auto col = check_and_get_column<ColumnVector<T>>(
259
0
                block.get_by_position(arguments[0]).column.get())) {
260
0
        auto col_res = ColumnUInt8::create();
261
262
0
        typename ColumnUInt8::Container& vec_res = col_res->get_data();
263
0
        vec_res.resize(col->get_data().size());
264
0
        UnaryOperationImpl<T, Impl<T>>::vector(col->get_data(), vec_res);
265
266
0
        block.replace_by_position(result, std::move(col_res));
267
0
        return true;
268
0
    }
269
270
0
    return false;
271
0
}
272
273
template <template <PrimitiveType> class Impl, typename Name>
274
Status FunctionUnaryLogical<Impl, Name>::execute_impl(FunctionContext* context, Block& block,
275
                                                      const ColumnNumbers& arguments,
276
                                                      uint32_t result,
277
0
                                                      size_t /*input_rows_count*/) const {
278
0
    if (!functionUnaryExecuteType<Impl, TYPE_BOOLEAN>(block, arguments, result)) {
279
0
        throw doris::Exception(ErrorCode::INVALID_ARGUMENT,
280
0
                               "Illegal column {} of argument of function {}",
281
0
                               block.get_by_position(arguments[0]).column->get_name(), get_name());
282
0
    }
283
284
0
    return Status::OK();
285
0
}
286
287
1
void register_function_logical(SimpleFunctionFactory& instance) {
288
1
    instance.register_function<FunctionAnd>();
289
1
    instance.register_function<FunctionOr>();
290
1
    instance.register_function<FunctionNot>();
291
1
    instance.register_function<FunctionXor>();
292
1
}
293
294
} // namespace doris