2012-12-21 19:48:47 +00:00
|
|
|
#pragma once
|
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <DataTypes/DataTypesNumber.h>
|
2019-05-23 14:04:33 +00:00
|
|
|
#include <DataTypes/DataTypesDecimal.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <DataTypes/DataTypeArray.h>
|
|
|
|
#include <DataTypes/DataTypeString.h>
|
|
|
|
#include <DataTypes/DataTypeDate.h>
|
|
|
|
#include <DataTypes/DataTypeDateTime.h>
|
|
|
|
#include <DataTypes/DataTypeTuple.h>
|
2017-11-14 00:08:54 +00:00
|
|
|
#include <DataTypes/DataTypeUUID.h>
|
2021-01-02 22:08:54 +00:00
|
|
|
#include <DataTypes/DataTypeNullable.h>
|
2021-01-08 21:02:47 +00:00
|
|
|
#include <DataTypes/DataTypeLowCardinality.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
|
2017-07-13 20:58:19 +00:00
|
|
|
#include <Common/typeid_cast.h>
|
2019-08-21 02:28:04 +00:00
|
|
|
#include <Common/assert_cast.h>
|
2017-07-13 20:58:19 +00:00
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Columns/ColumnsNumber.h>
|
|
|
|
#include <Columns/ColumnConst.h>
|
|
|
|
#include <Columns/ColumnArray.h>
|
|
|
|
#include <Columns/ColumnString.h>
|
|
|
|
#include <Columns/ColumnTuple.h>
|
|
|
|
|
2020-01-26 09:49:53 +00:00
|
|
|
#include <Access/AccessFlags.h>
|
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Interpreters/Context.h>
|
2019-09-26 10:41:33 +00:00
|
|
|
#include <Interpreters/ExternalDictionariesLoader.h>
|
2021-02-27 20:39:34 +00:00
|
|
|
#include <Interpreters/castColumn.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
|
2019-12-09 13:12:54 +00:00
|
|
|
#include <Functions/IFunctionImpl.h>
|
2017-07-21 06:35:58 +00:00
|
|
|
#include <Functions/FunctionHelpers.h>
|
2017-06-06 17:18:32 +00:00
|
|
|
#include <ext/range.h>
|
2015-04-16 06:12:35 +00:00
|
|
|
|
2018-09-13 13:33:44 +00:00
|
|
|
#include <type_traits>
|
2012-12-21 19:48:47 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2016-01-12 02:21:15 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2020-02-25 18:02:41 +00:00
|
|
|
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
2017-04-01 07:20:54 +00:00
|
|
|
extern const int UNSUPPORTED_METHOD;
|
2017-06-13 02:06:53 +00:00
|
|
|
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
2019-03-14 23:10:51 +00:00
|
|
|
extern const int ILLEGAL_COLUMN;
|
|
|
|
extern const int BAD_ARGUMENTS;
|
2021-01-21 14:42:50 +00:00
|
|
|
extern const int TYPE_MISMATCH;
|
2016-01-12 02:21:15 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 14:03:06 +00:00
|
|
|
|
2019-09-26 10:41:33 +00:00
|
|
|
/** Functions that use plug-ins (external) dictionaries_loader.
|
2015-02-10 14:50:43 +00:00
|
|
|
*
|
2017-05-13 22:19:04 +00:00
|
|
|
* Get the value of the attribute of the specified type.
|
2017-04-01 07:20:54 +00:00
|
|
|
* dictGetType(dictionary, attribute, id),
|
2017-05-13 22:19:04 +00:00
|
|
|
* Type - placeholder for the type name, any numeric and string types are currently supported.
|
|
|
|
* The type must match the actual attribute type with which it was declared in the dictionary structure.
|
2015-02-10 14:50:43 +00:00
|
|
|
*
|
2017-05-13 22:19:04 +00:00
|
|
|
* Get an array of identifiers, consisting of the source and parents chain.
|
2015-02-10 14:50:43 +00:00
|
|
|
* dictGetHierarchy(dictionary, id).
|
|
|
|
*
|
2017-05-13 22:19:04 +00:00
|
|
|
* Is the first identifier the child of the second.
|
2015-02-10 14:50:43 +00:00
|
|
|
* dictIsIn(dictionary, child_id, parent_id).
|
2012-12-21 19:48:47 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
2020-05-14 14:03:06 +00:00
|
|
|
class FunctionDictHelper
|
|
|
|
{
|
|
|
|
public:
|
2021-03-19 12:47:27 +00:00
|
|
|
explicit FunctionDictHelper(const Context & context_) : context(context_) {}
|
2020-05-14 14:03:06 +00:00
|
|
|
|
2021-03-24 16:31:00 +00:00
|
|
|
std::shared_ptr<const IDictionary> getDictionary(const String & dictionary_name)
|
2020-05-14 14:03:06 +00:00
|
|
|
{
|
2021-03-20 15:02:09 +00:00
|
|
|
auto dict = context.getExternalDictionariesLoader().getDictionary(dictionary_name, context);
|
2021-03-18 11:30:12 +00:00
|
|
|
|
2020-10-16 21:14:49 +00:00
|
|
|
if (!access_checked)
|
|
|
|
{
|
|
|
|
context.checkAccess(AccessType::dictGet, dict->getDatabaseOrNoDatabaseTag(), dict->getDictionaryID().getTableName());
|
|
|
|
access_checked = true;
|
|
|
|
}
|
2021-03-18 11:30:12 +00:00
|
|
|
|
2020-05-14 14:03:06 +00:00
|
|
|
return dict;
|
|
|
|
}
|
|
|
|
|
2021-03-24 16:31:00 +00:00
|
|
|
std::shared_ptr<const IDictionary> getDictionary(const ColumnWithTypeAndName & column)
|
2020-05-14 14:03:06 +00:00
|
|
|
{
|
2020-10-18 14:49:19 +00:00
|
|
|
const auto * dict_name_col = checkAndGetColumnConst<ColumnString>(column.column.get());
|
2020-05-14 14:03:06 +00:00
|
|
|
return getDictionary(dict_name_col->getValue<String>());
|
|
|
|
}
|
|
|
|
|
2020-10-14 14:04:50 +00:00
|
|
|
bool isDictGetFunctionInjective(const Block & sample_columns)
|
2020-05-14 14:03:06 +00:00
|
|
|
{
|
2020-07-07 21:26:09 +00:00
|
|
|
/// Assume non-injective by default
|
2020-10-14 14:04:50 +00:00
|
|
|
if (!sample_columns)
|
2020-07-07 21:26:09 +00:00
|
|
|
return false;
|
|
|
|
|
2020-12-20 20:11:28 +00:00
|
|
|
if (sample_columns.columns() < 3)
|
|
|
|
throw Exception{"Wrong arguments count", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH};
|
2020-05-14 14:03:06 +00:00
|
|
|
|
2020-10-18 14:49:19 +00:00
|
|
|
const auto * dict_name_col = checkAndGetColumnConst<ColumnString>(sample_columns.getByPosition(0).column.get());
|
2020-05-14 14:03:06 +00:00
|
|
|
if (!dict_name_col)
|
|
|
|
throw Exception{"First argument of function dictGet... must be a constant string", ErrorCodes::ILLEGAL_COLUMN};
|
|
|
|
|
2020-10-18 14:49:19 +00:00
|
|
|
const auto * attr_name_col = checkAndGetColumnConst<ColumnString>(sample_columns.getByPosition(1).column.get());
|
2020-05-14 14:03:06 +00:00
|
|
|
if (!attr_name_col)
|
|
|
|
throw Exception{"Second argument of function dictGet... must be a constant string", ErrorCodes::ILLEGAL_COLUMN};
|
|
|
|
|
|
|
|
return getDictionary(dict_name_col->getValue<String>())->isInjective(attr_name_col->getValue<String>());
|
|
|
|
}
|
|
|
|
|
2021-01-29 12:44:56 +00:00
|
|
|
DictionaryStructure getDictionaryStructure(const String & dictionary_name) const
|
2021-01-08 21:02:47 +00:00
|
|
|
{
|
2021-03-20 15:02:09 +00:00
|
|
|
return context.getExternalDictionariesLoader().getDictionaryStructure(dictionary_name, context);
|
2021-01-08 21:02:47 +00:00
|
|
|
}
|
2021-01-29 12:44:56 +00:00
|
|
|
|
2021-03-18 11:30:12 +00:00
|
|
|
private:
|
2021-03-19 12:47:27 +00:00
|
|
|
const Context & context;
|
2020-10-16 21:14:49 +00:00
|
|
|
/// Access cannot be not granted, since in this case checkAccess() will throw and access_checked will not be updated.
|
|
|
|
std::atomic<bool> access_checked = false;
|
2021-01-29 12:44:56 +00:00
|
|
|
|
|
|
|
/// We must not cache dictionary or dictionary's structure here, because there are places
|
|
|
|
/// where ExpressionActionsPtr is cached (StorageDistributed caching it for sharding_key_expr and
|
|
|
|
/// optimize_skip_unused_shards), and if the dictionary will be cached within "query" then
|
|
|
|
/// cached ExpressionActionsPtr will always have first version of the query and the dictionary
|
|
|
|
/// will not be updated after reload (see https://github.com/ClickHouse/ClickHouse/pull/16205)
|
2020-05-14 14:03:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-11-19 13:15:02 +00:00
|
|
|
class FunctionDictHas final : public IFunction
|
|
|
|
{
|
|
|
|
public:
|
2017-04-01 07:20:54 +00:00
|
|
|
static constexpr auto name = "dictHas";
|
2015-11-19 13:15:02 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
static FunctionPtr create(const Context & context)
|
|
|
|
{
|
2020-05-14 14:03:06 +00:00
|
|
|
return std::make_shared<FunctionDictHas>(context);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2015-11-19 13:15:02 +00:00
|
|
|
|
2020-10-18 14:49:19 +00:00
|
|
|
explicit FunctionDictHas(const Context & context_) : helper(context_) {}
|
2015-11-19 13:15:02 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
String getName() const override { return name; }
|
2015-11-19 13:15:02 +00:00
|
|
|
|
|
|
|
private:
|
2021-01-29 14:48:13 +00:00
|
|
|
size_t getNumberOfArguments() const override { return 0; }
|
|
|
|
bool isVariadic() const override { return true; }
|
|
|
|
|
|
|
|
bool isDeterministic() const override { return false; }
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-03-16 01:22:02 +00:00
|
|
|
bool useDefaultImplementationForConstants() const final { return true; }
|
2021-01-29 14:48:13 +00:00
|
|
|
|
2018-03-16 01:22:02 +00:00
|
|
|
ColumnNumbers getArgumentsThatAreAlwaysConstant() const final { return {0}; }
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
|
|
|
{
|
2021-01-29 14:48:13 +00:00
|
|
|
if (arguments.size() < 2)
|
|
|
|
throw Exception{"Wrong argument count for function " + getName(), ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH};
|
|
|
|
|
2018-09-07 14:37:26 +00:00
|
|
|
if (!isString(arguments[0]))
|
2018-03-16 03:03:17 +00:00
|
|
|
throw Exception{"Illegal type " + arguments[0]->getName() + " of first argument of function " + getName()
|
|
|
|
+ ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-09-07 14:37:26 +00:00
|
|
|
if (!WhichDataType(arguments[1]).isUInt64() &&
|
|
|
|
!isTuple(arguments[1]))
|
2018-03-16 03:03:17 +00:00
|
|
|
throw Exception{"Illegal type " + arguments[1]->getName() + " of second argument of function " + getName()
|
|
|
|
+ ", must be UInt64 or tuple(...).", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
return std::make_shared<DataTypeUInt8>();
|
|
|
|
}
|
|
|
|
|
2020-11-17 13:24:45 +00:00
|
|
|
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2020-10-14 14:04:50 +00:00
|
|
|
/** Do not require existence of the dictionary if the function is called for empty columns.
|
2018-03-16 03:13:13 +00:00
|
|
|
* This is needed to allow successful query analysis on a server,
|
|
|
|
* that is the initiator of a distributed query,
|
|
|
|
* in the case when the function will be invoked for real data only at the remote servers.
|
|
|
|
* This feature is controversial and implemented specially
|
|
|
|
* for backward compatibility with the case in Yandex Banner System.
|
|
|
|
*/
|
2018-09-14 18:55:12 +00:00
|
|
|
if (input_rows_count == 0)
|
2020-10-18 14:49:19 +00:00
|
|
|
return result_type->createColumn();
|
2018-03-16 03:13:13 +00:00
|
|
|
|
2020-12-19 13:24:51 +00:00
|
|
|
auto dictionary = helper.getDictionary(arguments[0]);
|
2021-01-23 13:18:24 +00:00
|
|
|
auto dictionary_key_type = dictionary->getKeyType();
|
2019-09-11 11:14:55 +00:00
|
|
|
|
2020-12-20 20:11:28 +00:00
|
|
|
const ColumnWithTypeAndName & key_column_with_type = arguments[1];
|
|
|
|
const auto key_column = key_column_with_type.column;
|
2021-01-08 21:02:47 +00:00
|
|
|
const auto key_column_type = WhichDataType(key_column_with_type.type);
|
2020-10-18 14:49:19 +00:00
|
|
|
|
2021-01-29 14:48:13 +00:00
|
|
|
ColumnPtr range_col = nullptr;
|
|
|
|
DataTypePtr range_col_type = nullptr;
|
|
|
|
|
|
|
|
if (dictionary_key_type == DictionaryKeyType::range)
|
|
|
|
{
|
|
|
|
if (arguments.size() != 3)
|
|
|
|
throw Exception{"Wrong argument count for function " + getName()
|
|
|
|
+ " when dictionary has key type range", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH};
|
|
|
|
|
|
|
|
range_col = arguments[2].column;
|
|
|
|
range_col_type = arguments[2].type;
|
|
|
|
|
|
|
|
if (!(range_col_type->isValueRepresentedByInteger() && range_col_type->getSizeOfValueInMemory() <= sizeof(Int64)))
|
|
|
|
throw Exception{"Illegal type " + range_col_type->getName() + " of fourth argument of function "
|
|
|
|
+ getName() + " must be convertible to Int64.",
|
|
|
|
ErrorCodes::ILLEGAL_COLUMN};
|
|
|
|
}
|
|
|
|
|
2021-01-23 13:18:24 +00:00
|
|
|
if (dictionary_key_type == DictionaryKeyType::simple)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2021-01-08 21:02:47 +00:00
|
|
|
if (!key_column_type.isUInt64())
|
|
|
|
throw Exception{"Second argument of function " + getName() + " must be " + dictionary->getStructure().getKeyDescription(),
|
|
|
|
ErrorCodes::TYPE_MISMATCH};
|
|
|
|
|
2021-01-23 13:18:24 +00:00
|
|
|
return dictionary->hasKeys({key_column}, {std::make_shared<DataTypeUInt64>()});
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2021-01-23 13:18:24 +00:00
|
|
|
else if (dictionary_key_type == DictionaryKeyType::complex)
|
2017-12-13 20:40:03 +00:00
|
|
|
{
|
2021-01-08 21:02:47 +00:00
|
|
|
if (!key_column_type.isTuple())
|
|
|
|
throw Exception{"Second argument of function " + getName() + " must be " + dictionary->getStructure().getKeyDescription(),
|
|
|
|
ErrorCodes::TYPE_MISMATCH};
|
|
|
|
|
2020-12-20 20:11:28 +00:00
|
|
|
/// Functions in external dictionaries_loader only support full-value (not constant) columns with keys.
|
2021-01-08 21:02:47 +00:00
|
|
|
ColumnPtr key_column_full = key_column->convertToFullColumnIfConst();
|
2020-12-20 20:11:28 +00:00
|
|
|
|
|
|
|
const auto & key_columns = typeid_cast<const ColumnTuple &>(*key_column_full).getColumnsCopy();
|
|
|
|
const auto & key_types = static_cast<const DataTypeTuple &>(*key_column_with_type.type).getElements();
|
|
|
|
|
2021-01-23 13:18:24 +00:00
|
|
|
return dictionary->hasKeys(key_columns, key_types);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
else
|
2021-01-29 14:48:13 +00:00
|
|
|
return dictionary->hasKeys({key_column, range_col}, {std::make_shared<DataTypeUInt64>(), range_col_type});
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 14:03:06 +00:00
|
|
|
mutable FunctionDictHelper helper;
|
2015-11-19 13:15:02 +00:00
|
|
|
};
|
|
|
|
|
2020-12-18 21:43:08 +00:00
|
|
|
enum class DictionaryGetFunctionType
|
|
|
|
{
|
2021-01-02 22:08:54 +00:00
|
|
|
get,
|
2021-01-08 21:02:47 +00:00
|
|
|
getOrDefault
|
2019-05-23 14:04:33 +00:00
|
|
|
};
|
|
|
|
|
2021-01-08 21:02:47 +00:00
|
|
|
/// This variant of function derives the result type automatically.
|
|
|
|
template <DictionaryGetFunctionType dictionary_get_function_type>
|
|
|
|
class FunctionDictGetNoType final : public IFunction
|
2015-01-22 14:32:38 +00:00
|
|
|
{
|
|
|
|
public:
|
2021-01-08 21:02:47 +00:00
|
|
|
static constexpr auto name = dictionary_get_function_type == DictionaryGetFunctionType::get ? "dictGet" : "dictGetOrDefault";
|
2015-01-22 14:32:38 +00:00
|
|
|
|
2021-01-08 21:02:47 +00:00
|
|
|
static FunctionPtr create(const Context & context)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2021-01-08 21:02:47 +00:00
|
|
|
return std::make_shared<FunctionDictGetNoType>(context);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2015-01-22 14:32:38 +00:00
|
|
|
|
2021-01-08 21:02:47 +00:00
|
|
|
explicit FunctionDictGetNoType(const Context & context_) : helper(context_) {}
|
2015-01-22 14:32:38 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
String getName() const override { return name; }
|
2015-01-22 14:32:38 +00:00
|
|
|
|
2020-12-20 20:11:28 +00:00
|
|
|
bool isVariadic() const override { return true; }
|
2021-01-08 21:02:47 +00:00
|
|
|
size_t getNumberOfArguments() const override { return 0; }
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-03-16 03:03:17 +00:00
|
|
|
bool useDefaultImplementationForConstants() const final { return true; }
|
2021-01-08 21:02:47 +00:00
|
|
|
ColumnNumbers getArgumentsThatAreAlwaysConstant() const final { return {0, 1}; }
|
2018-03-16 03:03:17 +00:00
|
|
|
|
2020-12-18 21:43:08 +00:00
|
|
|
bool isDeterministic() const override { return false; }
|
|
|
|
|
2021-01-08 21:02:47 +00:00
|
|
|
bool isInjective(const ColumnsWithTypeAndName & sample_columns) const override
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2021-01-08 21:02:47 +00:00
|
|
|
return helper.isDictGetFunctionInjective(sample_columns);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2021-01-08 21:02:47 +00:00
|
|
|
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2020-12-20 20:11:28 +00:00
|
|
|
if (arguments.size() < 3)
|
|
|
|
throw Exception{"Wrong argument count for function " + getName(), ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH};
|
|
|
|
|
2021-01-08 21:02:47 +00:00
|
|
|
String dictionary_name;
|
|
|
|
if (const auto * name_col = checkAndGetColumnConst<ColumnString>(arguments[0].column.get()))
|
|
|
|
dictionary_name = name_col->getValue<String>();
|
|
|
|
else
|
|
|
|
throw Exception{"Illegal type " + arguments[0].type->getName() + " of first argument of function " + getName()
|
|
|
|
+ ", expected a const string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
2020-12-20 20:11:28 +00:00
|
|
|
|
2021-02-26 15:56:41 +00:00
|
|
|
Strings attribute_names = getAttributeNamesFromColumn(arguments[1].column, arguments[1].type);
|
2020-12-20 20:11:28 +00:00
|
|
|
|
2021-02-26 15:56:41 +00:00
|
|
|
DataTypes types;
|
|
|
|
|
2021-03-18 11:30:12 +00:00
|
|
|
auto dictionary_structure = helper.getDictionaryStructure(dictionary_name);
|
|
|
|
|
2021-02-26 15:56:41 +00:00
|
|
|
for (auto & attribute_name : attribute_names)
|
|
|
|
{
|
|
|
|
/// We're extracting the return type from the dictionary's config, without loading the dictionary.
|
2021-03-18 11:30:12 +00:00
|
|
|
auto attribute = dictionary_structure.getAttribute(attribute_name);
|
2021-02-26 15:56:41 +00:00
|
|
|
types.emplace_back(attribute.type);
|
|
|
|
}
|
2020-12-20 20:11:28 +00:00
|
|
|
|
2021-02-26 15:56:41 +00:00
|
|
|
if (types.size() > 1)
|
|
|
|
return std::make_shared<DataTypeTuple>(types);
|
|
|
|
else
|
|
|
|
return types.front();
|
2021-01-08 21:02:47 +00:00
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-01-08 21:02:47 +00:00
|
|
|
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
|
|
|
|
{
|
|
|
|
if (input_rows_count == 0)
|
|
|
|
return result_type->createColumn();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-01-27 20:22:05 +00:00
|
|
|
String dictionary_name;
|
|
|
|
|
|
|
|
if (const auto * name_col = checkAndGetColumnConst<ColumnString>(arguments[0].column.get()))
|
|
|
|
dictionary_name = name_col->getValue<String>();
|
|
|
|
else
|
|
|
|
throw Exception{"Illegal type " + arguments[0].type->getName() + " of first argument of function " + getName()
|
|
|
|
+ ", expected a const string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
|
|
|
|
2021-02-26 15:56:41 +00:00
|
|
|
Strings attribute_names = getAttributeNamesFromColumn(arguments[1].column, arguments[1].type);
|
2021-01-27 20:22:05 +00:00
|
|
|
|
|
|
|
auto dictionary = helper.getDictionary(dictionary_name);
|
|
|
|
|
2020-12-20 20:11:28 +00:00
|
|
|
if (!WhichDataType(arguments[2].type).isUInt64() && !isTuple(arguments[2].type))
|
2020-12-29 15:21:49 +00:00
|
|
|
throw Exception{"Illegal type " + arguments[2].type->getName() + " of third argument of function "
|
|
|
|
+ getName() + ", must be UInt64 or tuple(...).",
|
2020-12-20 20:11:28 +00:00
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
2019-05-23 14:04:33 +00:00
|
|
|
|
2021-01-23 13:18:24 +00:00
|
|
|
auto dictionary_key_type = dictionary->getKeyType();
|
2020-12-20 20:11:28 +00:00
|
|
|
|
|
|
|
size_t current_arguments_index = 3;
|
|
|
|
|
|
|
|
ColumnPtr range_col = nullptr;
|
|
|
|
DataTypePtr range_col_type = nullptr;
|
|
|
|
|
2021-01-23 13:18:24 +00:00
|
|
|
if (dictionary_key_type == DictionaryKeyType::range)
|
2020-12-20 20:11:28 +00:00
|
|
|
{
|
|
|
|
if (current_arguments_index >= arguments.size())
|
|
|
|
throw Exception{"Wrong argument count for function " + getName(), ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH};
|
|
|
|
|
|
|
|
range_col = arguments[current_arguments_index].column;
|
|
|
|
range_col_type = arguments[current_arguments_index].type;
|
|
|
|
|
|
|
|
if (!(range_col_type->isValueRepresentedByInteger() && range_col_type->getSizeOfValueInMemory() <= sizeof(Int64)))
|
2020-12-29 15:21:49 +00:00
|
|
|
throw Exception{"Illegal type " + range_col_type->getName() + " of fourth argument of function "
|
|
|
|
+ getName() + " must be convertible to Int64.",
|
2020-12-20 20:11:28 +00:00
|
|
|
ErrorCodes::ILLEGAL_COLUMN};
|
|
|
|
|
|
|
|
++current_arguments_index;
|
|
|
|
}
|
|
|
|
|
2021-02-26 15:56:41 +00:00
|
|
|
Columns default_cols;
|
2020-12-19 14:27:39 +00:00
|
|
|
|
2021-01-02 22:08:54 +00:00
|
|
|
if (dictionary_get_function_type == DictionaryGetFunctionType::getOrDefault)
|
2020-12-19 14:27:39 +00:00
|
|
|
{
|
2020-12-20 20:11:28 +00:00
|
|
|
if (current_arguments_index >= arguments.size())
|
2021-01-08 21:02:47 +00:00
|
|
|
throw Exception{"Wrong argument count for function " + getName(), ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH};
|
2020-12-20 20:11:28 +00:00
|
|
|
|
2021-02-27 20:39:34 +00:00
|
|
|
const auto & column_before_cast = arguments[current_arguments_index];
|
2021-02-26 15:56:41 +00:00
|
|
|
|
2021-02-27 20:39:34 +00:00
|
|
|
if (const DataTypeTuple * type_tuple = typeid_cast<const DataTypeTuple *>(column_before_cast.type.get()))
|
|
|
|
{
|
|
|
|
const DataTypes & nested_types = type_tuple->getElements();
|
|
|
|
|
|
|
|
for (const auto & nested_type : nested_types)
|
|
|
|
if (nested_type->isNullable())
|
|
|
|
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Wrong argument for function ({}) default values column nullable is not supported", getName());
|
|
|
|
}
|
|
|
|
else if (column_before_cast.type->isNullable())
|
|
|
|
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Wrong argument for function ({}) default values column nullable is not supported", getName());
|
|
|
|
|
|
|
|
auto result_type_no_nullable = removeNullable(result_type);
|
|
|
|
|
|
|
|
ColumnWithTypeAndName column_to_cast = {column_before_cast.column->convertToFullColumnIfConst(), column_before_cast.type, column_before_cast.name};
|
|
|
|
|
|
|
|
auto result = castColumnAccurate(column_to_cast, result_type_no_nullable);
|
2021-02-26 15:56:41 +00:00
|
|
|
|
|
|
|
if (attribute_names.size() > 1)
|
|
|
|
{
|
2021-02-27 20:39:34 +00:00
|
|
|
const auto * tuple_column = checkAndGetColumn<ColumnTuple>(result.get());
|
2021-02-26 15:56:41 +00:00
|
|
|
|
|
|
|
if (!tuple_column)
|
|
|
|
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
|
|
|
"Wrong argument for function ({}) default values column must be tuple", getName());
|
|
|
|
|
|
|
|
if (tuple_column->tupleSize() != attribute_names.size())
|
|
|
|
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
|
|
|
"Wrong argument for function ({}) default values tuple column must contain same column size as requested attributes",
|
|
|
|
getName());
|
|
|
|
|
|
|
|
default_cols = tuple_column->getColumnsCopy();
|
|
|
|
}
|
|
|
|
else
|
2021-02-27 20:39:34 +00:00
|
|
|
default_cols.emplace_back(result);
|
2021-02-26 15:56:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < attribute_names.size(); ++i)
|
|
|
|
default_cols.emplace_back(nullptr);
|
2020-12-19 14:27:39 +00:00
|
|
|
}
|
2020-12-18 21:43:08 +00:00
|
|
|
|
2021-01-08 21:02:47 +00:00
|
|
|
ColumnPtr result;
|
2020-12-20 20:11:28 +00:00
|
|
|
|
|
|
|
const ColumnWithTypeAndName & key_col_with_type = arguments[2];
|
|
|
|
const auto key_column = key_col_with_type.column;
|
|
|
|
|
2021-01-23 13:18:24 +00:00
|
|
|
if (dictionary_key_type == DictionaryKeyType::simple)
|
2020-12-18 21:43:08 +00:00
|
|
|
{
|
2021-03-05 14:12:50 +00:00
|
|
|
if (!WhichDataType(key_col_with_type.type).isUInt64())
|
|
|
|
throw Exception(
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
|
|
|
"Third argument of function ({}) must be uint64 when dictionary is simple. Actual type ({}).",
|
|
|
|
getName(),
|
|
|
|
key_col_with_type.type->getName());
|
|
|
|
|
2021-02-26 15:56:41 +00:00
|
|
|
if (attribute_names.size() > 1)
|
|
|
|
{
|
|
|
|
const auto & result_tuple_type = assert_cast<const DataTypeTuple &>(*result_type);
|
|
|
|
|
|
|
|
Columns result_columns = dictionary->getColumns(
|
|
|
|
attribute_names,
|
|
|
|
result_tuple_type.getElements(),
|
|
|
|
{key_column},
|
|
|
|
{std::make_shared<DataTypeUInt64>()},
|
|
|
|
default_cols);
|
|
|
|
|
|
|
|
result = ColumnTuple::create(std::move(result_columns));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result = dictionary->getColumn(
|
|
|
|
attribute_names[0],
|
|
|
|
result_type,
|
|
|
|
{key_column},
|
|
|
|
{std::make_shared<DataTypeUInt64>()},
|
|
|
|
default_cols.front());
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2021-01-23 13:18:24 +00:00
|
|
|
else if (dictionary_key_type == DictionaryKeyType::complex)
|
2017-12-13 20:40:03 +00:00
|
|
|
{
|
2021-03-04 13:55:05 +00:00
|
|
|
if (!isTuple(key_col_with_type.type))
|
2021-03-05 14:12:50 +00:00
|
|
|
throw Exception(
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
|
|
|
"Third argument of function ({}) must be tuple when dictionary is complex. Actual type ({}).",
|
|
|
|
getName(),
|
|
|
|
key_col_with_type.type->getName());
|
2021-03-04 13:55:05 +00:00
|
|
|
|
2020-12-19 14:27:39 +00:00
|
|
|
/// Functions in external dictionaries_loader only support full-value (not constant) columns with keys.
|
|
|
|
ColumnPtr key_column_full = key_col_with_type.column->convertToFullColumnIfConst();
|
|
|
|
|
2021-03-01 11:34:34 +00:00
|
|
|
if (!isTuple(key_col_with_type.type))
|
|
|
|
throw Exception(
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
|
|
|
"Third argument of function ({}) must be tuple when dictionary is complex. Actual type ({}).",
|
|
|
|
getName(),
|
|
|
|
key_col_with_type.type->getName());
|
|
|
|
|
2020-12-19 14:27:39 +00:00
|
|
|
const auto & key_columns = typeid_cast<const ColumnTuple &>(*key_column_full).getColumnsCopy();
|
|
|
|
const auto & key_types = static_cast<const DataTypeTuple &>(*key_col_with_type.type).getElements();
|
|
|
|
|
2021-02-26 15:56:41 +00:00
|
|
|
if (attribute_names.size() > 1)
|
|
|
|
{
|
|
|
|
const auto & result_tuple_type = assert_cast<const DataTypeTuple &>(*result_type);
|
|
|
|
|
|
|
|
Columns result_columns = dictionary->getColumns(
|
|
|
|
attribute_names,
|
|
|
|
result_tuple_type.getElements(),
|
|
|
|
key_columns,
|
|
|
|
key_types,
|
|
|
|
default_cols);
|
|
|
|
|
|
|
|
result = ColumnTuple::create(std::move(result_columns));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result = dictionary->getColumn(
|
|
|
|
attribute_names[0],
|
|
|
|
result_type,
|
|
|
|
key_columns,
|
|
|
|
key_types,
|
|
|
|
default_cols.front());
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2021-01-23 13:18:24 +00:00
|
|
|
else if (dictionary_key_type == DictionaryKeyType::range)
|
2020-12-18 21:43:08 +00:00
|
|
|
{
|
2021-03-05 14:12:50 +00:00
|
|
|
if (!WhichDataType(key_col_with_type.type).isUInt64())
|
|
|
|
throw Exception(
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
|
|
|
"Third argument of function ({}) must be uint64 when dictionary is range. Actual type ({}).",
|
|
|
|
getName(),
|
|
|
|
key_col_with_type.type->getName());
|
|
|
|
|
2021-02-26 15:56:41 +00:00
|
|
|
if (attribute_names.size() > 1)
|
|
|
|
{
|
|
|
|
const auto & result_tuple_type = assert_cast<const DataTypeTuple &>(*result_type);
|
|
|
|
|
|
|
|
Columns result_columns = dictionary->getColumns(
|
|
|
|
attribute_names,
|
|
|
|
result_tuple_type.getElements(),
|
|
|
|
{key_column, range_col},
|
|
|
|
{std::make_shared<DataTypeUInt64>(), range_col_type},
|
|
|
|
default_cols);
|
|
|
|
|
|
|
|
result = ColumnTuple::create(std::move(result_columns));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result = dictionary->getColumn(
|
|
|
|
attribute_names[0],
|
|
|
|
result_type,
|
|
|
|
{key_column, range_col},
|
|
|
|
{std::make_shared<DataTypeUInt64>(), range_col_type},
|
|
|
|
default_cols.front());
|
2020-12-18 21:43:08 +00:00
|
|
|
}
|
2020-12-20 20:11:28 +00:00
|
|
|
else
|
|
|
|
throw Exception{"Unknown dictionary identifier type", ErrorCodes::BAD_ARGUMENTS};
|
2020-12-19 13:24:51 +00:00
|
|
|
|
2021-01-08 21:02:47 +00:00
|
|
|
return result;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2021-01-08 21:02:47 +00:00
|
|
|
private:
|
2021-02-26 15:56:41 +00:00
|
|
|
|
|
|
|
Strings getAttributeNamesFromColumn(const ColumnPtr & column, const DataTypePtr & type) const
|
|
|
|
{
|
|
|
|
Strings attribute_names;
|
|
|
|
|
|
|
|
if (const auto * name_col = checkAndGetColumnConst<ColumnString>(column.get()))
|
|
|
|
attribute_names.emplace_back(name_col->getValue<String>());
|
|
|
|
else if (const auto * tuple_col_const = checkAndGetColumnConst<ColumnTuple>(column.get()))
|
|
|
|
{
|
|
|
|
const ColumnTuple & tuple_col = assert_cast<const ColumnTuple &>(tuple_col_const->getDataColumn());
|
|
|
|
size_t tuple_size = tuple_col.tupleSize();
|
|
|
|
|
|
|
|
if (tuple_size < 1)
|
|
|
|
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
|
|
|
"Tuple second argument of function ({}) must contain multiple constant string columns");
|
|
|
|
|
|
|
|
for (size_t i = 0; i < tuple_col.tupleSize(); ++i)
|
|
|
|
{
|
|
|
|
const auto * tuple_column = tuple_col.getColumnPtr(i).get();
|
|
|
|
|
|
|
|
const auto * attribute_name_column = checkAndGetColumn<ColumnString>(tuple_column);
|
|
|
|
|
|
|
|
if (!attribute_name_column)
|
|
|
|
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
|
|
|
"Tuple second argument of function ({}) must contain multiple constant string columns",
|
|
|
|
getName());
|
|
|
|
|
|
|
|
attribute_names.emplace_back(attribute_name_column->getDataAt(0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
|
|
|
"Illegal type ({}) of second argument of function ({}), expected a const string or const tuple of const strings.",
|
|
|
|
type->getName(),
|
|
|
|
getName());
|
|
|
|
|
|
|
|
return attribute_names;
|
|
|
|
}
|
|
|
|
|
2020-05-14 14:03:06 +00:00
|
|
|
mutable FunctionDictHelper helper;
|
2021-01-08 21:02:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename DataType, typename Name, DictionaryGetFunctionType dictionary_get_function_type>
|
|
|
|
class FunctionDictGetImpl final : public IFunction
|
|
|
|
{
|
|
|
|
using Type = typename DataType::FieldType;
|
|
|
|
|
|
|
|
public:
|
|
|
|
static constexpr auto name = Name::name;
|
|
|
|
|
|
|
|
static FunctionPtr create(const Context &context)
|
|
|
|
{
|
|
|
|
return std::make_shared<FunctionDictGetImpl>(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
explicit FunctionDictGetImpl(const Context & context_) : impl(context_) {}
|
|
|
|
|
|
|
|
String getName() const override { return name; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
size_t getNumberOfArguments() const override { return 0; }
|
|
|
|
|
|
|
|
bool isVariadic() const override { return true; }
|
|
|
|
|
|
|
|
bool useDefaultImplementationForConstants() const final { return true; }
|
|
|
|
|
|
|
|
bool isDeterministic() const override { return false; }
|
|
|
|
|
|
|
|
ColumnNumbers getArgumentsThatAreAlwaysConstant() const final { return {0, 1}; }
|
|
|
|
|
|
|
|
bool isInjective(const ColumnsWithTypeAndName & sample_columns) const override
|
|
|
|
{
|
|
|
|
return impl.isInjective(sample_columns);
|
|
|
|
}
|
|
|
|
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes &) const override
|
|
|
|
{
|
|
|
|
DataTypePtr result;
|
2021-01-12 21:26:32 +00:00
|
|
|
|
2021-01-08 21:02:47 +00:00
|
|
|
if constexpr (IsDataTypeDecimal<DataType>)
|
|
|
|
result = std::make_shared<DataType>(DataType::maxPrecision(), 0);
|
|
|
|
else
|
|
|
|
result = std::make_shared<DataType>();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
|
|
|
|
{
|
|
|
|
auto return_type = impl.getReturnTypeImpl(arguments);
|
|
|
|
|
|
|
|
if (!areTypesEqual(return_type, result_type))
|
|
|
|
throw Exception{"Dictionary attribute has different type " + return_type->getName() + " expected " + result_type->getName(),
|
|
|
|
ErrorCodes::TYPE_MISMATCH};
|
|
|
|
|
|
|
|
return impl.executeImpl(arguments, return_type, input_rows_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool areTypesEqual(const DataTypePtr & lhs, const DataTypePtr & rhs)
|
|
|
|
{
|
|
|
|
return removeNullable(recursiveRemoveLowCardinality(lhs))->equals(*removeNullable(recursiveRemoveLowCardinality(rhs)));
|
|
|
|
}
|
|
|
|
|
|
|
|
const FunctionDictGetNoType<dictionary_get_function_type> impl;
|
2015-01-22 14:32:38 +00:00
|
|
|
};
|
|
|
|
|
2020-12-18 21:43:08 +00:00
|
|
|
template<typename DataType, typename Name>
|
2021-01-02 22:08:54 +00:00
|
|
|
using FunctionDictGet = FunctionDictGetImpl<DataType, Name, DictionaryGetFunctionType::get>;
|
2020-12-18 21:43:08 +00:00
|
|
|
|
2017-11-22 21:09:23 +00:00
|
|
|
struct NameDictGetUInt8 { static constexpr auto name = "dictGetUInt8"; };
|
|
|
|
struct NameDictGetUInt16 { static constexpr auto name = "dictGetUInt16"; };
|
|
|
|
struct NameDictGetUInt32 { static constexpr auto name = "dictGetUInt32"; };
|
|
|
|
struct NameDictGetUInt64 { static constexpr auto name = "dictGetUInt64"; };
|
|
|
|
struct NameDictGetInt8 { static constexpr auto name = "dictGetInt8"; };
|
|
|
|
struct NameDictGetInt16 { static constexpr auto name = "dictGetInt16"; };
|
|
|
|
struct NameDictGetInt32 { static constexpr auto name = "dictGetInt32"; };
|
|
|
|
struct NameDictGetInt64 { static constexpr auto name = "dictGetInt64"; };
|
|
|
|
struct NameDictGetFloat32 { static constexpr auto name = "dictGetFloat32"; };
|
|
|
|
struct NameDictGetFloat64 { static constexpr auto name = "dictGetFloat64"; };
|
|
|
|
struct NameDictGetDate { static constexpr auto name = "dictGetDate"; };
|
|
|
|
struct NameDictGetDateTime { static constexpr auto name = "dictGetDateTime"; };
|
|
|
|
struct NameDictGetUUID { static constexpr auto name = "dictGetUUID"; };
|
2019-05-23 14:04:33 +00:00
|
|
|
struct NameDictGetDecimal32 { static constexpr auto name = "dictGetDecimal32"; };
|
|
|
|
struct NameDictGetDecimal64 { static constexpr auto name = "dictGetDecimal64"; };
|
|
|
|
struct NameDictGetDecimal128 { static constexpr auto name = "dictGetDecimal128"; };
|
2020-12-18 21:43:08 +00:00
|
|
|
struct NameDictGetString { static constexpr auto name = "dictGetString"; };
|
2017-11-22 21:09:23 +00:00
|
|
|
|
|
|
|
using FunctionDictGetUInt8 = FunctionDictGet<DataTypeUInt8, NameDictGetUInt8>;
|
|
|
|
using FunctionDictGetUInt16 = FunctionDictGet<DataTypeUInt16, NameDictGetUInt16>;
|
|
|
|
using FunctionDictGetUInt32 = FunctionDictGet<DataTypeUInt32, NameDictGetUInt32>;
|
|
|
|
using FunctionDictGetUInt64 = FunctionDictGet<DataTypeUInt64, NameDictGetUInt64>;
|
|
|
|
using FunctionDictGetInt8 = FunctionDictGet<DataTypeInt8, NameDictGetInt8>;
|
|
|
|
using FunctionDictGetInt16 = FunctionDictGet<DataTypeInt16, NameDictGetInt16>;
|
|
|
|
using FunctionDictGetInt32 = FunctionDictGet<DataTypeInt32, NameDictGetInt32>;
|
|
|
|
using FunctionDictGetInt64 = FunctionDictGet<DataTypeInt64, NameDictGetInt64>;
|
|
|
|
using FunctionDictGetFloat32 = FunctionDictGet<DataTypeFloat32, NameDictGetFloat32>;
|
|
|
|
using FunctionDictGetFloat64 = FunctionDictGet<DataTypeFloat64, NameDictGetFloat64>;
|
|
|
|
using FunctionDictGetDate = FunctionDictGet<DataTypeDate, NameDictGetDate>;
|
|
|
|
using FunctionDictGetDateTime = FunctionDictGet<DataTypeDateTime, NameDictGetDateTime>;
|
|
|
|
using FunctionDictGetUUID = FunctionDictGet<DataTypeUUID, NameDictGetUUID>;
|
2019-05-23 14:04:33 +00:00
|
|
|
using FunctionDictGetDecimal32 = FunctionDictGet<DataTypeDecimal<Decimal32>, NameDictGetDecimal32>;
|
|
|
|
using FunctionDictGetDecimal64 = FunctionDictGet<DataTypeDecimal<Decimal64>, NameDictGetDecimal64>;
|
|
|
|
using FunctionDictGetDecimal128 = FunctionDictGet<DataTypeDecimal<Decimal128>, NameDictGetDecimal128>;
|
2020-12-18 21:43:08 +00:00
|
|
|
using FunctionDictGetString = FunctionDictGet<DataTypeString, NameDictGetString>;
|
2017-11-22 21:09:23 +00:00
|
|
|
|
2020-12-18 21:43:08 +00:00
|
|
|
template<typename DataType, typename Name>
|
2021-01-02 22:08:54 +00:00
|
|
|
using FunctionDictGetOrDefault = FunctionDictGetImpl<DataType, Name, DictionaryGetFunctionType::getOrDefault>;
|
2015-11-10 09:22:25 +00:00
|
|
|
|
2017-11-22 21:09:23 +00:00
|
|
|
struct NameDictGetUInt8OrDefault { static constexpr auto name = "dictGetUInt8OrDefault"; };
|
|
|
|
struct NameDictGetUInt16OrDefault { static constexpr auto name = "dictGetUInt16OrDefault"; };
|
|
|
|
struct NameDictGetUInt32OrDefault { static constexpr auto name = "dictGetUInt32OrDefault"; };
|
|
|
|
struct NameDictGetUInt64OrDefault { static constexpr auto name = "dictGetUInt64OrDefault"; };
|
|
|
|
struct NameDictGetInt8OrDefault { static constexpr auto name = "dictGetInt8OrDefault"; };
|
|
|
|
struct NameDictGetInt16OrDefault { static constexpr auto name = "dictGetInt16OrDefault"; };
|
|
|
|
struct NameDictGetInt32OrDefault { static constexpr auto name = "dictGetInt32OrDefault"; };
|
|
|
|
struct NameDictGetInt64OrDefault { static constexpr auto name = "dictGetInt64OrDefault"; };
|
|
|
|
struct NameDictGetFloat32OrDefault { static constexpr auto name = "dictGetFloat32OrDefault"; };
|
|
|
|
struct NameDictGetFloat64OrDefault { static constexpr auto name = "dictGetFloat64OrDefault"; };
|
|
|
|
struct NameDictGetDateOrDefault { static constexpr auto name = "dictGetDateOrDefault"; };
|
|
|
|
struct NameDictGetDateTimeOrDefault { static constexpr auto name = "dictGetDateTimeOrDefault"; };
|
|
|
|
struct NameDictGetUUIDOrDefault { static constexpr auto name = "dictGetUUIDOrDefault"; };
|
2019-05-23 14:04:33 +00:00
|
|
|
struct NameDictGetDecimal32OrDefault { static constexpr auto name = "dictGetDecimal32OrDefault"; };
|
|
|
|
struct NameDictGetDecimal64OrDefault { static constexpr auto name = "dictGetDecimal64OrDefault"; };
|
|
|
|
struct NameDictGetDecimal128OrDefault { static constexpr auto name = "dictGetDecimal128OrDefault"; };
|
2020-12-18 21:43:08 +00:00
|
|
|
struct NameDictGetStringOrDefault { static constexpr auto name = "dictGetStringOrDefault"; };
|
2017-11-22 21:09:23 +00:00
|
|
|
|
2017-12-23 23:16:40 +00:00
|
|
|
using FunctionDictGetUInt8OrDefault = FunctionDictGetOrDefault<DataTypeUInt8, NameDictGetUInt8OrDefault>;
|
|
|
|
using FunctionDictGetUInt16OrDefault = FunctionDictGetOrDefault<DataTypeUInt16, NameDictGetUInt16OrDefault>;
|
|
|
|
using FunctionDictGetUInt32OrDefault = FunctionDictGetOrDefault<DataTypeUInt32, NameDictGetUInt32OrDefault>;
|
|
|
|
using FunctionDictGetUInt64OrDefault = FunctionDictGetOrDefault<DataTypeUInt64, NameDictGetUInt64OrDefault>;
|
|
|
|
using FunctionDictGetInt8OrDefault = FunctionDictGetOrDefault<DataTypeInt8, NameDictGetInt8OrDefault>;
|
|
|
|
using FunctionDictGetInt16OrDefault = FunctionDictGetOrDefault<DataTypeInt16, NameDictGetInt16OrDefault>;
|
|
|
|
using FunctionDictGetInt32OrDefault = FunctionDictGetOrDefault<DataTypeInt32, NameDictGetInt32OrDefault>;
|
|
|
|
using FunctionDictGetInt64OrDefault = FunctionDictGetOrDefault<DataTypeInt64, NameDictGetInt64OrDefault>;
|
|
|
|
using FunctionDictGetFloat32OrDefault = FunctionDictGetOrDefault<DataTypeFloat32, NameDictGetFloat32OrDefault>;
|
|
|
|
using FunctionDictGetFloat64OrDefault = FunctionDictGetOrDefault<DataTypeFloat64, NameDictGetFloat64OrDefault>;
|
|
|
|
using FunctionDictGetDateOrDefault = FunctionDictGetOrDefault<DataTypeDate, NameDictGetDateOrDefault>;
|
|
|
|
using FunctionDictGetDateTimeOrDefault = FunctionDictGetOrDefault<DataTypeDateTime, NameDictGetDateTimeOrDefault>;
|
|
|
|
using FunctionDictGetUUIDOrDefault = FunctionDictGetOrDefault<DataTypeUUID, NameDictGetUUIDOrDefault>;
|
2019-05-23 14:04:33 +00:00
|
|
|
using FunctionDictGetDecimal32OrDefault = FunctionDictGetOrDefault<DataTypeDecimal<Decimal32>, NameDictGetDecimal32OrDefault>;
|
|
|
|
using FunctionDictGetDecimal64OrDefault = FunctionDictGetOrDefault<DataTypeDecimal<Decimal64>, NameDictGetDecimal64OrDefault>;
|
|
|
|
using FunctionDictGetDecimal128OrDefault = FunctionDictGetOrDefault<DataTypeDecimal<Decimal128>, NameDictGetDecimal128OrDefault>;
|
2020-12-18 21:43:08 +00:00
|
|
|
using FunctionDictGetStringOrDefault = FunctionDictGetOrDefault<DataTypeString, NameDictGetStringOrDefault>;
|
2015-11-10 09:22:25 +00:00
|
|
|
|
2017-03-25 23:42:04 +00:00
|
|
|
/// Functions to work with hierarchies.
|
|
|
|
|
2015-01-28 13:20:20 +00:00
|
|
|
class FunctionDictGetHierarchy final : public IFunction
|
|
|
|
{
|
|
|
|
public:
|
2017-04-01 07:20:54 +00:00
|
|
|
static constexpr auto name = "dictGetHierarchy";
|
2015-01-28 13:20:20 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
static FunctionPtr create(const Context & context)
|
|
|
|
{
|
2020-05-14 14:03:06 +00:00
|
|
|
return std::make_shared<FunctionDictGetHierarchy>(context);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2015-01-28 13:20:20 +00:00
|
|
|
|
2020-10-18 14:49:19 +00:00
|
|
|
explicit FunctionDictGetHierarchy(const Context & context_) : helper(context_) {}
|
2015-01-28 13:20:20 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
String getName() const override { return name; }
|
2015-01-28 13:20:20 +00:00
|
|
|
|
|
|
|
private:
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t getNumberOfArguments() const override { return 2; }
|
2020-10-14 14:04:50 +00:00
|
|
|
bool isInjective(const ColumnsWithTypeAndName & /*sample_columns*/) const override { return true; }
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-03-16 03:03:17 +00:00
|
|
|
bool useDefaultImplementationForConstants() const final { return true; }
|
|
|
|
ColumnNumbers getArgumentsThatAreAlwaysConstant() const final { return {0}; }
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
|
|
|
{
|
2018-09-07 14:37:26 +00:00
|
|
|
if (!isString(arguments[0]))
|
2018-03-16 03:03:17 +00:00
|
|
|
throw Exception{"Illegal type " + arguments[0]->getName() + " of first argument of function " + getName()
|
|
|
|
+ ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-09-07 14:37:26 +00:00
|
|
|
if (!WhichDataType(arguments[1]).isUInt64())
|
2018-03-16 03:03:17 +00:00
|
|
|
throw Exception{"Illegal type " + arguments[1]->getName() + " of second argument of function " + getName()
|
|
|
|
+ ", must be UInt64.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeUInt64>());
|
|
|
|
}
|
|
|
|
|
2018-08-08 11:26:18 +00:00
|
|
|
bool isDeterministic() const override { return false; }
|
2018-02-21 17:05:21 +00:00
|
|
|
|
2020-11-17 13:24:45 +00:00
|
|
|
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2018-04-24 07:16:39 +00:00
|
|
|
if (input_rows_count == 0)
|
2020-10-18 14:49:19 +00:00
|
|
|
return result_type->createColumn();
|
2018-03-16 03:13:13 +00:00
|
|
|
|
2021-03-24 16:31:00 +00:00
|
|
|
auto dictionary = helper.getDictionary(arguments[0]);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-03-24 16:31:00 +00:00
|
|
|
if (!dictionary->hasHierarchy())
|
|
|
|
throw Exception(ErrorCodes::UNSUPPORTED_METHOD,
|
|
|
|
"Dictionary ({}) does not support hierarchy",
|
|
|
|
dictionary->getFullName());
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-03-24 16:31:00 +00:00
|
|
|
ColumnPtr result = dictionary->getHierarchy(arguments[1].column, std::make_shared<DataTypeUInt64>());
|
|
|
|
return result;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 14:03:06 +00:00
|
|
|
mutable FunctionDictHelper helper;
|
2015-01-28 13:20:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class FunctionDictIsIn final : public IFunction
|
|
|
|
{
|
|
|
|
public:
|
2017-04-01 07:20:54 +00:00
|
|
|
static constexpr auto name = "dictIsIn";
|
2015-01-28 13:20:20 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
static FunctionPtr create(const Context & context)
|
|
|
|
{
|
2020-05-14 14:03:06 +00:00
|
|
|
return std::make_shared<FunctionDictIsIn>(context);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2015-01-28 13:20:20 +00:00
|
|
|
|
2020-10-18 14:49:19 +00:00
|
|
|
explicit FunctionDictIsIn(const Context & context_)
|
2020-05-14 14:03:06 +00:00
|
|
|
: helper(context_) {}
|
2015-01-28 13:20:20 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
String getName() const override { return name; }
|
2015-01-28 13:20:20 +00:00
|
|
|
|
|
|
|
private:
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t getNumberOfArguments() const override { return 3; }
|
|
|
|
|
2018-03-16 03:03:17 +00:00
|
|
|
bool useDefaultImplementationForConstants() const final { return true; }
|
|
|
|
ColumnNumbers getArgumentsThatAreAlwaysConstant() const final { return {0}; }
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
|
|
|
{
|
2018-09-07 14:37:26 +00:00
|
|
|
if (!isString(arguments[0]))
|
2018-03-16 03:03:17 +00:00
|
|
|
throw Exception{"Illegal type " + arguments[0]->getName() + " of first argument of function " + getName()
|
|
|
|
+ ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-09-07 14:37:26 +00:00
|
|
|
if (!WhichDataType(arguments[1]).isUInt64())
|
2018-03-16 03:03:17 +00:00
|
|
|
throw Exception{"Illegal type " + arguments[1]->getName() + " of second argument of function " + getName()
|
|
|
|
+ ", must be UInt64.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-09-07 14:37:26 +00:00
|
|
|
if (!WhichDataType(arguments[2]).isUInt64())
|
2018-03-16 03:03:17 +00:00
|
|
|
throw Exception{"Illegal type " + arguments[2]->getName() + " of third argument of function " + getName()
|
|
|
|
+ ", must be UInt64.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
return std::make_shared<DataTypeUInt8>();
|
|
|
|
}
|
|
|
|
|
2018-08-08 11:26:18 +00:00
|
|
|
bool isDeterministic() const override { return false; }
|
2018-02-21 17:05:21 +00:00
|
|
|
|
2020-11-17 13:24:45 +00:00
|
|
|
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2018-04-24 07:16:39 +00:00
|
|
|
if (input_rows_count == 0)
|
2020-10-18 14:49:19 +00:00
|
|
|
return result_type->createColumn();
|
2018-03-16 03:13:13 +00:00
|
|
|
|
2020-10-18 14:49:19 +00:00
|
|
|
auto dict = helper.getDictionary(arguments[0]);
|
2019-09-11 11:14:55 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (!dict->hasHierarchy())
|
2021-03-24 16:31:00 +00:00
|
|
|
throw Exception(ErrorCodes::UNSUPPORTED_METHOD, "Dictionary ({}) does not support hierarchy", dict->getFullName());
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-03-24 16:31:00 +00:00
|
|
|
ColumnPtr res = dict->isInHierarchy(arguments[1].column, arguments[2].column, std::make_shared<DataTypeUInt64>());
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-03-24 16:31:00 +00:00
|
|
|
return res;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 14:03:06 +00:00
|
|
|
mutable FunctionDictHelper helper;
|
2015-01-28 13:20:20 +00:00
|
|
|
};
|
|
|
|
|
2021-03-24 19:55:06 +00:00
|
|
|
class FunctionDictGetChildren final : public IFunction
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static constexpr auto name = "dictGetChildren";
|
|
|
|
|
|
|
|
static FunctionPtr create(const Context & context)
|
|
|
|
{
|
|
|
|
return std::make_shared<FunctionDictGetChildren>(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
explicit FunctionDictGetChildren(const Context & context_)
|
|
|
|
: helper(context_) {}
|
|
|
|
|
|
|
|
String getName() const override { return name; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
size_t getNumberOfArguments() const override { return 2; }
|
|
|
|
|
|
|
|
bool useDefaultImplementationForConstants() const final { return true; }
|
|
|
|
ColumnNumbers getArgumentsThatAreAlwaysConstant() const final { return {0}; }
|
|
|
|
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
|
|
|
{
|
|
|
|
if (!isString(arguments[0]))
|
|
|
|
throw Exception{"Illegal type " + arguments[0]->getName() + " of first argument of function " + getName()
|
|
|
|
+ ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
|
|
|
|
|
|
|
if (!WhichDataType(arguments[1]).isUInt64())
|
|
|
|
throw Exception{"Illegal type " + arguments[1]->getName() + " of second argument of function " + getName()
|
|
|
|
+ ", must be UInt64.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
|
|
|
|
|
|
|
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeUInt64>());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isDeterministic() const override { return false; }
|
|
|
|
|
|
|
|
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
|
|
|
|
{
|
|
|
|
if (input_rows_count == 0)
|
|
|
|
return result_type->createColumn();
|
|
|
|
|
|
|
|
auto dict = helper.getDictionary(arguments[0]);
|
|
|
|
|
|
|
|
if (!dict->hasHierarchy())
|
|
|
|
throw Exception(ErrorCodes::UNSUPPORTED_METHOD, "Dictionary ({}) does not support hierarchy", dict->getFullName());
|
|
|
|
|
|
|
|
ColumnPtr res = dict->getDescendands(arguments[1].column, std::make_shared<DataTypeUInt64>(), 0);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutable FunctionDictHelper helper;
|
|
|
|
};
|
|
|
|
|
|
|
|
class FunctionDictGetDescendands final : public IFunction
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static constexpr auto name = "dictGetDescendands";
|
|
|
|
|
|
|
|
static FunctionPtr create(const Context & context)
|
|
|
|
{
|
|
|
|
return std::make_shared<FunctionDictGetDescendands>(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
explicit FunctionDictGetDescendands(const Context & context_)
|
|
|
|
: helper(context_) {}
|
|
|
|
|
|
|
|
String getName() const override { return name; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
size_t getNumberOfArguments() const override { return 3; }
|
|
|
|
|
|
|
|
bool useDefaultImplementationForConstants() const final { return true; }
|
|
|
|
ColumnNumbers getArgumentsThatAreAlwaysConstant() const final { return {0, 2}; }
|
|
|
|
|
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
|
|
|
{
|
|
|
|
if (!isString(arguments[0]))
|
|
|
|
throw Exception{"Illegal type " + arguments[0]->getName() + " of first argument of function " + getName()
|
|
|
|
+ ", expected a string.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
|
|
|
|
|
|
|
if (!WhichDataType(arguments[1]).isUInt64())
|
|
|
|
throw Exception{"Illegal type " + arguments[1]->getName() + " of second argument of function " + getName()
|
|
|
|
+ ", must be UInt64.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
|
|
|
|
|
|
|
if (!WhichDataType(arguments[2]).isUInt64())
|
|
|
|
throw Exception{"Illegal type " + arguments[1]->getName() + " of third argument of function " + getName()
|
|
|
|
+ ", must be const UInt64.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
|
|
|
|
|
|
|
return std::make_shared<DataTypeUInt8>();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isDeterministic() const override { return false; }
|
|
|
|
|
|
|
|
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
|
|
|
|
{
|
|
|
|
if (input_rows_count == 0)
|
|
|
|
return result_type->createColumn();
|
|
|
|
|
|
|
|
const auto * level_const_column = checkAndGetColumnConst<ColumnVector<UInt64>>(arguments[2].column.get());
|
|
|
|
|
|
|
|
if (!level_const_column)
|
|
|
|
throw Exception{"Illegal type " + arguments[1].type->getName() + " of third argument of function " + getName()
|
|
|
|
+ ", must be const UInt64.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
|
|
|
|
|
|
|
auto dict = helper.getDictionary(arguments[0]);
|
|
|
|
|
|
|
|
if (!dict->hasHierarchy())
|
|
|
|
throw Exception(ErrorCodes::UNSUPPORTED_METHOD, "Dictionary ({}) does not support hierarchy", dict->getFullName());
|
|
|
|
|
|
|
|
size_t level = static_cast<size_t>(level_const_column->getValue<UInt64>());
|
|
|
|
ColumnPtr res = dict->getDescendands(arguments[1].column, std::make_shared<DataTypeUInt64>(), level);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutable FunctionDictHelper helper;
|
|
|
|
};
|
|
|
|
|
2018-08-26 00:52:58 +00:00
|
|
|
}
|