#include #include #include #include #include #include #include #include #include namespace DB { struct Settings; namespace ErrorCodes { extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; } namespace { /** `DataForVariadic` is a data structure that will be used for `uniq` aggregate function of multiple arguments. * It differs, for example, in that it uses a trivial hash function, since `uniq` of many arguments first hashes them out itself. */ template AggregateFunctionPtr createAggregateFunctionUniq(const std::string & name, const DataTypes & argument_types, const Array & params, const Settings *) { assertNoParameters(name, params); if (argument_types.empty()) throw Exception("Incorrect number of arguments for aggregate function " + name, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); bool use_exact_hash_function = !isAllArgumentsContiguousInMemory(argument_types); if (argument_types.size() == 1) { const IDataType & argument_type = *argument_types[0]; AggregateFunctionPtr res(createWithNumericType(*argument_types[0], argument_types)); WhichDataType which(argument_type); if (res) return res; else if (which.isDate()) return std::make_shared>(argument_types); else if (which.isDate32()) return std::make_shared>(argument_types); else if (which.isDateTime()) return std::make_shared>(argument_types); else if (which.isStringOrFixedString()) return std::make_shared>(argument_types); else if (which.isUUID()) return std::make_shared>(argument_types); else if (which.isTuple()) { if (use_exact_hash_function) return std::make_shared>(argument_types); else return std::make_shared>(argument_types); } } /// "Variadic" method also works as a fallback generic case for single argument. if (use_exact_hash_function) return std::make_shared>(argument_types); else return std::make_shared>(argument_types); } template class Data, typename DataForVariadic> AggregateFunctionPtr createAggregateFunctionUniq(const std::string & name, const DataTypes & argument_types, const Array & params, const Settings *) { assertNoParameters(name, params); if (argument_types.empty()) throw Exception("Incorrect number of arguments for aggregate function " + name, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); /// We use exact hash function if the user wants it; /// or if the arguments are not contiguous in memory, because only exact hash function have support for this case. bool use_exact_hash_function = is_exact || !isAllArgumentsContiguousInMemory(argument_types); if (argument_types.size() == 1) { const IDataType & argument_type = *argument_types[0]; AggregateFunctionPtr res(createWithNumericType(*argument_types[0], argument_types)); WhichDataType which(argument_type); if (res) return res; else if (which.isDate()) return std::make_shared>>(argument_types); else if (which.isDate32()) return std::make_shared>>(argument_types); else if (which.isDateTime()) return std::make_shared>>(argument_types); else if (which.isStringOrFixedString()) return std::make_shared>>(argument_types); else if (which.isUUID()) return std::make_shared>>(argument_types); else if (which.isTuple()) { if (use_exact_hash_function) return std::make_shared>(argument_types); else return std::make_shared>(argument_types); } } /// "Variadic" method also works as a fallback generic case for single argument. if (use_exact_hash_function) return std::make_shared>(argument_types); else return std::make_shared>(argument_types); } } void registerAggregateFunctionsUniq(AggregateFunctionFactory & factory) { AggregateFunctionProperties properties = { .returns_default_when_only_null = true, .is_order_dependent = false }; factory.registerFunction("uniq", {createAggregateFunctionUniq, properties}); factory.registerFunction("uniqHLL12", {createAggregateFunctionUniq, properties}); factory.registerFunction("uniqExact", {createAggregateFunctionUniq>, properties}); #if USE_DATASKETCHES factory.registerFunction("uniqTheta", {createAggregateFunctionUniq, properties}); #endif } }