1#include <AggregateFunctions/AggregateFunctionFactory.h>
2#include <AggregateFunctions/AggregateFunctionGroupUniqArray.h>
3#include <AggregateFunctions/Helpers.h>
4#include <AggregateFunctions/FactoryHelpers.h>
5#include <DataTypes/DataTypeDate.h>
6#include <DataTypes/DataTypeDateTime.h>
7#include "registerAggregateFunctions.h"
8
9
10namespace DB
11{
12
13namespace ErrorCodes
14{
15 extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
16 extern const int BAD_ARGUMENTS;
17}
18
19namespace
20{
21
22/// Substitute return type for Date and DateTime
23template <typename has_limit>
24class AggregateFunctionGroupUniqArrayDate : public AggregateFunctionGroupUniqArray<DataTypeDate::FieldType, has_limit>
25{
26public:
27 AggregateFunctionGroupUniqArrayDate(const DataTypePtr & argument_type, UInt64 max_elems_ = std::numeric_limits<UInt64>::max()) : AggregateFunctionGroupUniqArray<DataTypeDate::FieldType, has_limit>(argument_type, max_elems_) {}
28 DataTypePtr getReturnType() const override { return std::make_shared<DataTypeArray>(std::make_shared<DataTypeDate>()); }
29};
30
31template <typename has_limit>
32class AggregateFunctionGroupUniqArrayDateTime : public AggregateFunctionGroupUniqArray<DataTypeDateTime::FieldType, has_limit>
33{
34public:
35 AggregateFunctionGroupUniqArrayDateTime(const DataTypePtr & argument_type, UInt64 max_elems_ = std::numeric_limits<UInt64>::max()) : AggregateFunctionGroupUniqArray<DataTypeDateTime::FieldType, has_limit>(argument_type, max_elems_) {}
36 DataTypePtr getReturnType() const override { return std::make_shared<DataTypeArray>(std::make_shared<DataTypeDateTime>()); }
37};
38
39template <typename has_limit, typename ... TArgs>
40static IAggregateFunction * createWithExtraTypes(const DataTypePtr & argument_type, TArgs && ... args)
41{
42 WhichDataType which(argument_type);
43 if (which.idx == TypeIndex::Date) return new AggregateFunctionGroupUniqArrayDate<has_limit>(argument_type, std::forward<TArgs>(args)...);
44 else if (which.idx == TypeIndex::DateTime) return new AggregateFunctionGroupUniqArrayDateTime<has_limit>(argument_type, std::forward<TArgs>(args)...);
45 else
46 {
47 /// Check that we can use plain version of AggregateFunctionGroupUniqArrayGeneric
48 if (argument_type->isValueUnambiguouslyRepresentedInContiguousMemoryRegion())
49 return new AggregateFunctionGroupUniqArrayGeneric<true, has_limit>(argument_type, std::forward<TArgs>(args)...);
50 else
51 return new AggregateFunctionGroupUniqArrayGeneric<false, has_limit>(argument_type, std::forward<TArgs>(args)...);
52 }
53}
54
55template <typename has_limit, typename ... TArgs>
56inline AggregateFunctionPtr createAggregateFunctionGroupUniqArrayImpl(const std::string & name, const DataTypePtr & argument_type, TArgs ... args)
57{
58
59 AggregateFunctionPtr res(createWithNumericType<AggregateFunctionGroupUniqArray, has_limit, const DataTypePtr &, TArgs...>(*argument_type, argument_type, std::forward<TArgs>(args)...));
60
61 if (!res)
62 res = AggregateFunctionPtr(createWithExtraTypes<has_limit>(argument_type, std::forward<TArgs>(args)...));
63
64 if (!res)
65 throw Exception("Illegal type " + argument_type->getName() +
66 " of argument for aggregate function " + name, ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
67
68 return res;
69
70}
71
72AggregateFunctionPtr createAggregateFunctionGroupUniqArray(const std::string & name, const DataTypes & argument_types, const Array & parameters)
73{
74 assertUnary(name, argument_types);
75
76 bool limit_size = false;
77 UInt64 max_elems = std::numeric_limits<UInt64>::max();
78
79 if (parameters.empty())
80 {
81 // no limit
82 }
83 else if (parameters.size() == 1)
84 {
85 auto type = parameters[0].getType();
86 if (type != Field::Types::Int64 && type != Field::Types::UInt64)
87 throw Exception("Parameter for aggregate function " + name + " should be positive number", ErrorCodes::BAD_ARGUMENTS);
88
89 if ((type == Field::Types::Int64 && parameters[0].get<Int64>() < 0) ||
90 (type == Field::Types::UInt64 && parameters[0].get<UInt64>() == 0))
91 throw Exception("Parameter for aggregate function " + name + " should be positive number", ErrorCodes::BAD_ARGUMENTS);
92
93 limit_size = true;
94 max_elems = parameters[0].get<UInt64>();
95 }
96 else
97 throw Exception("Incorrect number of parameters for aggregate function " + name + ", should be 0 or 1",
98 ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
99
100 if (!limit_size)
101 return createAggregateFunctionGroupUniqArrayImpl<std::false_type>(name, argument_types[0]);
102 else
103 return createAggregateFunctionGroupUniqArrayImpl<std::true_type>(name, argument_types[0], max_elems);
104}
105
106}
107
108void registerAggregateFunctionGroupUniqArray(AggregateFunctionFactory & factory)
109{
110 factory.registerFunction("groupUniqArray", createAggregateFunctionGroupUniqArray);
111}
112
113}
114