1 | #include <AggregateFunctions/AggregateFunctionUniqCombined.h> |
2 | |
3 | #include <AggregateFunctions/AggregateFunctionFactory.h> |
4 | #include <AggregateFunctions/Helpers.h> |
5 | |
6 | #include <DataTypes/DataTypeDate.h> |
7 | #include <DataTypes/DataTypeDateTime.h> |
8 | |
9 | #include <functional> |
10 | #include "registerAggregateFunctions.h" |
11 | |
12 | namespace DB |
13 | { |
14 | namespace ErrorCodes |
15 | { |
16 | extern const int ILLEGAL_TYPE_OF_ARGUMENT; |
17 | extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; |
18 | extern const int ARGUMENT_OUT_OF_BOUND; |
19 | } |
20 | |
21 | namespace |
22 | { |
23 | template <UInt8 K, typename HashValueType> |
24 | struct WithK |
25 | { |
26 | template <typename T> |
27 | using AggregateFunction = AggregateFunctionUniqCombined<T, K, HashValueType>; |
28 | |
29 | template <bool is_exact, bool argument_is_tuple> |
30 | using AggregateFunctionVariadic = AggregateFunctionUniqCombinedVariadic<is_exact, argument_is_tuple, K, HashValueType>; |
31 | }; |
32 | |
33 | template <UInt8 K, typename HashValueType> |
34 | AggregateFunctionPtr createAggregateFunctionWithK(const DataTypes & argument_types, const Array & params) |
35 | { |
36 | /// We use exact hash function if the arguments are not contiguous in memory, because only exact hash function has support for this case. |
37 | bool use_exact_hash_function = !isAllArgumentsContiguousInMemory(argument_types); |
38 | |
39 | if (argument_types.size() == 1) |
40 | { |
41 | const IDataType & argument_type = *argument_types[0]; |
42 | |
43 | AggregateFunctionPtr res(createWithNumericType<WithK<K, HashValueType>::template AggregateFunction>(*argument_types[0], argument_types, params)); |
44 | |
45 | WhichDataType which(argument_type); |
46 | if (res) |
47 | return res; |
48 | else if (which.isDate()) |
49 | return std::make_shared<typename WithK<K, HashValueType>::template AggregateFunction<DataTypeDate::FieldType>>(argument_types, params); |
50 | else if (which.isDateTime()) |
51 | return std::make_shared<typename WithK<K, HashValueType>::template AggregateFunction<DataTypeDateTime::FieldType>>(argument_types, params); |
52 | else if (which.isStringOrFixedString()) |
53 | return std::make_shared<typename WithK<K, HashValueType>::template AggregateFunction<String>>(argument_types, params); |
54 | else if (which.isUUID()) |
55 | return std::make_shared<typename WithK<K, HashValueType>::template AggregateFunction<DataTypeUUID::FieldType>>(argument_types, params); |
56 | else if (which.isTuple()) |
57 | { |
58 | if (use_exact_hash_function) |
59 | return std::make_shared<typename WithK<K, HashValueType>::template AggregateFunctionVariadic<true, true>>(argument_types, params); |
60 | else |
61 | return std::make_shared<typename WithK<K, HashValueType>::template AggregateFunctionVariadic<false, true>>(argument_types, params); |
62 | } |
63 | } |
64 | |
65 | /// "Variadic" method also works as a fallback generic case for a single argument. |
66 | if (use_exact_hash_function) |
67 | return std::make_shared<typename WithK<K, HashValueType>::template AggregateFunctionVariadic<true, false>>(argument_types, params); |
68 | else |
69 | return std::make_shared<typename WithK<K, HashValueType>::template AggregateFunctionVariadic<false, false>>(argument_types, params); |
70 | } |
71 | |
72 | template <UInt8 K> |
73 | AggregateFunctionPtr createAggregateFunctionWithHashType(bool use_64_bit_hash, const DataTypes & argument_types, const Array & params) |
74 | { |
75 | if (use_64_bit_hash) |
76 | return createAggregateFunctionWithK<K, UInt64>(argument_types, params); |
77 | else |
78 | return createAggregateFunctionWithK<K, UInt32>(argument_types, params); |
79 | } |
80 | |
81 | AggregateFunctionPtr createAggregateFunctionUniqCombined(bool use_64_bit_hash, |
82 | const std::string & name, const DataTypes & argument_types, const Array & params) |
83 | { |
84 | /// log2 of the number of cells in HyperLogLog. |
85 | /// Reasonable default value, selected to be comparable in quality with "uniq" aggregate function. |
86 | UInt8 precision = 17; |
87 | |
88 | if (!params.empty()) |
89 | { |
90 | if (params.size() != 1) |
91 | throw Exception( |
92 | "Aggregate function " + name + " requires one parameter or less." , ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); |
93 | |
94 | UInt64 precision_param = applyVisitor(FieldVisitorConvertToNumber<UInt64>(), params[0]); |
95 | // This range is hardcoded below |
96 | if (precision_param > 20 || precision_param < 12) |
97 | throw Exception( |
98 | "Parameter for aggregate function " + name + " is out or range: [12, 20]." , ErrorCodes::ARGUMENT_OUT_OF_BOUND); |
99 | precision = precision_param; |
100 | } |
101 | |
102 | if (argument_types.empty()) |
103 | throw Exception("Incorrect number of arguments for aggregate function " + name, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); |
104 | |
105 | switch (precision) |
106 | { |
107 | case 12: |
108 | return createAggregateFunctionWithHashType<12>(use_64_bit_hash, argument_types, params); |
109 | case 13: |
110 | return createAggregateFunctionWithHashType<13>(use_64_bit_hash, argument_types, params); |
111 | case 14: |
112 | return createAggregateFunctionWithHashType<14>(use_64_bit_hash, argument_types, params); |
113 | case 15: |
114 | return createAggregateFunctionWithHashType<15>(use_64_bit_hash, argument_types, params); |
115 | case 16: |
116 | return createAggregateFunctionWithHashType<16>(use_64_bit_hash, argument_types, params); |
117 | case 17: |
118 | return createAggregateFunctionWithHashType<17>(use_64_bit_hash, argument_types, params); |
119 | case 18: |
120 | return createAggregateFunctionWithHashType<18>(use_64_bit_hash, argument_types, params); |
121 | case 19: |
122 | return createAggregateFunctionWithHashType<19>(use_64_bit_hash, argument_types, params); |
123 | case 20: |
124 | return createAggregateFunctionWithHashType<20>(use_64_bit_hash, argument_types, params); |
125 | } |
126 | |
127 | __builtin_unreachable(); |
128 | } |
129 | |
130 | } |
131 | |
132 | void registerAggregateFunctionUniqCombined(AggregateFunctionFactory & factory) |
133 | { |
134 | using namespace std::placeholders; |
135 | factory.registerFunction("uniqCombined" , std::bind(createAggregateFunctionUniqCombined, false, _1, _2, _3)); |
136 | factory.registerFunction("uniqCombined64" , std::bind(createAggregateFunctionUniqCombined, true, _1, _2, _3)); |
137 | } |
138 | |
139 | } |
140 | |