ClickHouse
97 строк · 3.2 Кб
1#include <Functions/IFunction.h>
2#include <Functions/FunctionHelpers.h>
3#include <Functions/FunctionFactory.h>
4#include <DataTypes/DataTypesNumber.h>
5#include <DataTypes/DataTypeNullable.h>
6#include <DataTypes/getLeastSupertype.h>
7#include <Core/ColumnNumbers.h>
8#include <Columns/ColumnNullable.h>
9
10
11namespace DB
12{
13namespace
14{
15
16/// Implements the function ifNull which takes 2 arguments and returns
17/// the value of the 1st argument if it is not null. Otherwise it returns
18/// the value of the 2nd argument.
19class FunctionIfNull : public IFunction
20{
21public:
22static constexpr auto name = "ifNull";
23
24explicit FunctionIfNull(ContextPtr context_) : context(context_) {}
25
26static FunctionPtr create(ContextPtr context)
27{
28return std::make_shared<FunctionIfNull>(context);
29}
30
31std::string getName() const override
32{
33return name;
34}
35
36size_t getNumberOfArguments() const override { return 2; }
37bool useDefaultImplementationForNulls() const override { return false; }
38bool useDefaultImplementationForConstants() const override { return true; }
39bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
40ColumnNumbers getArgumentsThatDontImplyNullableReturnType(size_t /*number_of_arguments*/) const override { return {0}; }
41
42DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
43{
44if (arguments[0]->onlyNull())
45return arguments[1];
46
47if (!arguments[0]->isNullable())
48return arguments[0];
49
50return getLeastSupertype(DataTypes{removeNullable(arguments[0]), arguments[1]});
51}
52
53ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
54{
55/// Always null.
56if (arguments[0].type->onlyNull())
57return arguments[1].column;
58
59/// Could not contain nulls, so nullIf makes no sense.
60if (!arguments[0].type->isNullable())
61return arguments[0].column;
62
63/// ifNull(col1, col2) == if(isNotNull(col1), assumeNotNull(col1), col2)
64
65ColumnsWithTypeAndName columns{arguments[0]};
66
67auto is_not_null = FunctionFactory::instance().get("isNotNull", context)->build(columns);
68auto is_not_null_type = std::make_shared<DataTypeUInt8>();
69auto is_not_null_res = is_not_null->execute(columns, is_not_null_type, input_rows_count);
70
71auto assume_not_null = FunctionFactory::instance().get("assumeNotNull", context)->build(columns);
72auto assume_not_null_type = removeNullable(arguments[0].type);
73auto assume_nut_null_res = assume_not_null->execute(columns, assume_not_null_type, input_rows_count);
74
75ColumnsWithTypeAndName if_columns
76{
77{is_not_null_res, is_not_null_type, ""},
78{assume_nut_null_res, assume_not_null_type, ""},
79arguments[1],
80};
81
82auto func_if = FunctionFactory::instance().get("if", context)->build(if_columns);
83return func_if->execute(if_columns, result_type, input_rows_count);
84}
85
86private:
87ContextPtr context;
88};
89
90}
91
92REGISTER_FUNCTION(IfNull)
93{
94factory.registerFunction<FunctionIfNull>({}, FunctionFactory::CaseInsensitive);
95}
96
97}
98