ClickHouse
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
11namespace DB12{
13
14namespace ErrorCodes15{
16extern const int ILLEGAL_TYPE_OF_ARGUMENT;17}
18
19namespace
20{
21
22class AggregateFunctionCombinatorNull final : public IAggregateFunctionCombinator23{
24public:25String getName() const override { return "Null"; }26
27bool isForInternalUsageOnly() const override { return true; }28
29DataTypes transformArguments(const DataTypes & arguments) const override30{31size_t size = arguments.size();32DataTypes res(size);33for (size_t i = 0; i < size; ++i)34{35/// Nullable(Nothing) is processed separately, don't convert it to Nothing.36if (arguments[i]->onlyNull())37res[i] = arguments[i];38else39res[i] = removeNullable(arguments[i]);40}41return res;42}43
44template <typename T>45std::optional<AggregateFunctionPtr> tryTransformStateFunctionImpl(const AggregateFunctionPtr & nested_function,46const AggregateFunctionProperties & properties,47const DataTypes & arguments,48const Array & params) const49{50if (const T * function_state = typeid_cast<const T *>(nested_function.get()))51{52auto transformed_nested_function = transformAggregateFunction(function_state->getNestedFunction(), properties, arguments, params);53
54return std::make_shared<T>(55transformed_nested_function,56transformed_nested_function->getArgumentTypes(),57transformed_nested_function->getParameters());58}59return {};60}61
62AggregateFunctionPtr tryTransformStateFunction(const AggregateFunctionPtr & nested_function,63const AggregateFunctionProperties & properties,64const DataTypes & arguments,65const Array & params) const66{67return tryTransformStateFunctionImpl<AggregateFunctionState>(nested_function, properties, arguments, params)68.or_else([&]() { return tryTransformStateFunctionImpl<AggregateFunctionSimpleState>(nested_function, properties, arguments, params); })69.value_or(nullptr);70}71
72AggregateFunctionPtr transformAggregateFunction(73const AggregateFunctionPtr & nested_function,74const AggregateFunctionProperties & properties,75const DataTypes & arguments,76const Array & params) const override77{78bool has_nullable_types = false;79bool has_null_types = false;80std::unordered_set<size_t> arguments_that_can_be_only_null;81if (nested_function)82arguments_that_can_be_only_null = nested_function->getArgumentsThatCanBeOnlyNull();83
84for (size_t i = 0; i < arguments.size(); ++i)85{86if (arguments[i]->isNullable())87{88has_nullable_types = true;89if (arguments[i]->onlyNull() && !arguments_that_can_be_only_null.contains(i))90{91has_null_types = true;92break;93}94}95}96
97if (!has_nullable_types)98throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Aggregate function combinator 'Null' "99"requires at least one argument to be Nullable");100
101if (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*/
113if (properties.returns_default_when_only_null)114return std::make_shared<AggregateFunctionNothingUInt64>(arguments, params);115else116return std::make_shared<AggregateFunctionNothingNull>(arguments, params);117}118
119assert(nested_function);120
121if (auto adapter = nested_function->getOwnNullAdapter(nested_function, arguments, params, properties))122return 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.126if (const AggregateFunctionPtr new_function = tryTransformStateFunction(nested_function, properties, arguments, params))127{128return new_function;129}130
131bool return_type_is_nullable = !properties.returns_default_when_only_null && nested_function->getResultType()->canBeInsideNullable();132bool serialize_flag = return_type_is_nullable || properties.returns_default_when_only_null;133
134if (arguments.size() == 1)135{136if (return_type_is_nullable)137{138return std::make_shared<AggregateFunctionNullUnary<true, true>>(nested_function, arguments, params);139}140else141{142if (serialize_flag)143return std::make_shared<AggregateFunctionNullUnary<false, true>>(nested_function, arguments, params);144else145return std::make_shared<AggregateFunctionNullUnary<false, false>>(nested_function, arguments, params);146}147}148else149{150if (return_type_is_nullable)151{152return std::make_shared<AggregateFunctionNullVariadic<true, true>>(nested_function, arguments, params);153}154else155{156return std::make_shared<AggregateFunctionNullVariadic<false, true>>(nested_function, arguments, params);157#if 0158if (serialize_flag)159return std::make_shared<AggregateFunctionNullVariadic<false, true>>(nested_function, arguments, params);160else161/// This should be <false, false> (no serialize flag) but it was initially added incorrectly and162/// changing it would break the binary compatibility of aggregation states using this method163// (such as AggregateFunction(argMaxOrNull, Nullable(Int64), UInt64)). The extra flag is harmless164return std::make_shared<AggregateFunctionNullVariadic<false, true>>(nested_function, arguments, params);165}166#endif167}168}169}170};171
172}
173
174void registerAggregateFunctionCombinatorNull(AggregateFunctionCombinatorFactory & factory)175{
176factory.registerCombinator(std::make_shared<AggregateFunctionCombinatorNull>());177}
178
179}
180