Coverage Report

Created: 2026-08-06 12:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exprs/function/function.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/IFunction.cpp
19
// and modified by Doris
20
21
#include "exprs/function/function.h"
22
23
#include <algorithm>
24
#include <memory>
25
#include <numeric>
26
27
#include "common/status.h"
28
#include "core/assert_cast.h"
29
#include "core/column/column.h"
30
#include "core/column/column_const.h"
31
#include "core/column/column_nullable.h"
32
#include "core/column/column_vector.h"
33
#include "core/data_type/data_type_array.h"
34
#include "core/data_type/data_type_nothing.h"
35
#include "core/data_type/data_type_nullable.h"
36
#include "core/data_type/define_primitive_type.h"
37
#include "core/data_type/primitive_type.h"
38
#include "core/field.h"
39
#include "exec/common/util.hpp"
40
#include "exprs/aggregate/aggregate_function.h"
41
#include "exprs/function/function_helpers.h"
42
#include "storage/index/zone_map/zonemap_eval_context.h"
43
44
namespace doris {
45
ColumnPtr wrap_in_nullable(const ColumnPtr& src, const Block& block, const ColumnNumbers& args,
46
                           const NullableColumnInfos& nullable_column_infos,
47
1.82M
                           size_t input_rows_count) {
48
1.82M
    ColumnPtr result_null_map_column;
49
    /// If result is already nullable.
50
1.82M
    ColumnPtr src_not_nullable = src;
51
1.82M
    MutableColumnPtr mutable_result_null_map_column;
52
53
1.82M
    if (auto nullable = check_and_get_column_ptr<ColumnNullable>(src)) {
54
1.06M
        src_not_nullable = nullable->get_nested_column_ptr();
55
1.06M
        result_null_map_column = nullable->get_null_map_column_ptr();
56
1.06M
    }
57
58
2.15M
    for (const auto& arg : args) {
59
2.15M
        const auto& info = nullable_column_infos[arg];
60
2.15M
        if (!info.is_nullable || info.is_const) {
61
342k
            continue;
62
342k
        }
63
64
1.81M
        if (info.has_null) {
65
65.9k
            const auto& null_map_column = block.get_by_position(arg).get_nullable_null_map_column();
66
65.9k
            if (!result_null_map_column) { // NOLINT(bugprone-use-after-move)
67
38.6k
                result_null_map_column = null_map_column;
68
38.6k
                continue;
69
38.6k
            }
70
71
27.2k
            if (!mutable_result_null_map_column) {
72
25.9k
                mutable_result_null_map_column = (*std::move(result_null_map_column)).mutate();
73
25.9k
            }
74
75
27.2k
            NullMap& result_null_map =
76
27.2k
                    assert_cast<ColumnUInt8&>(*mutable_result_null_map_column).get_data();
77
27.2k
            const NullMap& src_null_map = null_map_column->get_data();
78
79
27.2k
            VectorizedUtils::update_null_map(result_null_map, src_null_map);
80
27.2k
        }
81
1.81M
    }
82
83
    // Commit merged null map back: result_null_map_column was moved into
84
    // mutable_result_null_map_column when merging 2+ nullable args with nulls.
85
1.82M
    if (mutable_result_null_map_column) {
86
25.9k
        result_null_map_column = std::move(mutable_result_null_map_column);
87
25.9k
    }
88
89
1.82M
    if (!result_null_map_column) {
90
723k
        if (is_column_const(*src)) {
91
77
            return ColumnConst::create(
92
77
                    make_nullable(assert_cast<const ColumnConst&>(*src).get_data_column_ptr(),
93
77
                                  false),
94
77
                    input_rows_count);
95
77
        }
96
722k
        return ColumnNullable::create(src, ColumnUInt8::create(input_rows_count, 0));
97
723k
    }
98
99
1.10M
    return ColumnNullable::create(src_not_nullable, result_null_map_column);
100
1.82M
}
101
102
ColumnPtr wrap_in_nullable(const ColumnPtr& src, const Block& block, const ColumnNumbers& args,
103
15.5k
                           size_t input_rows_count) {
104
15.5k
    NullableColumnInfos nullable_column_infos(block.columns());
105
31.1k
    for (const auto arg : args) {
106
31.1k
        const auto& column = block.get_by_position(arg);
107
31.1k
        if (column.type->is_nullable()) {
108
15.5k
            nullable_column_infos[arg] = column.get_nullable_column_info();
109
15.5k
        }
110
31.1k
    }
111
15.5k
    return wrap_in_nullable(src, block, args, nullable_column_infos, input_rows_count);
112
15.5k
}
113
114
714k
bool have_null_column(const Block& block, const ColumnNumbers& args) {
115
1.15M
    return std::ranges::any_of(args, [&block](const auto& elem) {
116
1.15M
        return block.get_by_position(elem).type->is_nullable();
117
1.15M
    });
118
714k
}
119
120
603k
bool have_null_column(const ColumnsWithTypeAndName& args) {
121
1.07M
    return std::ranges::any_of(args, [](const auto& elem) { return elem.type->is_nullable(); });
122
603k
}
123
124
inline Status PreparedFunctionImpl::_execute_skipped_constant_deal(FunctionContext* context,
125
                                                                   Block& block,
126
                                                                   const ColumnNumbers& args,
127
                                                                   uint32_t result,
128
2.26M
                                                                   size_t input_rows_count) const {
129
2.26M
    bool executed = false;
130
2.26M
    RETURN_IF_ERROR(default_implementation_for_nulls(context, block, args, result, input_rows_count,
131
2.26M
                                                     &executed));
132
2.26M
    if (executed) {
133
303k
        return Status::OK();
134
303k
    }
135
1.95M
    return execute_impl(context, block, args, result, input_rows_count);
136
2.26M
}
137
138
Status PreparedFunctionImpl::default_implementation_for_constant_arguments(
139
        FunctionContext* context, Block& block, const ColumnNumbers& args, uint32_t result,
140
2.26M
        size_t input_rows_count, bool* executed) const {
141
2.26M
    *executed = false;
142
2.26M
    ColumnNumbers args_expect_const = get_arguments_that_are_always_constant();
143
144
    // Check that these arguments are really constant.
145
2.26M
    for (auto arg_num : args_expect_const) {
146
1.41M
        if (arg_num < args.size() &&
147
1.41M
            !is_column_const(*block.get_by_position(args[arg_num]).column)) {
148
15
            return Status::InvalidArgument("Argument at index {} for function {} must be constant",
149
15
                                           arg_num, get_name());
150
15
        }
151
1.41M
    }
152
153
2.26M
    if (args.empty() || !use_default_implementation_for_constants() ||
154
2.26M
        !VectorizedUtils::all_arguments_are_constant(block, args)) {
155
2.16M
        return Status::OK();
156
2.16M
    }
157
158
    // now all columns are const.
159
91.7k
    Block temporary_block;
160
161
91.7k
    int arguments_size = (int)args.size();
162
218k
    for (size_t arg_num = 0; arg_num < arguments_size; ++arg_num) {
163
127k
        const ColumnWithTypeAndName& column = block.get_by_position(args[arg_num]);
164
        // Columns in const_list --> column_const,    others --> nested_column
165
        // that's because some functions supposes some specific columns always constant.
166
        // If we unpack it, there will be unnecessary cost of virtual judge.
167
127k
        if (args_expect_const.end() !=
168
127k
            std::find(args_expect_const.begin(), args_expect_const.end(), arg_num)) {
169
327
            temporary_block.insert({column.column, column.type, column.name});
170
126k
        } else {
171
126k
            temporary_block.insert(
172
126k
                    {assert_cast<const ColumnConst*>(column.column.get())->get_data_column_ptr(),
173
126k
                     column.type, column.name});
174
126k
        }
175
127k
    }
176
177
91.7k
    temporary_block.insert(block.get_by_position(result));
178
179
91.7k
    ColumnNumbers temporary_argument_numbers(arguments_size);
180
218k
    for (int i = 0; i < arguments_size; ++i) {
181
127k
        temporary_argument_numbers[i] = i;
182
127k
    }
183
184
91.7k
    RETURN_IF_ERROR(_execute_skipped_constant_deal(context, temporary_block,
185
91.7k
                                                   temporary_argument_numbers, arguments_size,
186
91.7k
                                                   temporary_block.rows()));
187
188
90.6k
    ColumnPtr result_column;
189
    /// extremely rare case, when we have function with completely const arguments
190
    /// but some of them produced by non is_deterministic function
191
90.6k
    if (temporary_block.get_by_position(arguments_size).column->size() > 1) {
192
0
        result_column = temporary_block.get_by_position(arguments_size).column->clone_resized(1);
193
90.6k
    } else {
194
90.6k
        result_column = temporary_block.get_by_position(arguments_size).column;
195
90.6k
    }
196
    // We shuold handle the case where the result column is also a ColumnConst.
197
90.6k
    block.get_by_position(result).column = ColumnConst::create(result_column, input_rows_count);
198
90.6k
    *executed = true;
199
90.6k
    return Status::OK();
200
91.7k
}
201
202
Status PreparedFunctionImpl::default_implementation_for_nulls(
203
        FunctionContext* context, Block& block, const ColumnNumbers& args, uint32_t result,
204
2.26M
        size_t input_rows_count, bool* executed) const {
205
2.26M
    *executed = false;
206
2.26M
    if (args.empty() || !use_default_implementation_for_nulls()) {
207
1.54M
        return Status::OK();
208
1.54M
    }
209
210
714k
    if (have_null_column(block, args)) {
211
303k
        NullableColumnInfos nullable_column_infos(block.columns());
212
613k
        for (const auto arg : args) {
213
613k
            const auto& argument = block.get_by_position(arg);
214
613k
            if (!argument.type->is_nullable()) {
215
149k
                continue;
216
149k
            }
217
218
464k
            auto info = argument.get_nullable_column_info();
219
464k
            if (info.only_null) {
220
15.2k
                auto& result_column = block.get_by_position(result);
221
15.2k
                result_column.column =
222
15.2k
                        result_column.type->create_column_const(input_rows_count, Field());
223
15.2k
                *executed = true;
224
15.2k
                return Status::OK();
225
15.2k
            }
226
448k
            nullable_column_infos[arg] = info;
227
448k
        }
228
229
288k
        bool need_to_default = need_replace_null_data_to_default();
230
        // extract nested column from nulls
231
288k
        ColumnNumbers new_args;
232
288k
        Block new_block;
233
234
879k
        for (int i = 0; i < args.size(); ++i) {
235
591k
            uint32_t arg = args[i];
236
591k
            new_args.push_back(i);
237
591k
            new_block.insert(block.get_by_position(arg).unnest_nullable(nullable_column_infos[arg],
238
591k
                                                                        need_to_default));
239
591k
        }
240
288k
        new_block.insert(block.get_by_position(result));
241
288k
        int new_result = new_block.columns() - 1;
242
243
288k
        RETURN_IF_ERROR(default_execute(context, new_block, new_args, new_result, block.rows()));
244
        // After run with nested, wrap them in null. Before this, block.get_by_position(result).type
245
        // is not compatible with get_by_position(result).column
246
247
288k
        block.get_by_position(result).column =
248
288k
                wrap_in_nullable(new_block.get_by_position(new_result).column, block, args,
249
288k
                                 nullable_column_infos, input_rows_count);
250
251
288k
        *executed = true;
252
288k
        return Status::OK();
253
288k
    }
254
410k
    return Status::OK();
255
714k
}
256
257
Status PreparedFunctionImpl::default_execute(FunctionContext* context, Block& block,
258
                                             const ColumnNumbers& args, uint32_t result,
259
2.26M
                                             size_t input_rows_count) const {
260
2.26M
    bool executed = false;
261
262
2.26M
    RETURN_IF_ERROR(default_implementation_for_constant_arguments(context, block, args, result,
263
2.26M
                                                                  input_rows_count, &executed));
264
2.25M
    if (executed) {
265
91.0k
        return Status::OK();
266
91.0k
    }
267
268
2.16M
    return _execute_skipped_constant_deal(context, block, args, result, input_rows_count);
269
2.25M
}
270
271
Status PreparedFunctionImpl::execute(FunctionContext* context, Block& block,
272
                                     const ColumnNumbers& args, uint32_t result,
273
1.97M
                                     size_t input_rows_count) const {
274
1.97M
    return default_execute(context, block, args, result, input_rows_count);
275
1.97M
}
276
277
700k
void FunctionBuilderImpl::check_number_of_arguments(size_t number_of_arguments) const {
278
700k
    if (is_variadic()) {
279
77.5k
        return;
280
77.5k
    }
281
282
622k
    size_t expected_number_of_arguments = get_number_of_arguments();
283
284
622k
    DCHECK_EQ(number_of_arguments, expected_number_of_arguments) << fmt::format(
285
0
            "Number of arguments for function {} doesn't match: passed {} , should be {}",
286
0
            get_name(), number_of_arguments, expected_number_of_arguments);
287
622k
    if (number_of_arguments != expected_number_of_arguments) {
288
0
        throw Exception(
289
0
                ErrorCode::INVALID_ARGUMENT,
290
0
                "Number of arguments for function {} doesn't match: passed {} , should be {}",
291
0
                get_name(), number_of_arguments, expected_number_of_arguments);
292
0
    }
293
622k
}
294
295
702k
DataTypePtr FunctionBuilderImpl::get_return_type(const ColumnsWithTypeAndName& arguments) const {
296
702k
    check_number_of_arguments(arguments.size());
297
298
702k
    if (!arguments.empty() && use_default_implementation_for_nulls()) {
299
1.24M
        if (std::ranges::any_of(arguments, [](const auto& argument) {
300
1.24M
                return argument.type->is_null_literal();
301
1.24M
            })) {
302
12
            return make_nullable(std::make_shared<DataTypeNothing>());
303
12
        }
304
603k
        if (have_null_column(arguments)) {
305
146k
            ColumnNumbers numbers(arguments.size());
306
146k
            std::iota(numbers.begin(), numbers.end(), 0);
307
146k
            auto [nested_block, _] =
308
146k
                    create_block_with_nested_columns(Block(arguments), numbers, false);
309
146k
            auto return_type = get_return_type_impl(
310
146k
                    ColumnsWithTypeAndName(nested_block.begin(), nested_block.end()));
311
146k
            if (!return_type) {
312
0
                return nullptr;
313
0
            }
314
146k
            return make_nullable(return_type);
315
146k
        }
316
603k
    }
317
318
556k
    return get_return_type_impl(arguments);
319
702k
}
320
321
bool FunctionBuilderImpl::is_date_or_datetime_or_decimal(
322
2.67k
        const DataTypePtr& return_type, const DataTypePtr& func_return_type) const {
323
2.67k
    return (is_date_or_datetime(return_type->get_primitive_type()) &&
324
2.67k
            is_date_or_datetime(func_return_type->get_primitive_type())) ||
325
2.67k
           (is_date_v2_or_datetime_v2(return_type->get_primitive_type()) &&
326
2.67k
            is_date_v2_or_datetime_v2(func_return_type->get_primitive_type())) ||
327
           // For some date functions such as str_to_date(string, string), return_type will
328
           // be datetimev2 if users enable datev2 but get_return_type(arguments) will still
329
           // return datetime. We need keep backward compatibility here.
330
2.67k
           (is_date_v2_or_datetime_v2(return_type->get_primitive_type()) &&
331
1.78k
            is_date_or_datetime(func_return_type->get_primitive_type())) ||
332
2.67k
           (is_date_or_datetime(return_type->get_primitive_type()) &&
333
1.75k
            is_date_v2_or_datetime_v2(func_return_type->get_primitive_type())) ||
334
2.67k
           (is_decimal(return_type->get_primitive_type()) &&
335
1.75k
            is_decimal(func_return_type->get_primitive_type())) ||
336
2.67k
           (is_time_type(return_type->get_primitive_type()) &&
337
530
            is_time_type(func_return_type->get_primitive_type()));
338
2.67k
}
339
340
602
bool contains_date_or_datetime_or_decimal(const DataTypePtr& type) {
341
602
    auto type_ptr = type->is_nullable() ? ((DataTypeNullable*)type.get())->get_nested_type() : type;
342
343
602
    switch (type_ptr->get_primitive_type()) {
344
11
    case TYPE_ARRAY: {
345
11
        const auto* array_type = assert_cast<const DataTypeArray*>(type_ptr.get());
346
11
        return contains_date_or_datetime_or_decimal(array_type->get_nested_type());
347
0
    }
348
0
    case TYPE_MAP: {
349
0
        const auto* map_type = assert_cast<const DataTypeMap*>(type_ptr.get());
350
0
        return contains_date_or_datetime_or_decimal(map_type->get_key_type()) ||
351
0
               contains_date_or_datetime_or_decimal(map_type->get_value_type());
352
0
    }
353
34
    case TYPE_STRUCT: {
354
34
        const auto* struct_type = assert_cast<const DataTypeStruct*>(type_ptr.get());
355
34
        const auto& elements = struct_type->get_elements();
356
74
        return std::ranges::any_of(elements, [](const DataTypePtr& element) {
357
74
            return contains_date_or_datetime_or_decimal(element);
358
74
        });
359
0
    }
360
557
    default:
361
        // For scalar types, check if it's date/datetime/decimal
362
557
        return is_date_or_datetime(type_ptr->get_primitive_type()) ||
363
557
               is_date_v2_or_datetime_v2(type_ptr->get_primitive_type()) ||
364
557
               is_decimal(type_ptr->get_primitive_type()) ||
365
557
               is_time_type(type_ptr->get_primitive_type());
366
602
    }
367
602
}
368
369
// make sure array/map/struct and nested  array/map/struct can be check
370
bool FunctionBuilderImpl::is_nested_type_date_or_datetime_or_decimal(
371
519
        const DataTypePtr& return_type, const DataTypePtr& func_return_type) const {
372
519
    auto return_type_ptr = return_type->is_nullable()
373
519
                                   ? ((DataTypeNullable*)return_type.get())->get_nested_type()
374
519
                                   : return_type;
375
519
    auto func_return_type_ptr =
376
519
            func_return_type->is_nullable()
377
519
                    ? ((DataTypeNullable*)func_return_type.get())->get_nested_type()
378
519
                    : func_return_type;
379
    // make sure that map/struct/array also need to check
380
519
    if (return_type_ptr->get_primitive_type() != func_return_type_ptr->get_primitive_type()) {
381
2
        return false;
382
2
    }
383
384
    // Check if this type contains date/datetime/decimal types
385
517
    if (!contains_date_or_datetime_or_decimal(return_type_ptr)) {
386
        // If no date/datetime/decimal types, just pass through
387
493
        return true;
388
493
    }
389
390
    // If contains date/datetime/decimal types, recursively check each element
391
24
    switch (return_type_ptr->get_primitive_type()) {
392
11
    case TYPE_ARRAY: {
393
11
        auto nested_return_type = remove_nullable(
394
11
                (assert_cast<const DataTypeArray*>(return_type_ptr.get()))->get_nested_type());
395
11
        auto nested_func_type = remove_nullable(
396
11
                (assert_cast<const DataTypeArray*>(func_return_type_ptr.get()))->get_nested_type());
397
11
        return is_nested_type_date_or_datetime_or_decimal(nested_return_type, nested_func_type);
398
0
    }
399
0
    case TYPE_MAP: {
400
0
        const auto* return_map = assert_cast<const DataTypeMap*>(return_type_ptr.get());
401
0
        const auto* func_map = assert_cast<const DataTypeMap*>(func_return_type_ptr.get());
402
403
0
        auto key_return = remove_nullable(return_map->get_key_type());
404
0
        auto key_func = remove_nullable(func_map->get_key_type());
405
0
        auto value_return = remove_nullable(return_map->get_value_type());
406
0
        auto value_func = remove_nullable(func_map->get_value_type());
407
408
0
        return is_nested_type_date_or_datetime_or_decimal(key_return, key_func) &&
409
0
               is_nested_type_date_or_datetime_or_decimal(value_return, value_func);
410
0
    }
411
1
    case TYPE_STRUCT: {
412
1
        const auto* return_struct = assert_cast<const DataTypeStruct*>(return_type_ptr.get());
413
1
        const auto* func_struct = assert_cast<const DataTypeStruct*>(func_return_type_ptr.get());
414
415
1
        auto return_elements = return_struct->get_elements();
416
1
        auto func_elements = func_struct->get_elements();
417
418
1
        if (return_elements.size() != func_elements.size()) {
419
0
            return false;
420
0
        }
421
422
5
        for (size_t i = 0; i < return_elements.size(); i++) {
423
4
            auto elem_return = remove_nullable(return_elements[i]);
424
4
            auto elem_func = remove_nullable(func_elements[i]);
425
426
4
            if (!is_nested_type_date_or_datetime_or_decimal(elem_return, elem_func)) {
427
0
                return false;
428
0
            }
429
4
        }
430
1
        return true;
431
1
    }
432
12
    default:
433
12
        return is_date_or_datetime_or_decimal(return_type_ptr, func_return_type_ptr);
434
24
    }
435
24
}
436
437
ZoneMapFilterResult IFunctionBase::evaluate_zonemap_filter(
438
0
        const ZoneMapEvalContext& ctx, const VExprSPtrs& function_arguments) const {
439
0
    return unsupported_zonemap_filter(ctx);
440
0
}
441
442
ZoneMapFilterResult IFunctionBase::evaluate_dictionary_filter(
443
0
        const DictionaryEvalContext& ctx, const VExprSPtrs& function_arguments) const {
444
0
    return ZoneMapFilterResult::kUnsupported;
445
0
}
446
447
ZoneMapFilterResult IFunctionBase::evaluate_bloom_filter(
448
0
        const BloomFilterEvalContext& ctx, const VExprSPtrs& function_arguments) const {
449
0
    return ZoneMapFilterResult::kUnsupported;
450
0
}
451
452
} // namespace doris