Coverage Report

Created: 2026-06-11 22:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exprs/function/if.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/If.cpp
19
// and modified by Doris
20
21
#include "exprs/function/if.h"
22
23
#include <glog/logging.h>
24
#include <stddef.h>
25
26
#include <algorithm>
27
#include <boost/iterator/iterator_facade.hpp>
28
#include <memory>
29
#include <type_traits>
30
#include <utility>
31
32
#include "common/status.h"
33
#include "core/assert_cast.h"
34
#include "core/block/block.h"
35
#include "core/block/column_numbers.h"
36
#include "core/block/column_with_type_and_name.h"
37
#include "core/call_on_type_index.h"
38
#include "core/column/column.h"
39
#include "core/column/column_const.h"
40
#include "core/column/column_nullable.h"
41
#include "core/column/column_vector.h"
42
#include "core/data_type/data_type.h"
43
#include "core/data_type/data_type_date_or_datetime_v2.h"
44
#include "core/data_type/data_type_decimal.h"
45
#include "core/data_type/data_type_ipv4.h"
46
#include "core/data_type/data_type_ipv6.h"
47
#include "core/data_type/data_type_nullable.h"
48
#include "core/data_type/data_type_number.h"
49
#include "core/data_type/data_type_time.h"
50
#include "core/data_type/define_primitive_type.h"
51
#include "core/data_type/primitive_type.h"
52
#include "core/typeid_cast.h"
53
#include "core/types.h"
54
#include "exprs/aggregate/aggregate_function.h"
55
#include "exprs/function/cast_type_to_either.h"
56
#include "exprs/function/function.h"
57
#include "exprs/function/function_helpers.h"
58
#include "exprs/function/simple_function_factory.h"
59
#include "util/simd/bits.h"
60
namespace doris {
61
class FunctionContext;
62
63
namespace NumberTraits {
64
struct Error;
65
} // namespace NumberTraits
66
} // namespace doris
67
68
namespace doris {
69
70
3
size_t count_true_with_notnull(const ColumnPtr& col) {
71
3
    if (col->only_null()) {
72
0
        return 0;
73
0
    }
74
75
3
    if (const auto* const_col = check_and_get_column<ColumnConst>(col.get())) {
76
0
        bool is_true = const_col->get_bool(0);
77
0
        return is_true ? col->size() : 0;
78
0
    }
79
80
3
    auto count = col->size();
81
3
    if (const auto* nullable = check_and_get_column<ColumnNullable>(col.get())) {
82
3
        const auto* __restrict null_data = nullable->get_null_map_data().data();
83
3
        const auto* __restrict bool_data =
84
3
                ((const ColumnUInt8&)(nullable->get_nested_column())).get_data().data();
85
86
3
        size_t null_count = count - simd::count_zero_num((const int8_t*)null_data, count);
87
88
3
        if (null_count == count) {
89
0
            return 0;
90
3
        } else if (null_count == 0) {
91
0
            size_t true_count = count - simd::count_zero_num((const int8_t*)bool_data, count);
92
0
            return true_count;
93
3
        } else {
94
            // In fact, the null_count maybe is different with true_count, but it's no impact
95
3
            return null_count;
96
3
        }
97
3
    } else {
98
0
        const auto* bool_col = assert_cast<const ColumnUInt8*>(col.get());
99
0
        const auto* __restrict bool_data = bool_col->get_data().data();
100
0
        return count - simd::count_zero_num((const int8_t*)bool_data, count);
101
0
    }
102
3
}
103
// todo(wb) support llvm codegen
104
class FunctionIf : public IFunction {
105
public:
106
    static constexpr auto name = "if";
107
108
5
    static FunctionPtr create() { return std::make_shared<FunctionIf>(); }
109
1
    String get_name() const override { return name; }
110
111
3
    size_t get_number_of_arguments() const override { return 3; }
112
6
    bool use_default_implementation_for_nulls() const override { return false; }
113
3
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
114
        // if return type is custom, one of nullable return type will be nullable
115
3
        bool nullable = arguments[1]->is_nullable() || arguments[2]->is_nullable();
116
3
        if (nullable) {
117
3
            return make_nullable(arguments[1]);
118
3
        } else {
119
0
            return arguments[1];
120
0
        }
121
3
    }
122
123
9
    static ColumnPtr materialize_column_if_const(const ColumnPtr& column) {
124
9
        return column->convert_to_full_column_if_const();
125
9
    }
126
127
0
    static ColumnPtr make_nullable_column_if_not(const ColumnPtr& column) {
128
0
        if (is_column_nullable(*column)) return column;
129
130
0
        return ColumnNullable::create(materialize_column_if_const(column),
131
0
                                      ColumnUInt8::create(column->size(), 0));
132
0
    }
133
134
0
    static ColumnPtr get_nested_column(const ColumnPtr& column) {
135
0
        if (auto* nullable = check_and_get_column<ColumnNullable>(*column))
136
0
            return nullable->get_nested_column_ptr();
137
0
        else if (const auto* column_const = check_and_get_column<ColumnConst>(*column))
138
0
            return ColumnConst::create(get_nested_column(column_const->get_data_column_ptr()),
139
0
                                       column->size());
140
141
0
        return column;
142
0
    }
143
144
    Status execute_generic(Block& block, const ColumnUInt8* cond_col,
145
                           const ColumnWithTypeAndName& then_col_type_name,
146
                           const ColumnWithTypeAndName& else_col_type_name, uint32_t result,
147
0
                           size_t input_row_count) const {
148
0
        MutableColumnPtr result_column = block.get_by_position(result).type->create_column();
149
0
        result_column->reserve(input_row_count);
150
151
0
        const IColumn& then_col = *then_col_type_name.column;
152
0
        const IColumn& else_col = *else_col_type_name.column;
153
0
        bool then_is_const = is_column_const(then_col);
154
0
        bool else_is_const = is_column_const(else_col);
155
156
0
        const auto& cond_array = cond_col->get_data();
157
158
0
        if (then_is_const && else_is_const) {
159
0
            const IColumn& then_nested_column =
160
0
                    assert_cast<const ColumnConst&>(then_col).get_data_column();
161
0
            const IColumn& else_nested_column =
162
0
                    assert_cast<const ColumnConst&>(else_col).get_data_column();
163
0
            for (size_t i = 0; i < input_row_count; i++) {
164
0
                if (cond_array[i])
165
0
                    result_column->insert_from(then_nested_column, 0);
166
0
                else
167
0
                    result_column->insert_from(else_nested_column, 0);
168
0
            }
169
0
        } else if (then_is_const) {
170
0
            const IColumn& then_nested_column =
171
0
                    assert_cast<const ColumnConst&>(then_col).get_data_column();
172
173
0
            for (size_t i = 0; i < input_row_count; i++) {
174
0
                if (cond_array[i])
175
0
                    result_column->insert_from(then_nested_column, 0);
176
0
                else
177
0
                    result_column->insert_from(else_col, i);
178
0
            }
179
0
        } else if (else_is_const) {
180
0
            const IColumn& else_nested_column =
181
0
                    assert_cast<const ColumnConst&>(else_col).get_data_column();
182
183
0
            for (size_t i = 0; i < input_row_count; i++) {
184
0
                if (cond_array[i])
185
0
                    result_column->insert_from(then_col, i);
186
0
                else
187
0
                    result_column->insert_from(else_nested_column, 0);
188
0
            }
189
0
        } else {
190
0
            for (size_t i = 0; i < input_row_count; i++) {
191
0
                result_column->insert_from(cond_array[i] ? then_col : else_col, i);
192
0
            }
193
0
        }
194
0
        block.replace_by_position(result, std::move(result_column));
195
0
        return Status::OK();
196
0
    }
197
198
    template <PrimitiveType PType>
199
    Status execute_basic_type(Block& block, const ColumnUInt8* cond_col,
200
                              const ColumnWithTypeAndName& then_col,
201
                              const ColumnWithTypeAndName& else_col, uint32_t result,
202
0
                              Status& status) const {
203
0
        if (then_col.type->get_primitive_type() != else_col.type->get_primitive_type()) {
204
0
            return Status::InternalError(
205
0
                    "then and else column type must be same for function {} , but got {} , {}",
206
0
                    get_name(), then_col.type->get_name(), else_col.type->get_name());
207
0
        }
208
209
0
        auto res_column =
210
0
                NumIfImpl<PType>::execute_if(cond_col->get_data(), then_col.column, else_col.column,
211
0
                                             block.get_by_position(result).type->get_scale());
212
0
        if (!res_column) {
213
0
            return Status::InternalError("unexpected args column {} , {} , of function {}",
214
0
                                         then_col.column->get_name(), else_col.column->get_name(),
215
0
                                         get_name());
216
0
        }
217
0
        block.replace_by_position(result, std::move(res_column));
218
0
        return Status::OK();
219
0
    }
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE2EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE3EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE4EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE5EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE6EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE7EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE8EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE9EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE28EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE29EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE20EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE30EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE35EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE11EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE25EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE26EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE12EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE27EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE42EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE36EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
Unexecuted instantiation: _ZNK5doris10FunctionIf18execute_basic_typeILNS_13PrimitiveTypeE37EEENS_6StatusERNS_5BlockEPKNS_12ColumnVectorILS2_2EEERKNS_21ColumnWithTypeAndNameESC_jRS3_
220
221
    Status execute_for_null_then_else(FunctionContext* context, Block& block,
222
                                      const ColumnWithTypeAndName& arg_cond,
223
                                      const ColumnWithTypeAndName& arg_then,
224
                                      const ColumnWithTypeAndName& arg_else, uint32_t result,
225
3
                                      size_t input_rows_count, bool& handled) const {
226
3
        bool then_is_null = arg_then.column->only_null();
227
3
        bool else_is_null = arg_else.column->only_null();
228
229
3
        handled = false;
230
3
        if (!then_is_null && !else_is_null) {
231
0
            return Status::OK();
232
0
        }
233
234
3
        if (then_is_null && else_is_null) {
235
0
            block.get_by_position(result).column =
236
0
                    block.get_by_position(result).type->create_column_const_with_default_value(
237
0
                            input_rows_count);
238
0
            handled = true;
239
0
            return Status::OK();
240
0
        }
241
242
3
        const auto* cond_col = check_and_get_column<ColumnUInt8>(arg_cond.column.get());
243
3
        const ColumnConst* cond_const_col =
244
3
                check_and_get_column_const<ColumnUInt8>(arg_cond.column.get());
245
246
        /// If then is NULL, we create Nullable column with null mask OR-ed with condition.
247
3
        if (then_is_null) {
248
3
            if (cond_col) {
249
3
                if (is_column_nullable(*arg_else.column)) { // if(cond, null, nullable)
250
3
                    auto arg_else_column = arg_else.column;
251
3
                    auto result_column = (*std::move(arg_else_column)).mutate();
252
3
                    assert_cast<ColumnNullable&>(*result_column)
253
3
                            .apply_null_map(assert_cast<const ColumnUInt8&>(*arg_cond.column));
254
3
                    block.replace_by_position(result, std::move(result_column));
255
3
                } else { // if(cond, null, not_nullable)
256
0
                    block.replace_by_position(
257
0
                            result,
258
0
                            ColumnNullable::create(materialize_column_if_const(arg_else.column),
259
0
                                                   arg_cond.column));
260
0
                }
261
3
            } else if (cond_const_col) {
262
0
                if (cond_const_col->get_value<TYPE_BOOLEAN>()) { // if(true, null, else)
263
0
                    block.get_by_position(result).column =
264
0
                            block.get_by_position(result).type->create_column()->clone_resized(
265
0
                                    input_rows_count);
266
0
                } else { // if(false, null, else)
267
0
                    block.get_by_position(result).column =
268
0
                            make_nullable_column_if_not(arg_else.column);
269
0
                }
270
0
            } else {
271
0
                return Status::InternalError(
272
0
                        "Illegal column {} of first argument of function {}. Must be ColumnUInt8 "
273
0
                        "or ColumnConstUInt8.",
274
0
                        arg_cond.column->get_name(), get_name());
275
0
            }
276
3
        } else { /// If else is NULL, we create Nullable column with null mask OR-ed with negated condition.
277
0
            if (cond_col) {
278
0
                size_t size = input_rows_count;
279
280
0
                if (is_column_nullable(*arg_then.column)) { // if(cond, nullable, NULL)
281
0
                    auto arg_then_column = arg_then.column;
282
0
                    auto result_column = (*std::move(arg_then_column)).mutate();
283
0
                    assert_cast<ColumnNullable&>(*result_column)
284
0
                            .apply_negated_null_map(
285
0
                                    assert_cast<const ColumnUInt8&>(*arg_cond.column));
286
0
                    block.replace_by_position(result, std::move(result_column));
287
0
                } else { // if(cond, not_nullable, NULL)
288
0
                    const auto& null_map_data = cond_col->get_data();
289
0
                    auto negated_null_map = ColumnUInt8::create();
290
0
                    auto& negated_null_map_data = negated_null_map->get_data();
291
0
                    negated_null_map_data.resize(size);
292
293
0
                    for (size_t i = 0; i < size; ++i) {
294
0
                        negated_null_map_data[i] = !null_map_data[i];
295
0
                    }
296
297
0
                    block.replace_by_position(
298
0
                            result,
299
0
                            ColumnNullable::create(materialize_column_if_const(arg_then.column),
300
0
                                                   std::move(negated_null_map)));
301
0
                }
302
0
            } else if (cond_const_col) {
303
0
                if (cond_const_col->get_value<TYPE_BOOLEAN>()) { // if(true, then, NULL)
304
0
                    block.get_by_position(result).column =
305
0
                            make_nullable_column_if_not(arg_then.column);
306
0
                } else { // if(false, then, NULL)
307
0
                    block.get_by_position(result).column =
308
0
                            block.get_by_position(result).type->create_column()->clone_resized(
309
0
                                    input_rows_count);
310
0
                }
311
0
            } else {
312
0
                return Status::InternalError(
313
0
                        "Illegal column {} of first argument of function {}. Must be ColumnUInt8 "
314
0
                        "or ColumnConstUInt8.",
315
0
                        arg_cond.column->get_name(), get_name());
316
0
            }
317
0
        }
318
3
        handled = true;
319
3
        return Status::OK();
320
3
    }
321
322
    Status execute_for_nullable_then_else(FunctionContext* context, Block& block,
323
                                          const ColumnWithTypeAndName& arg_cond,
324
                                          const ColumnWithTypeAndName& arg_then,
325
                                          const ColumnWithTypeAndName& arg_else, uint32_t result,
326
0
                                          size_t input_rows_count, bool& handled) const {
327
0
        auto then_type_is_nullable = arg_then.type->is_nullable();
328
0
        auto else_type_is_nullable = arg_else.type->is_nullable();
329
0
        handled = false;
330
0
        if (!then_type_is_nullable && !else_type_is_nullable) {
331
0
            return Status::OK();
332
0
        }
333
334
0
        auto* then_is_nullable = check_and_get_column<ColumnNullable>(*arg_then.column);
335
0
        auto* else_is_nullable = check_and_get_column<ColumnNullable>(*arg_else.column);
336
0
        bool then_column_is_const_nullable = false;
337
0
        bool else_column_is_const_nullable = false;
338
0
        if (then_type_is_nullable && then_is_nullable == nullptr) {
339
            //this case is a const(nullable column)
340
0
            auto& const_column = assert_cast<const ColumnConst&>(*arg_then.column);
341
0
            then_is_nullable =
342
0
                    assert_cast<const ColumnNullable*>(const_column.get_data_column_ptr().get());
343
0
            then_column_is_const_nullable = true;
344
0
        }
345
346
0
        if (else_type_is_nullable && else_is_nullable == nullptr) {
347
            //this case is a const(nullable column)
348
0
            auto& const_column = assert_cast<const ColumnConst&>(*arg_else.column);
349
0
            else_is_nullable =
350
0
                    assert_cast<const ColumnNullable*>(const_column.get_data_column_ptr().get());
351
0
            else_column_is_const_nullable = true;
352
0
        }
353
354
        /** Calculate null mask of result and nested column separately.
355
          */
356
0
        ColumnPtr result_null_mask;
357
0
        {
358
            // get null map from column:
359
            // a. get_null_map_column_ptr() : it's a real nullable column, so could get it from nullable column
360
            // b. create a const_nullmap_column: it's a not nullable column or a const nullable column, contain a const value
361
0
            Block temporary_block;
362
0
            temporary_block.insert(arg_cond);
363
0
            ColumnPtr then_nested_null_map;
364
0
            if (then_type_is_nullable && !then_column_is_const_nullable) {
365
0
                then_nested_null_map = then_is_nullable->get_null_map_column_ptr();
366
0
            } else {
367
0
                then_nested_null_map =
368
0
                        DataTypeUInt8().create_column_const_with_default_value(input_rows_count);
369
0
            }
370
0
            temporary_block.insert({then_nested_null_map, std::make_shared<DataTypeUInt8>(),
371
0
                                    "then_column_null_map"});
372
373
0
            ColumnPtr else_nested_null_map;
374
0
            if (else_type_is_nullable && !else_column_is_const_nullable) {
375
0
                else_nested_null_map = else_is_nullable->get_null_map_column_ptr();
376
0
            } else {
377
0
                else_nested_null_map =
378
0
                        DataTypeUInt8().create_column_const_with_default_value(input_rows_count);
379
0
            }
380
0
            temporary_block.insert({else_nested_null_map, std::make_shared<DataTypeUInt8>(),
381
0
                                    "else_column_null_map"});
382
0
            temporary_block.insert(
383
0
                    {nullptr, std::make_shared<DataTypeUInt8>(), "result_column_null_map"});
384
385
0
            RETURN_IF_ERROR(_execute_impl_internal(context, temporary_block, {0, 1, 2}, 3,
386
0
                                                   temporary_block.rows()));
387
388
0
            result_null_mask = temporary_block.get_by_position(3).column;
389
0
        }
390
391
0
        ColumnPtr result_nested_column;
392
393
0
        {
394
0
            Block temporary_block(
395
0
                    {arg_cond,
396
0
                     {get_nested_column(arg_then.column), remove_nullable(arg_then.type), ""},
397
0
                     {get_nested_column(arg_else.column), remove_nullable(arg_else.type), ""},
398
0
                     {nullptr, remove_nullable(block.get_by_position(result).type), ""}});
399
400
0
            RETURN_IF_ERROR(_execute_impl_internal(context, temporary_block, {0, 1, 2}, 3,
401
0
                                                   temporary_block.rows()));
402
403
0
            result_nested_column = temporary_block.get_by_position(3).column;
404
0
        }
405
406
0
        auto column = ColumnNullable::create(materialize_column_if_const(result_nested_column),
407
0
                                             materialize_column_if_const(result_null_mask));
408
0
        block.replace_by_position(result, std::move(column));
409
0
        handled = true;
410
0
        return Status::OK();
411
0
    }
412
413
    Status execute_for_null_condition(FunctionContext* context, Block& block,
414
                                      const ColumnNumbers& arguments,
415
                                      const ColumnWithTypeAndName& arg_cond,
416
                                      const ColumnWithTypeAndName& arg_then,
417
                                      const ColumnWithTypeAndName& arg_else, uint32_t result,
418
6
                                      bool& handled) const {
419
6
        bool cond_is_null = arg_cond.column->only_null();
420
6
        handled = false;
421
422
6
        if (cond_is_null) {
423
0
            block.replace_by_position(result,
424
0
                                      arg_else.column->clone_resized(arg_cond.column->size()));
425
0
            handled = true;
426
0
            return Status::OK();
427
0
        }
428
429
6
        if (const auto* nullable = check_and_get_column<ColumnNullable>(*arg_cond.column)) {
430
3
            DCHECK(remove_nullable(arg_cond.type)->get_primitive_type() ==
431
3
                   PrimitiveType::TYPE_BOOLEAN);
432
433
            // update nested column by null map
434
3
            const auto* __restrict null_map = nullable->get_null_map_data().data();
435
3
            auto* __restrict nested_bool_data =
436
3
                    ((ColumnUInt8&)(nullable->get_nested_column())).get_data().data();
437
3
            auto rows = nullable->size();
438
12
            for (size_t i = 0; i < rows; i++) {
439
9
                nested_bool_data[i] &= !null_map[i];
440
9
            }
441
3
            auto column_size = block.columns();
442
3
            block.insert({nullable->get_nested_column_ptr(), remove_nullable(arg_cond.type),
443
3
                          arg_cond.name});
444
445
3
            handled = true;
446
3
            return _execute_impl_internal(context, block, {column_size, arguments[1], arguments[2]},
447
3
                                          result, rows);
448
3
        }
449
3
        return Status::OK();
450
6
    }
451
452
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
453
3
                        uint32_t result, size_t input_rows_count) const override {
454
3
        const ColumnWithTypeAndName& arg_then = block.get_by_position(arguments[1]);
455
3
        const ColumnWithTypeAndName& arg_else = block.get_by_position(arguments[2]);
456
457
        /// A case for identical then and else (pointers are the same).
458
3
        if (arg_then.column.get() == arg_else.column.get()) {
459
            /// Just point result to them.
460
0
            block.replace_by_position(result, arg_then.column);
461
0
            return Status::OK();
462
0
        }
463
464
3
        ColumnWithTypeAndName& cond_column = block.get_by_position(arguments[0]);
465
3
        cond_column.column = materialize_column_if_const(cond_column.column);
466
3
        const ColumnWithTypeAndName& arg_cond = block.get_by_position(arguments[0]);
467
468
3
        auto true_count = count_true_with_notnull(arg_cond.column);
469
3
        auto item_count = arg_cond.column->size();
470
3
        if (true_count == item_count || true_count == 0) {
471
0
            bool result_nullable = block.get_by_position(result).type->is_nullable();
472
0
            if (true_count == item_count) {
473
0
                block.replace_by_position(
474
0
                        result,
475
0
                        result_nullable
476
0
                                ? make_nullable(arg_then.column->clone_resized(input_rows_count))
477
0
                                : arg_then.column->clone_resized(input_rows_count));
478
0
            } else {
479
0
                block.replace_by_position(
480
0
                        result,
481
0
                        result_nullable
482
0
                                ? make_nullable(arg_else.column->clone_resized(input_rows_count))
483
0
                                : arg_else.column->clone_resized(input_rows_count));
484
0
            }
485
0
            return Status::OK();
486
0
        }
487
488
3
        return _execute_impl_internal(context, block, arguments, result, input_rows_count);
489
3
    }
