#include #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(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "DataTypeLowCardinality is supported only for numbers, strings, Date or DateTime, but got {}", dictionary_type->getName()); } 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()(TypeList) { 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.isDate32()) 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.isIPv4()) return creator(static_cast *>(nullptr)); else if (which.isIPv6()) return creator(static_cast *>(nullptr)); else if (which.isInterval()) return creator(static_cast(nullptr)); else if (which.isInt() || which.isUInt() || which.isFloat()) { MutableColumnUniquePtr column; TypeListUtils::forEach(TypeListIntAndFloat{}, CreateColumnVector(column, *type, creator)); if (!column) throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected numeric type: {}", type->getName()); return column; } throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected dictionary type for DataTypeLowCardinality: {}", type->getName()); } MutableColumnUniquePtr DataTypeLowCardinality::createColumnUnique(const IDataType & keys_type) { auto creator = [&](auto x) { using ColumnType = typename std::remove_pointer_t; 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_t; 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(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "LowCardinality data type family must have single argument - type of elements"); 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; } DataTypePtr removeLowCardinalityAndNullable(const DataTypePtr & type) { return removeNullable(removeLowCardinality(type)); }; }