2017-09-15 11:14:19 +00:00
|
|
|
#include <AggregateFunctions/AggregateFunctionFactory.h>
|
|
|
|
#include <AggregateFunctions/AggregateFunctionSumMap.h>
|
|
|
|
#include <AggregateFunctions/Helpers.h>
|
2017-12-20 20:58:43 +00:00
|
|
|
#include <AggregateFunctions/FactoryHelpers.h>
|
|
|
|
#include <Functions/FunctionHelpers.h>
|
|
|
|
#include <IO/WriteHelpers.h>
|
|
|
|
|
2017-09-15 11:14:19 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
2021-05-26 11:32:14 +00:00
|
|
|
struct Settings;
|
|
|
|
|
2020-02-25 18:10:48 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
|
|
|
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
|
|
|
}
|
2017-09-15 11:14:19 +00:00
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
2020-04-20 15:37:28 +00:00
|
|
|
auto parseArguments(const std::string & name, const DataTypes & arguments)
|
2019-01-22 16:47:43 +00:00
|
|
|
{
|
2020-04-06 11:25:25 +00:00
|
|
|
DataTypes args;
|
2020-04-20 15:37:28 +00:00
|
|
|
bool tuple_argument = false;
|
2020-04-06 11:25:25 +00:00
|
|
|
|
|
|
|
if (arguments.size() == 1)
|
|
|
|
{
|
2020-04-28 14:30:45 +00:00
|
|
|
// sumMap state is fully given by its result, so it can be stored in
|
|
|
|
// SimpleAggregateFunction columns. There is a caveat: it must support
|
|
|
|
// sumMap(sumMap(...)), e.g. it must be able to accept its own output as
|
|
|
|
// an input. This is why it also accepts a Tuple(keys, values) argument.
|
2020-04-06 11:25:25 +00:00
|
|
|
const auto * tuple_type = checkAndGetDataType<DataTypeTuple>(arguments[0].get());
|
|
|
|
if (!tuple_type)
|
|
|
|
throw Exception("When function " + name + " gets one argument it must be a tuple",
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
|
|
|
const auto elems = tuple_type->getElements();
|
|
|
|
args.insert(args.end(), elems.begin(), elems.end());
|
2020-04-20 15:37:28 +00:00
|
|
|
tuple_argument = true;
|
2020-04-06 11:25:25 +00:00
|
|
|
}
|
|
|
|
else
|
2020-04-20 15:37:28 +00:00
|
|
|
{
|
2020-04-06 11:25:25 +00:00
|
|
|
args.insert(args.end(), arguments.begin(), arguments.end());
|
2020-04-20 15:37:28 +00:00
|
|
|
tuple_argument = false;
|
|
|
|
}
|
2020-04-06 11:25:25 +00:00
|
|
|
|
|
|
|
if (args.size() < 2)
|
|
|
|
throw Exception("Aggregate function " + name + " requires at least two arguments of Array type or one argument of tuple of two arrays",
|
2017-09-15 11:14:19 +00:00
|
|
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
2020-04-06 11:25:25 +00:00
|
|
|
const auto * array_type = checkAndGetDataType<DataTypeArray>(args[0].get());
|
2017-10-12 04:13:33 +00:00
|
|
|
if (!array_type)
|
2020-04-06 11:25:25 +00:00
|
|
|
throw Exception("First argument for function " + name + " must be an array, not " + args[0]->getName(),
|
2017-12-20 20:58:43 +00:00
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
2019-01-24 08:10:08 +00:00
|
|
|
DataTypePtr keys_type = array_type->getNestedType();
|
2017-12-20 20:58:43 +00:00
|
|
|
|
|
|
|
DataTypes values_types;
|
2020-04-06 11:25:25 +00:00
|
|
|
values_types.reserve(args.size() - 1);
|
|
|
|
for (size_t i = 1; i < args.size(); ++i)
|
2017-12-20 20:58:43 +00:00
|
|
|
{
|
2020-04-06 11:25:25 +00:00
|
|
|
array_type = checkAndGetDataType<DataTypeArray>(args[i].get());
|
2017-12-20 20:58:43 +00:00
|
|
|
if (!array_type)
|
|
|
|
throw Exception("Argument #" + toString(i) + " for function " + name + " must be an array.",
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
values_types.push_back(array_type->getNestedType());
|
|
|
|
}
|
|
|
|
|
2020-12-25 19:22:42 +00:00
|
|
|
return std::tuple{std::move(keys_type), std::move(values_types), tuple_argument};
|
2019-01-22 16:47:43 +00:00
|
|
|
}
|
|
|
|
|
2020-06-16 10:44:23 +00:00
|
|
|
// This function instantiates a particular overload of the sumMap family of
|
|
|
|
// functions.
|
|
|
|
// The template parameter MappedFunction<bool template_argument> is an aggregate
|
|
|
|
// function template that allows to choose the aggregate function variant that
|
|
|
|
// accepts either normal arguments or tuple argument.
|
|
|
|
template<template <bool tuple_argument> typename MappedFunction>
|
2021-05-26 11:32:14 +00:00
|
|
|
AggregateFunctionPtr createAggregateFunctionMap(const std::string & name, const DataTypes & arguments, const Array & params, const Settings *)
|
2019-01-22 16:47:43 +00:00
|
|
|
{
|
2020-06-16 10:44:23 +00:00
|
|
|
auto [keys_type, values_types, tuple_argument] = parseArguments(name, arguments);
|
2019-01-22 16:47:43 +00:00
|
|
|
|
2020-04-20 15:37:28 +00:00
|
|
|
AggregateFunctionPtr res;
|
|
|
|
if (tuple_argument)
|
|
|
|
{
|
2020-06-16 10:44:23 +00:00
|
|
|
res.reset(createWithNumericBasedType<MappedFunction<true>::template F>(*keys_type, keys_type, values_types, arguments, params));
|
2020-04-20 15:37:28 +00:00
|
|
|
if (!res)
|
2020-06-16 10:44:23 +00:00
|
|
|
res.reset(createWithDecimalType<MappedFunction<true>::template F>(*keys_type, keys_type, values_types, arguments, params));
|
2020-04-20 15:37:28 +00:00
|
|
|
if (!res)
|
2020-06-16 10:44:23 +00:00
|
|
|
res.reset(createWithStringType<MappedFunction<true>::template F>(*keys_type, keys_type, values_types, arguments, params));
|
2020-04-20 15:37:28 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-06-16 10:44:23 +00:00
|
|
|
res.reset(createWithNumericBasedType<MappedFunction<false>::template F>(*keys_type, keys_type, values_types, arguments, params));
|
2020-04-20 15:37:28 +00:00
|
|
|
if (!res)
|
2020-06-16 10:44:23 +00:00
|
|
|
res.reset(createWithDecimalType<MappedFunction<false>::template F>(*keys_type, keys_type, values_types, arguments, params));
|
2020-04-20 15:37:28 +00:00
|
|
|
if (!res)
|
2020-06-16 10:44:23 +00:00
|
|
|
res.reset(createWithStringType<MappedFunction<false>::template F>(*keys_type, keys_type, values_types, arguments, params));
|
2020-04-20 15:37:28 +00:00
|
|
|
}
|
2018-03-22 15:37:24 +00:00
|
|
|
if (!res)
|
|
|
|
throw Exception("Illegal type of argument for aggregate function " + name, ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
|
|
|
return res;
|
2017-09-15 11:14:19 +00:00
|
|
|
}
|
|
|
|
|
2020-06-16 10:44:23 +00:00
|
|
|
// This template chooses the sumMap variant with given filtering and overflow
|
|
|
|
// handling.
|
|
|
|
template <bool filtered, bool overflow>
|
|
|
|
struct SumMapVariants
|
2019-01-22 16:47:43 +00:00
|
|
|
{
|
2020-06-16 10:44:23 +00:00
|
|
|
// SumMapVariants chooses the `overflow` and `filtered` parameters of the
|
|
|
|
// aggregate functions. The `tuple_argument` and the value type `T` are left
|
|
|
|
// as free parameters.
|
|
|
|
// DispatchOnTupleArgument chooses `tuple_argument`, and the value type `T`
|
|
|
|
// is left free.
|
|
|
|
template <bool tuple_argument>
|
|
|
|
struct DispatchOnTupleArgument
|
2020-04-20 15:37:28 +00:00
|
|
|
{
|
2020-06-16 10:44:23 +00:00
|
|
|
template <typename T>
|
|
|
|
using F = std::conditional_t<filtered,
|
|
|
|
AggregateFunctionSumMapFiltered<T, overflow, tuple_argument>,
|
|
|
|
AggregateFunctionSumMap<T, overflow, tuple_argument>>;
|
|
|
|
};
|
|
|
|
};
|
2020-04-20 15:37:28 +00:00
|
|
|
|
2020-06-16 10:44:23 +00:00
|
|
|
// This template gives an aggregate function template that is narrowed
|
2020-08-08 00:47:03 +00:00
|
|
|
// to accept either tuple argumen or normal arguments.
|
2020-06-16 10:44:23 +00:00
|
|
|
template <bool tuple_argument>
|
|
|
|
struct MinMapDispatchOnTupleArgument
|
2020-06-11 10:31:37 +00:00
|
|
|
{
|
2020-06-16 10:44:23 +00:00
|
|
|
template <typename T>
|
|
|
|
using F = AggregateFunctionMinMap<T, tuple_argument>;
|
|
|
|
};
|
2020-06-11 10:31:37 +00:00
|
|
|
|
2020-06-16 10:44:23 +00:00
|
|
|
// This template gives an aggregate function template that is narrowed
|
2020-08-08 00:47:03 +00:00
|
|
|
// to accept either tuple argumen or normal arguments.
|
2020-06-16 10:44:23 +00:00
|
|
|
template <bool tuple_argument>
|
|
|
|
struct MaxMapDispatchOnTupleArgument
|
|
|
|
{
|
|
|
|
template <typename T>
|
|
|
|
using F = AggregateFunctionMaxMap<T, tuple_argument>;
|
|
|
|
};
|
2020-06-11 10:31:37 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-06-16 10:44:23 +00:00
|
|
|
void registerAggregateFunctionSumMap(AggregateFunctionFactory & factory)
|
2020-06-11 10:31:37 +00:00
|
|
|
{
|
2021-05-05 15:11:56 +00:00
|
|
|
// these functions used to be called *Map, with now these names occupied by
|
|
|
|
// Map combinator, which redirects calls here if was called with
|
|
|
|
// array or tuple arguments.
|
|
|
|
factory.registerFunction("sumMappedArrays", createAggregateFunctionMap<
|
2020-06-16 10:44:23 +00:00
|
|
|
SumMapVariants<false, false>::DispatchOnTupleArgument>);
|
2020-06-11 10:31:37 +00:00
|
|
|
|
2021-05-05 15:11:56 +00:00
|
|
|
factory.registerFunction("minMappedArrays",
|
|
|
|
createAggregateFunctionMap<MinMapDispatchOnTupleArgument>);
|
|
|
|
|
|
|
|
factory.registerFunction("maxMappedArrays",
|
|
|
|
createAggregateFunctionMap<MaxMapDispatchOnTupleArgument>);
|
|
|
|
|
|
|
|
// these functions could be renamed to *MappedArrays too, but it would
|
|
|
|
// break backward compatibility
|
2020-06-16 10:44:23 +00:00
|
|
|
factory.registerFunction("sumMapWithOverflow", createAggregateFunctionMap<
|
|
|
|
SumMapVariants<false, true>::DispatchOnTupleArgument>);
|
2020-06-11 10:31:37 +00:00
|
|
|
|
2020-06-16 10:44:23 +00:00
|
|
|
factory.registerFunction("sumMapFiltered", createAggregateFunctionMap<
|
|
|
|
SumMapVariants<true, false>::DispatchOnTupleArgument>);
|
2020-06-11 10:31:37 +00:00
|
|
|
|
2020-06-16 10:44:23 +00:00
|
|
|
factory.registerFunction("sumMapFilteredWithOverflow",
|
|
|
|
createAggregateFunctionMap<
|
|
|
|
SumMapVariants<true, true>::DispatchOnTupleArgument>);
|
2017-09-15 11:14:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|