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>
|
2019-12-15 06:34:43 +00:00
|
|
|
#include "registerAggregateFunctions.h"
|
2017-12-20 20:58:43 +00:00
|
|
|
|
2017-09-15 11:14:19 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
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
|
|
|
|
{
|
|
|
|
|
2019-01-25 19:35:53 +00:00
|
|
|
struct WithOverflowPolicy
|
|
|
|
{
|
|
|
|
/// Overflow, meaning that the returned type is the same as the input type.
|
|
|
|
static DataTypePtr promoteType(const DataTypePtr & data_type) { return data_type; }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct WithoutOverflowPolicy
|
|
|
|
{
|
|
|
|
/// No overflow, meaning we promote the types if necessary.
|
|
|
|
static DataTypePtr promoteType(const DataTypePtr & data_type)
|
|
|
|
{
|
|
|
|
if (!data_type->canBePromoted())
|
2019-04-10 20:15:44 +00:00
|
|
|
throw Exception{"Values to be summed are expected to be Numeric, Float or Decimal.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
2019-01-25 19:35:53 +00:00
|
|
|
|
|
|
|
return data_type->promoteNumericType();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
using SumMapWithOverflow = AggregateFunctionSumMap<T, WithOverflowPolicy>;
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
using SumMapWithoutOverflow = AggregateFunctionSumMap<T, WithoutOverflowPolicy>;
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
using SumMapFilteredWithOverflow = AggregateFunctionSumMapFiltered<T, WithOverflowPolicy>;
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
using SumMapFilteredWithoutOverflow = AggregateFunctionSumMapFiltered<T, WithoutOverflowPolicy>;
|
|
|
|
|
2019-01-24 08:10:08 +00:00
|
|
|
using SumMapArgs = std::pair<DataTypePtr, DataTypes>;
|
2017-12-20 20:58:43 +00:00
|
|
|
|
2019-01-22 16:47:43 +00:00
|
|
|
SumMapArgs parseArguments(const std::string & name, const DataTypes & arguments)
|
|
|
|
{
|
2017-12-20 20:58:43 +00:00
|
|
|
if (arguments.size() < 2)
|
|
|
|
throw Exception("Aggregate function " + name + " requires at least two arguments of Array type.",
|
2017-09-15 11:14:19 +00:00
|
|
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
2017-12-20 20:58:43 +00:00
|
|
|
const auto * array_type = checkAndGetDataType<DataTypeArray>(arguments[0].get());
|
2017-10-12 04:13:33 +00:00
|
|
|
if (!array_type)
|
|
|
|
throw Exception("First argument for function " + name + " must be an array.",
|
2017-12-20 20:58:43 +00:00
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
2019-01-22 16:47:43 +00:00
|
|
|
|
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;
|
2019-01-24 08:10:08 +00:00
|
|
|
values_types.reserve(arguments.size() - 1);
|
2017-12-20 20:58:43 +00:00
|
|
|
for (size_t i = 1; i < arguments.size(); ++i)
|
|
|
|
{
|
|
|
|
array_type = checkAndGetDataType<DataTypeArray>(arguments[i].get());
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2019-01-24 08:10:08 +00:00
|
|
|
return {std::move(keys_type), std::move(values_types)};
|
2019-01-22 16:47:43 +00:00
|
|
|
}
|
|
|
|
|
2019-01-25 19:35:53 +00:00
|
|
|
template <template <typename> class Function>
|
2019-01-22 16:47:43 +00:00
|
|
|
AggregateFunctionPtr createAggregateFunctionSumMap(const std::string & name, const DataTypes & arguments, const Array & params)
|
|
|
|
{
|
|
|
|
assertNoParameters(name, params);
|
|
|
|
|
|
|
|
auto [keys_type, values_types] = parseArguments(name, arguments);
|
|
|
|
|
2019-02-11 19:26:32 +00:00
|
|
|
AggregateFunctionPtr res(createWithNumericBasedType<Function>(*keys_type, keys_type, values_types, arguments));
|
2018-10-03 14:22:28 +00:00
|
|
|
if (!res)
|
2019-02-12 09:31:20 +00:00
|
|
|
res.reset(createWithDecimalType<Function>(*keys_type, keys_type, values_types, arguments));
|
2020-01-29 15:36:32 +00:00
|
|
|
if (!res)
|
|
|
|
res.reset(createWithStringType<Function>(*keys_type, keys_type, values_types, arguments));
|
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
|
|
|
}
|
|
|
|
|
2019-01-25 19:35:53 +00:00
|
|
|
template <template <typename> class Function>
|
2019-01-22 16:47:43 +00:00
|
|
|
AggregateFunctionPtr createAggregateFunctionSumMapFiltered(const std::string & name, const DataTypes & arguments, const Array & params)
|
|
|
|
{
|
|
|
|
if (params.size() != 1)
|
2019-01-24 12:30:31 +00:00
|
|
|
throw Exception("Aggregate function " + name + " requires exactly one parameter of Array type.",
|
2019-01-22 16:47:43 +00:00
|
|
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
2019-01-24 12:30:31 +00:00
|
|
|
Array keys_to_keep;
|
|
|
|
if (!params.front().tryGet<Array>(keys_to_keep))
|
|
|
|
throw Exception("Aggregate function " + name + " requires an Array as parameter.",
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
2019-01-22 16:47:43 +00:00
|
|
|
|
|
|
|
auto [keys_type, values_types] = parseArguments(name, arguments);
|
|
|
|
|
2019-02-11 19:26:32 +00:00
|
|
|
AggregateFunctionPtr res(createWithNumericBasedType<Function>(*keys_type, keys_type, values_types, keys_to_keep, arguments, params));
|
2019-01-22 16:47:43 +00:00
|
|
|
if (!res)
|
2019-02-12 09:31:20 +00:00
|
|
|
res.reset(createWithDecimalType<Function>(*keys_type, keys_type, values_types, keys_to_keep, arguments, params));
|
2020-01-29 15:36:32 +00:00
|
|
|
if (!res)
|
|
|
|
res.reset(createWithStringType<Function>(*keys_type, keys_type, values_types, keys_to_keep, arguments, params));
|
2019-01-22 16:47:43 +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
|
|
|
}
|
|
|
|
|
|
|
|
void registerAggregateFunctionSumMap(AggregateFunctionFactory & factory)
|
|
|
|
{
|
2019-01-25 19:35:53 +00:00
|
|
|
factory.registerFunction("sumMap", createAggregateFunctionSumMap<SumMapWithoutOverflow>);
|
|
|
|
factory.registerFunction("sumMapWithOverflow", createAggregateFunctionSumMap<SumMapWithOverflow>);
|
|
|
|
factory.registerFunction("sumMapFiltered", createAggregateFunctionSumMapFiltered<SumMapFilteredWithoutOverflow>);
|
|
|
|
factory.registerFunction("sumMapFilteredWithOverflow", createAggregateFunctionSumMapFiltered<SumMapFilteredWithOverflow>);
|
2017-09-15 11:14:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|