ClickHouse

Форк
0
/
AggregateFunctionNull.cpp 
179 строк · 7.6 Кб
1
#include "AggregateFunctionNull.h"
2
#include "AggregateFunctionState.h"
3
#include "AggregateFunctionSimpleState.h"
4
#include "AggregateFunctionCombinatorFactory.h"
5

6
#include <AggregateFunctions/AggregateFunctionNothing.h>
7
#include <AggregateFunctions/AggregateFunctionCount.h>
8
#include <DataTypes/DataTypeNullable.h>
9

10

11
namespace DB
12
{
13

14
namespace ErrorCodes
15
{
16
    extern const int ILLEGAL_TYPE_OF_ARGUMENT;
17
}
18

19
namespace
20
{
21

22
class AggregateFunctionCombinatorNull final : public IAggregateFunctionCombinator
23
{
24
public:
25
    String getName() const override { return "Null"; }
26

27
    bool isForInternalUsageOnly() const override { return true; }
28

29
    DataTypes transformArguments(const DataTypes & arguments) const override
30
    {
31
        size_t size = arguments.size();
32
        DataTypes res(size);
33
        for (size_t i = 0; i < size; ++i)
34
        {
35
            /// Nullable(Nothing) is processed separately, don't convert it to Nothing.
36
            if (arguments[i]->onlyNull())
37
                res[i] = arguments[i];
38
            else
39
                res[i] = removeNullable(arguments[i]);
40
        }
41
        return res;
42
    }
43

44
    template <typename T>
45
    std::optional<AggregateFunctionPtr> tryTransformStateFunctionImpl(const AggregateFunctionPtr & nested_function,
46
                                                       const AggregateFunctionProperties & properties,
47
                                                       const DataTypes & arguments,
48
                                                       const Array & params) const
49
    {
50
        if (const T * function_state = typeid_cast<const T *>(nested_function.get()))
51
        {
52
            auto transformed_nested_function = transformAggregateFunction(function_state->getNestedFunction(), properties, arguments, params);
53

54
            return std::make_shared<T>(
55
                transformed_nested_function,
56
                transformed_nested_function->getArgumentTypes(),
57
                transformed_nested_function->getParameters());
58
        }
59
        return {};
60
    }
61

62
    AggregateFunctionPtr tryTransformStateFunction(const AggregateFunctionPtr & nested_function,
63
                                                   const AggregateFunctionProperties & properties,
64
                                                   const DataTypes & arguments,
65
                                                   const Array & params) const
66
    {
67
        return tryTransformStateFunctionImpl<AggregateFunctionState>(nested_function, properties, arguments, params)
68
            .or_else([&]() { return tryTransformStateFunctionImpl<AggregateFunctionSimpleState>(nested_function, properties, arguments, params); })
69
            .value_or(nullptr);
70
    }
71

72
    AggregateFunctionPtr transformAggregateFunction(
73
        const AggregateFunctionPtr & nested_function,
74
        const AggregateFunctionProperties & properties,
75
        const DataTypes & arguments,
76
        const Array & params) const override
77
    {
78
        bool has_nullable_types = false;
79
        bool has_null_types = false;
80
        std::unordered_set<size_t> arguments_that_can_be_only_null;
81
        if (nested_function)
82
            arguments_that_can_be_only_null = nested_function->getArgumentsThatCanBeOnlyNull();
83

84
        for (size_t i = 0; i < arguments.size(); ++i)
85
        {
86
            if (arguments[i]->isNullable())
87
            {
88
                has_nullable_types = true;
89
                if (arguments[i]->onlyNull() && !arguments_that_can_be_only_null.contains(i))
90
                {
91
                    has_null_types = true;
92
                    break;
93
                }
94
            }
95
        }
96

97
        if (!has_nullable_types)
98
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Aggregate function combinator 'Null' "
99
                            "requires at least one argument to be Nullable");
100

101
        if (has_null_types)
102
        {
103
            /** Some functions, such as `count`, `uniq`, and others, return 0 :: UInt64 instead of NULL for a NULL argument.
104
              * These functions have the `returns_default_when_only_null` property, so we explicitly specify the result type
105
              * when replacing the function with `nothing`.
106
              *
107
              * Note: It's a bit dangerous to have the function result type depend on properties because we do not serialize properties in AST,
108
              * and we can lose this information. For example, when we have `count(NULL)` replaced with `nothing(NULL) as "count(NULL)"` and send it
109
              * to the remote server, the remote server will execute `nothing(NULL)` and return `NULL` while `0` is expected.
110
              *
111
              * To address this, we handle `nothing` in a special way in `FunctionNode::toASTImpl`.
112
              */
113
            if (properties.returns_default_when_only_null)
114
                return std::make_shared<AggregateFunctionNothingUInt64>(arguments, params);
115
            else
116
                return std::make_shared<AggregateFunctionNothingNull>(arguments, params);
117
        }
118

119
        assert(nested_function);
120

121
        if (auto adapter = nested_function->getOwnNullAdapter(nested_function, arguments, params, properties))
122
            return adapter;
123

124
        /// If applied to aggregate function with either -State/-SimpleState combinator, we apply -Null combinator to it's nested_function instead of itself.
125
        /// Because Nullable AggregateFunctionState does not make sense and ruins the logic of managing aggregate function states.
126
        if (const AggregateFunctionPtr new_function = tryTransformStateFunction(nested_function, properties, arguments, params))
127
        {
128
            return new_function;
129
        }
130

131
        bool return_type_is_nullable = !properties.returns_default_when_only_null && nested_function->getResultType()->canBeInsideNullable();
132
        bool serialize_flag = return_type_is_nullable || properties.returns_default_when_only_null;
133

134
        if (arguments.size() == 1)
135
        {
136
            if (return_type_is_nullable)
137
            {
138
                return std::make_shared<AggregateFunctionNullUnary<true, true>>(nested_function, arguments, params);
139
            }
140
            else
141
            {
142
                if (serialize_flag)
143
                    return std::make_shared<AggregateFunctionNullUnary<false, true>>(nested_function, arguments, params);
144
                else
145
                    return std::make_shared<AggregateFunctionNullUnary<false, false>>(nested_function, arguments, params);
146
            }
147
        }
148
        else
149
        {
150
            if (return_type_is_nullable)
151
            {
152
                return std::make_shared<AggregateFunctionNullVariadic<true, true>>(nested_function, arguments, params);
153
            }
154
            else
155
            {
156
                return std::make_shared<AggregateFunctionNullVariadic<false, true>>(nested_function, arguments, params);
157
#if 0
158
                if (serialize_flag)
159
                    return std::make_shared<AggregateFunctionNullVariadic<false, true>>(nested_function, arguments, params);
160
                else
161
                    /// This should be <false, false> (no serialize flag) but it was initially added incorrectly and
162
                    /// changing it would break the binary compatibility of aggregation states using this method
163
                    // (such as AggregateFunction(argMaxOrNull, Nullable(Int64), UInt64)). The extra flag is harmless
164
                    return std::make_shared<AggregateFunctionNullVariadic<false, true>>(nested_function, arguments, params);
165
            }
166
#endif
167
            }
168
        }
169
    }
170
};
171

172
}
173

174
void registerAggregateFunctionCombinatorNull(AggregateFunctionCombinatorFactory & factory)
175
{
176
    factory.registerCombinator(std::make_shared<AggregateFunctionCombinatorNull>());
177
}
178

179
}
180

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.