diff --git a/src/DataTypes/DataTypeArray.cpp b/src/DataTypes/DataTypeArray.cpp index 24cd759e2a5..6e5760933eb 100644 --- a/src/DataTypes/DataTypeArray.cpp +++ b/src/DataTypes/DataTypeArray.cpp @@ -69,6 +69,11 @@ String DataTypeArray::doGetPrettyName(size_t indent) const return s.str(); } +void DataTypeArray::forEachChild(const ChildCallback & callback) const +{ + callback(*nested); + nested->forEachChild(callback); +} static DataTypePtr create(const ASTPtr & arguments) { diff --git a/src/DataTypes/DataTypeArray.h b/src/DataTypes/DataTypeArray.h index 6a09b3b530d..4423f137e1a 100644 --- a/src/DataTypes/DataTypeArray.h +++ b/src/DataTypes/DataTypeArray.h @@ -43,6 +43,7 @@ public: MutableColumnPtr createColumn() const override; + void forEachChild(const ChildCallback & callback) const override; Field getDefault() const override; diff --git a/src/DataTypes/DataTypeLowCardinality.cpp b/src/DataTypes/DataTypeLowCardinality.cpp index 3e94b533c7a..5af1f28cbad 100644 --- a/src/DataTypes/DataTypeLowCardinality.cpp +++ b/src/DataTypes/DataTypeLowCardinality.cpp @@ -153,6 +153,12 @@ SerializationPtr DataTypeLowCardinality::doGetDefaultSerialization() const return std::make_shared(dictionary_type); } +void DataTypeLowCardinality::forEachChild(const ChildCallback & callback) const +{ + callback(*dictionary_type); + dictionary_type->forEachChild(callback); +} + static DataTypePtr create(const ASTPtr & arguments) { diff --git a/src/DataTypes/DataTypeLowCardinality.h b/src/DataTypes/DataTypeLowCardinality.h index 389e24ef2a9..cd926bb595c 100644 --- a/src/DataTypes/DataTypeLowCardinality.h +++ b/src/DataTypes/DataTypeLowCardinality.h @@ -60,6 +60,8 @@ public: static MutableColumnUniquePtr createColumnUnique(const IDataType & keys_type); static MutableColumnUniquePtr createColumnUnique(const IDataType & keys_type, MutableColumnPtr && keys); + void forEachChild(const ChildCallback & callback) const override; + private: SerializationPtr doGetDefaultSerialization() const override; diff --git a/src/DataTypes/DataTypeMap.cpp b/src/DataTypes/DataTypeMap.cpp index 1f246af74d3..4b85606ff26 100644 --- a/src/DataTypes/DataTypeMap.cpp +++ b/src/DataTypes/DataTypeMap.cpp @@ -143,6 +143,14 @@ DataTypePtr DataTypeMap::getNestedTypeWithUnnamedTuple() const return std::make_shared(std::make_shared(from_tuple.getElements())); } +void DataTypeMap::forEachChild(const DB::IDataType::ChildCallback & callback) const +{ + callback(*key_type); + key_type->forEachChild(callback); + callback(*value_type); + value_type->forEachChild(callback); +} + static DataTypePtr create(const ASTPtr & arguments) { if (!arguments || arguments->children.size() != 2) diff --git a/src/DataTypes/DataTypeMap.h b/src/DataTypes/DataTypeMap.h index 257888a8e44..7281cca1bb1 100644 --- a/src/DataTypes/DataTypeMap.h +++ b/src/DataTypes/DataTypeMap.h @@ -54,6 +54,8 @@ public: static bool checkKeyType(DataTypePtr key_type); + void forEachChild(const ChildCallback & callback) const override; + private: void assertKeyType() const; }; diff --git a/src/DataTypes/DataTypeNullable.cpp b/src/DataTypes/DataTypeNullable.cpp index 484d779551f..16d5d41e5e5 100644 --- a/src/DataTypes/DataTypeNullable.cpp +++ b/src/DataTypes/DataTypeNullable.cpp @@ -61,6 +61,12 @@ SerializationPtr DataTypeNullable::doGetDefaultSerialization() const return std::make_shared(nested_data_type->getDefaultSerialization()); } +void DataTypeNullable::forEachChild(const ChildCallback & callback) const +{ + callback(*nested_data_type); + nested_data_type->forEachChild(callback); +} + static DataTypePtr create(const ASTPtr & arguments) { diff --git a/src/DataTypes/DataTypeNullable.h b/src/DataTypes/DataTypeNullable.h index 7ad0e1ba5f1..b102c767993 100644 --- a/src/DataTypes/DataTypeNullable.h +++ b/src/DataTypes/DataTypeNullable.h @@ -43,6 +43,9 @@ public: bool canBePromoted() const override { return nested_data_type->canBePromoted(); } const DataTypePtr & getNestedType() const { return nested_data_type; } + + void forEachChild(const ChildCallback & callback) const override; + private: SerializationPtr doGetDefaultSerialization() const override; diff --git a/src/DataTypes/DataTypeTuple.cpp b/src/DataTypes/DataTypeTuple.cpp index 5c9d5a3366e..26a871182a7 100644 --- a/src/DataTypes/DataTypeTuple.cpp +++ b/src/DataTypes/DataTypeTuple.cpp @@ -376,6 +376,15 @@ SerializationInfoPtr DataTypeTuple::getSerializationInfo(const IColumn & column) return std::make_shared(std::move(infos), names, SerializationInfo::Settings{}); } +void DataTypeTuple::forEachChild(const ChildCallback & callback) const +{ + for (const auto & elem : elems) + { + callback(*elem); + elem->forEachChild(callback); + } +} + static DataTypePtr create(const ASTPtr & arguments) { diff --git a/src/DataTypes/DataTypeTuple.h b/src/DataTypes/DataTypeTuple.h index db49b7f22d1..4e5a0c1b33c 100644 --- a/src/DataTypes/DataTypeTuple.h +++ b/src/DataTypes/DataTypeTuple.h @@ -70,6 +70,8 @@ public: String getNameByPosition(size_t i) const; bool haveExplicitNames() const { return have_explicit_names; } + + void forEachChild(const ChildCallback & callback) const override; }; } diff --git a/src/DataTypes/DataTypeVariant.cpp b/src/DataTypes/DataTypeVariant.cpp index 456b4ea03b6..0543507a14d 100644 --- a/src/DataTypes/DataTypeVariant.cpp +++ b/src/DataTypes/DataTypeVariant.cpp @@ -175,6 +175,15 @@ SerializationPtr DataTypeVariant::doGetDefaultSerialization() const return std::make_shared(std::move(serializations), std::move(variant_names), SerializationVariant::getVariantsDeserializeTextOrder(variants), getName()); } +void DataTypeVariant::forEachChild(const DB::IDataType::ChildCallback & callback) const +{ + for (const auto & variant : variants) + { + callback(*variant); + variant->forEachChild(callback); + } +} + static DataTypePtr create(const ASTPtr & arguments) { if (!arguments || arguments->children.empty()) diff --git a/src/DataTypes/DataTypeVariant.h b/src/DataTypes/DataTypeVariant.h index d26ce4ea90f..2a2206f985a 100644 --- a/src/DataTypes/DataTypeVariant.h +++ b/src/DataTypes/DataTypeVariant.h @@ -54,6 +54,8 @@ public: /// Check if Variant has provided type in the list of variants and return its discriminator. std::optional tryGetVariantDiscriminator(const DataTypePtr & type) const; + void forEachChild(const ChildCallback & callback) const override; + private: std::string doGetName() const override; std::string doGetPrettyName(size_t indent) const override; diff --git a/src/DataTypes/IDataType.h b/src/DataTypes/IDataType.h index 48cc127746f..220658afda5 100644 --- a/src/DataTypes/IDataType.h +++ b/src/DataTypes/IDataType.h @@ -111,6 +111,10 @@ public: const SubcolumnCallback & callback, const SubstreamData & data); + /// Call callback for each nested type recursively. + using ChildCallback = std::function; + virtual void forEachChild(const ChildCallback &) const {} + Names getSubcolumnNames() const; virtual MutableSerializationInfoPtr createSerializationInfo(const SerializationInfo::Settings & settings) const; diff --git a/src/Interpreters/parseColumnsListForTableFunction.cpp b/src/Interpreters/parseColumnsListForTableFunction.cpp index 056674c4379..1499568cec9 100644 --- a/src/Interpreters/parseColumnsListForTableFunction.cpp +++ b/src/Interpreters/parseColumnsListForTableFunction.cpp @@ -7,11 +7,6 @@ #include #include #include -#include -#include -#include -#include - namespace DB { @@ -24,84 +19,64 @@ namespace ErrorCodes } -void validateDataType(const DataTypePtr & type, const DataTypeValidationSettings & settings) +void validateDataType(const DataTypePtr & type_to_check, const DataTypeValidationSettings & settings) { - if (!settings.allow_suspicious_low_cardinality_types) + auto validate_callback = [&](const IDataType & data_type) { - if (const auto * lc_type = typeid_cast(type.get())) + if (!settings.allow_suspicious_low_cardinality_types) { - if (!isStringOrFixedString(*removeNullable(lc_type->getDictionaryType()))) - throw Exception( - ErrorCodes::SUSPICIOUS_TYPE_FOR_LOW_CARDINALITY, - "Creating columns of type {} is prohibited by default due to expected negative impact on performance. " - "It can be enabled with the \"allow_suspicious_low_cardinality_types\" setting.", - lc_type->getName()); + if (const auto * lc_type = typeid_cast(&data_type)) + { + if (!isStringOrFixedString(*removeNullable(lc_type->getDictionaryType()))) + throw Exception( + ErrorCodes::SUSPICIOUS_TYPE_FOR_LOW_CARDINALITY, + "Creating columns of type {} is prohibited by default due to expected negative impact on performance. " + "It can be enabled with the \"allow_suspicious_low_cardinality_types\" setting.", + lc_type->getName()); + } } - } - if (!settings.allow_experimental_object_type) - { - if (type->hasDynamicSubcolumns()) + if (!settings.allow_experimental_object_type) { - throw Exception( - ErrorCodes::ILLEGAL_COLUMN, - "Cannot create column with type '{}' because experimental Object type is not allowed. " - "Set setting allow_experimental_object_type = 1 in order to allow it", type->getName()); - } - } - - if (!settings.allow_suspicious_fixed_string_types) - { - if (const auto * fixed_string = typeid_cast(type.get())) - { - if (fixed_string->getN() > MAX_FIXEDSTRING_SIZE_WITHOUT_SUSPICIOUS) + if (data_type.hasDynamicSubcolumns()) + { throw Exception( ErrorCodes::ILLEGAL_COLUMN, - "Cannot create column with type '{}' because fixed string with size > {} is suspicious. " - "Set setting allow_suspicious_fixed_string_types = 1 in order to allow it", - type->getName(), - MAX_FIXEDSTRING_SIZE_WITHOUT_SUSPICIOUS); + "Cannot create column with type '{}' because experimental Object type is not allowed. " + "Set setting allow_experimental_object_type = 1 in order to allow it", + data_type.getName()); + } } - } - if (!settings.allow_experimental_variant_type) - { - if (isVariant(type)) + if (!settings.allow_suspicious_fixed_string_types) { - throw Exception( - ErrorCodes::ILLEGAL_COLUMN, - "Cannot create column with type '{}' because experimental Variant type is not allowed. " - "Set setting allow_experimental_variant_type = 1 in order to allow it", type->getName()); + if (const auto * fixed_string = typeid_cast(&data_type)) + { + if (fixed_string->getN() > MAX_FIXEDSTRING_SIZE_WITHOUT_SUSPICIOUS) + throw Exception( + ErrorCodes::ILLEGAL_COLUMN, + "Cannot create column with type '{}' because fixed string with size > {} is suspicious. " + "Set setting allow_suspicious_fixed_string_types = 1 in order to allow it", + data_type.getName(), + MAX_FIXEDSTRING_SIZE_WITHOUT_SUSPICIOUS); + } } - } - if (const auto * nullable_type = typeid_cast(type.get())) - { - validateDataType(nullable_type->getNestedType(), settings); - } - else if (const auto * lc_type = typeid_cast(type.get())) - { - validateDataType(lc_type->getDictionaryType(), settings); - } - else if (const auto * array_type = typeid_cast(type.get())) - { - validateDataType(array_type->getNestedType(), settings); - } - else if (const auto * tuple_type = typeid_cast(type.get())) - { - for (const auto & element : tuple_type->getElements()) - validateDataType(element, settings); - } - else if (const auto * map_type = typeid_cast(type.get())) - { - validateDataType(map_type->getKeyType(), settings); - validateDataType(map_type->getValueType(), settings); - } - else if (const auto * variant_type = typeid_cast(type.get())) - { - for (const auto & variant : variant_type->getVariants()) - validateDataType(variant, settings); - } + if (!settings.allow_experimental_variant_type) + { + if (isVariant(data_type)) + { + throw Exception( + ErrorCodes::ILLEGAL_COLUMN, + "Cannot create column with type '{}' because experimental Variant type is not allowed. " + "Set setting allow_experimental_variant_type = 1 in order to allow it", + data_type.getName()); + } + } + }; + + validate_callback(*type_to_check); + type_to_check->forEachChild(validate_callback); } ColumnsDescription parseColumnsListFromString(const std::string & structure, const ContextPtr & context)