#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; extern const int LOGICAL_ERROR; extern const int ILLEGAL_TYPE_OF_ARGUMENT; } DataTypeLowCardinality::DataTypeLowCardinality(DataTypePtr dictionary_type_) : dictionary_type(std::move(dictionary_type_)) { auto inner_type = dictionary_type; if (dictionary_type->isNullable()) inner_type = static_cast(*dictionary_type).getNestedType(); if (!inner_type->canBeInsideLowCardinality()) throw Exception("DataTypeLowCardinality is supported only for numbers, strings, Date or DateTime, but got " + dictionary_type->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } namespace { template struct CreateColumnVector { MutableColumnUniquePtr & column; const IDataType & keys_type; const Creator & creator; CreateColumnVector(MutableColumnUniquePtr & column_, const IDataType & keys_type_, const Creator & creator_) : column(column_), keys_type(keys_type_), creator(creator_) { } template void operator()() { if (typeid_cast *>(&keys_type)) column = creator(static_cast *>(nullptr)); } }; } template MutableColumnUniquePtr DataTypeLowCardinality::createColumnUniqueImpl(const IDataType & keys_type, const Creator & creator) { const auto * type = &keys_type; if (const auto * nullable_type = typeid_cast(&keys_type)) type = nullable_type->getNestedType().get(); WhichDataType which(type); if (which.isString()) return creator(static_cast(nullptr)); else if (which.isFixedString()) return creator(static_cast(nullptr)); else if (which.isDate()) return creator(static_cast *>(nullptr)); else if (which.isDateTime()) return creator(static_cast *>(nullptr)); else if (which.isUUID()) return creator(static_cast *>(nullptr)); else if (which.isInt() || which.isUInt() || which.isFloat()) { MutableColumnUniquePtr column; TypeListNativeNumbers::forEach(CreateColumnVector(column, *type, creator)); if (!column) throw Exception("Unexpected numeric type: " + type->getName(), ErrorCodes::LOGICAL_ERROR); return column; } throw Exception("Unexpected dictionary type for DataTypeLowCardinality: " + type->getName(), ErrorCodes::LOGICAL_ERROR); } MutableColumnUniquePtr DataTypeLowCardinality::createColumnUnique(const IDataType & keys_type) { auto creator = [&](auto x) { using ColumnType = typename std::remove_pointer::type; return ColumnUnique::create(keys_type); }; return createColumnUniqueImpl(keys_type, creator); } MutableColumnUniquePtr DataTypeLowCardinality::createColumnUnique(const IDataType & keys_type, MutableColumnPtr && keys) { auto creator = [&](auto x) { using ColumnType = typename std::remove_pointer::type; return ColumnUnique::create(std::move(keys), keys_type.isNullable()); }; return createColumnUniqueImpl(keys_type, creator); } MutableColumnPtr DataTypeLowCardinality::createColumn() const { MutableColumnPtr indexes = DataTypeUInt8().createColumn(); MutableColumnPtr dictionary = createColumnUnique(*dictionary_type); return ColumnLowCardinality::create(std::move(dictionary), std::move(indexes)); } Field DataTypeLowCardinality::getDefault() const { return dictionary_type->getDefault(); } bool DataTypeLowCardinality::equals(const IDataType & rhs) const { if (typeid(rhs) != typeid(*this)) return false; const auto & low_cardinality_rhs= static_cast(rhs); return dictionary_type->equals(*low_cardinality_rhs.dictionary_type); } SerializationPtr DataTypeLowCardinality::doGetDefaultSerialization() const { return std::make_shared(dictionary_type); } static DataTypePtr create(const ASTPtr & arguments) { if (!arguments || arguments->children.size() != 1) throw Exception("LowCardinality data type family must have single argument - type of elements", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); return std::make_shared(DataTypeFactory::instance().get(arguments->children[0])); } void registerDataTypeLowCardinality(DataTypeFactory & factory) { factory.registerDataType("LowCardinality", create); } DataTypePtr removeLowCardinality(const DataTypePtr & type) { if (const auto * low_cardinality_type = typeid_cast(type.get())) return low_cardinality_type->getDictionaryType(); return type; } }