1#include <AggregateFunctions/AggregateFunctionFactory.h>
2#include <AggregateFunctions/AggregateFunctionUniq.h>
3#include <AggregateFunctions/Helpers.h>
4#include <AggregateFunctions/FactoryHelpers.h>
5
6#include <DataTypes/DataTypeDate.h>
7#include <DataTypes/DataTypeDateTime.h>
8#include <DataTypes/DataTypeString.h>
9#include <DataTypes/DataTypeFixedString.h>
10#include <DataTypes/DataTypeTuple.h>
11#include <DataTypes/DataTypeUUID.h>
12#include "registerAggregateFunctions.h"
13
14
15namespace DB
16{
17
18namespace ErrorCodes
19{
20 extern const int ILLEGAL_TYPE_OF_ARGUMENT;
21 extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
22}
23
24
25namespace
26{
27
28
29/** `DataForVariadic` is a data structure that will be used for `uniq` aggregate function of multiple arguments.
30 * It differs, for example, in that it uses a trivial hash function, since `uniq` of many arguments first hashes them out itself.
31 */
32template <typename Data, typename DataForVariadic>
33AggregateFunctionPtr createAggregateFunctionUniq(const std::string & name, const DataTypes & argument_types, const Array & params)
34{
35 assertNoParameters(name, params);
36
37 if (argument_types.empty())
38 throw Exception("Incorrect number of arguments for aggregate function " + name,
39 ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
40
41 bool use_exact_hash_function = !isAllArgumentsContiguousInMemory(argument_types);
42
43 if (argument_types.size() == 1)
44 {
45 const IDataType & argument_type = *argument_types[0];
46
47 AggregateFunctionPtr res(createWithNumericType<AggregateFunctionUniq, Data>(*argument_types[0], argument_types));
48
49 WhichDataType which(argument_type);
50 if (res)
51 return res;
52 else if (which.isDate())
53 return std::make_shared<AggregateFunctionUniq<DataTypeDate::FieldType, Data>>(argument_types);
54 else if (which.isDateTime())
55 return std::make_shared<AggregateFunctionUniq<DataTypeDateTime::FieldType, Data>>(argument_types);
56 else if (which.isStringOrFixedString())
57 return std::make_shared<AggregateFunctionUniq<String, Data>>(argument_types);
58 else if (which.isUUID())
59 return std::make_shared<AggregateFunctionUniq<DataTypeUUID::FieldType, Data>>(argument_types);
60 else if (which.isTuple())
61 {
62 if (use_exact_hash_function)
63 return std::make_shared<AggregateFunctionUniqVariadic<DataForVariadic, true, true>>(argument_types);
64 else
65 return std::make_shared<AggregateFunctionUniqVariadic<DataForVariadic, false, true>>(argument_types);
66 }
67 }
68
69 /// "Variadic" method also works as a fallback generic case for single argument.
70 if (use_exact_hash_function)
71 return std::make_shared<AggregateFunctionUniqVariadic<DataForVariadic, true, false>>(argument_types);
72 else
73 return std::make_shared<AggregateFunctionUniqVariadic<DataForVariadic, false, false>>(argument_types);
74}
75
76template <bool is_exact, template <typename> class Data, typename DataForVariadic>
77AggregateFunctionPtr createAggregateFunctionUniq(const std::string & name, const DataTypes & argument_types, const Array & params)
78{
79 assertNoParameters(name, params);
80
81 if (argument_types.empty())
82 throw Exception("Incorrect number of arguments for aggregate function " + name,
83 ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
84
85 /// We use exact hash function if the user wants it;
86 /// or if the arguments are not contiguous in memory, because only exact hash function have support for this case.
87 bool use_exact_hash_function = is_exact || !isAllArgumentsContiguousInMemory(argument_types);
88
89 if (argument_types.size() == 1)
90 {
91 const IDataType & argument_type = *argument_types[0];
92
93 AggregateFunctionPtr res(createWithNumericType<AggregateFunctionUniq, Data>(*argument_types[0], argument_types));
94
95 WhichDataType which(argument_type);
96 if (res)
97 return res;
98 else if (which.isDate())
99 return std::make_shared<AggregateFunctionUniq<DataTypeDate::FieldType, Data<DataTypeDate::FieldType>>>(argument_types);
100 else if (which.isDateTime())
101 return std::make_shared<AggregateFunctionUniq<DataTypeDateTime::FieldType, Data<DataTypeDateTime::FieldType>>>(argument_types);
102 else if (which.isStringOrFixedString())
103 return std::make_shared<AggregateFunctionUniq<String, Data<String>>>(argument_types);
104 else if (which.isUUID())
105 return std::make_shared<AggregateFunctionUniq<DataTypeUUID::FieldType, Data<DataTypeUUID::FieldType>>>(argument_types);
106 else if (which.isTuple())
107 {
108 if (use_exact_hash_function)
109 return std::make_shared<AggregateFunctionUniqVariadic<DataForVariadic, true, true>>(argument_types);
110 else
111 return std::make_shared<AggregateFunctionUniqVariadic<DataForVariadic, false, true>>(argument_types);
112 }
113 }
114
115 /// "Variadic" method also works as a fallback generic case for single argument.
116 if (use_exact_hash_function)
117 return std::make_shared<AggregateFunctionUniqVariadic<DataForVariadic, true, false>>(argument_types);
118 else
119 return std::make_shared<AggregateFunctionUniqVariadic<DataForVariadic, false, false>>(argument_types);
120}
121
122}
123
124void registerAggregateFunctionsUniq(AggregateFunctionFactory & factory)
125{
126 factory.registerFunction("uniq",
127 createAggregateFunctionUniq<AggregateFunctionUniqUniquesHashSetData, AggregateFunctionUniqUniquesHashSetDataForVariadic>);
128
129 factory.registerFunction("uniqHLL12",
130 createAggregateFunctionUniq<false, AggregateFunctionUniqHLL12Data, AggregateFunctionUniqHLL12DataForVariadic>);
131
132 factory.registerFunction("uniqExact",
133 createAggregateFunctionUniq<true, AggregateFunctionUniqExactData, AggregateFunctionUniqExactData<String>>);
134}
135
136}
137