Coverage Report

Created: 2025-03-11 17:58

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