490
491
    Status _execute_impl_internal(FunctionContext* context, Block& block,
492
                                  const ColumnNumbers& arguments, uint32_t result,
493
6
                                  size_t input_rows_count) const {
494
6
        const ColumnWithTypeAndName& arg_then = block.get_by_position(arguments[1]);
495
6
        const ColumnWithTypeAndName& arg_else = block.get_by_position(arguments[2]);
496
6
        ColumnWithTypeAndName& cond_column = block.get_by_position(arguments[0]);
497
6
        cond_column.column = materialize_column_if_const(cond_column.column);
498
6
        const ColumnWithTypeAndName& arg_cond = block.get_by_position(arguments[0]);
499
500
6
        Status ret = Status::OK();
501
6
        bool handled = false;
502
6
        RETURN_IF_ERROR(execute_for_null_condition(context, block, arguments, arg_cond, arg_then,
503
6
                                                   arg_else, result, handled));
504
505
6
        if (!handled) {
506
3
            RETURN_IF_ERROR(execute_for_null_then_else(context, block, arg_cond, arg_then, arg_else,
507
3
                                                       result, input_rows_count, handled));
508
3
        }
509
510
6
        if (!handled) {
511
0
            RETURN_IF_ERROR(execute_for_nullable_then_else(context, block, arg_cond, arg_then,
512
0
                                                           arg_else, result, input_rows_count,
513
0
                                                           handled));
514
0
        }
515
516
6
        if (handled) {
517
6
            return Status::OK();
518
6
        }
519
520
0
        const auto* cond_col = assert_cast<const ColumnUInt8*>(arg_cond.column.get());
521
0
        const ColumnConst* cond_const_col =
522
0
                check_and_get_column_const<ColumnUInt8>(arg_cond.column.get());
523
524
0
        if (cond_const_col) {
525
0
            block.get_by_position(result).column =
526
0
                    cond_const_col->get_value<TYPE_BOOLEAN>() ? arg_then.column : arg_else.column;
527
0
            return Status::OK();
528
0
        }
529
530
0
        Status vec_exec;
531
532
0
        auto call = [&](const auto& type) -> bool {
533
0
            using DataType = std::decay_t<decltype(type)>;
534
0
            vec_exec = execute_basic_type<DataType::PType>(block, cond_col, arg_then, arg_else,
535
0
                                                           result, vec_exec);
536
0
            return true;
537
0
        };
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE2EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE3EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE4EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE5EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE6EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE7EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE8EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE9EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE28EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE29EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE20EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE30EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE35EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE11EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE25EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE26EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE12EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE27EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE42EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE36EEEEEbSC_
Unexecuted instantiation: _ZZNK5doris10FunctionIf22_execute_impl_internalEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlRKT_E_clINS_16DispatchDataTypeILNS_13PrimitiveTypeE37EEEEEbSC_
538
539
0
        auto can_use_vec_exec = dispatch_switch_scalar(arg_then.type->get_primitive_type(), call);
540
0
        if (can_use_vec_exec) {
541
0
            return vec_exec;
542
0
        } else {
543
0
            return execute_generic(block, cond_col, arg_then, arg_else, result, input_rows_count);
544
0
        }
545
0
    }
546
};
547
548
1
void register_function_if(SimpleFunctionFactory& factory) {
549
1
    factory.register_function<FunctionIf>();
550
1
}
551
552
} // namespace doris