From 631d870ae3ddcca4a1bf93845a94fe8d1b34dec8 Mon Sep 17 00:00:00 2001 From: Maksim Kita Date: Wed, 21 Apr 2021 20:29:49 +0300 Subject: [PATCH 1/2] Cast to array from empty array --- src/Functions/FunctionsConversion.h | 17 ++++++++++------- ...837_cast_to_array_from_empty_array.reference | 2 ++ .../01837_cast_to_array_from_empty_array.sql | 2 ++ 3 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 tests/queries/0_stateless/01837_cast_to_array_from_empty_array.reference create mode 100644 tests/queries/0_stateless/01837_cast_to_array_from_empty_array.sql diff --git a/src/Functions/FunctionsConversion.h b/src/Functions/FunctionsConversion.h index 9b40be58862..5d38683b5f4 100644 --- a/src/Functions/FunctionsConversion.h +++ b/src/Functions/FunctionsConversion.h @@ -2517,14 +2517,17 @@ private: from_nested_type = from_type->getNestedType(); to_nested_type = to_type->getNestedType(); - from_type = checkAndGetDataType(from_nested_type.get()); - to_type = checkAndGetDataType(to_nested_type.get()); - } + if (from_type->getNumberOfDimensions() != to_type->getNumberOfDimensions()) + { + WhichDataType from_nested_data_type(from_nested_type); - /// both from_type and to_type should be nullptr now is array types had same dimensions - if ((from_type == nullptr) != (to_type == nullptr)) - throw Exception{"CAST AS Array can only be performed between same-dimensional array types or from String", - ErrorCodes::TYPE_MISMATCH}; + /// In query SELECT CAST([] AS Array(Array(String))) from type is Array(Nothing) + bool is_empty_array = from_nested_data_type.isNothing(); + if (!is_empty_array) + throw Exception(ErrorCodes::TYPE_MISMATCH, + "CAST AS Array can only be performed between same-dimensional array types or from String"); + } + } /// Prepare nested type conversion const auto nested_function = prepareUnpackDictionaries(from_nested_type, to_nested_type); diff --git a/tests/queries/0_stateless/01837_cast_to_array_from_empty_array.reference b/tests/queries/0_stateless/01837_cast_to_array_from_empty_array.reference new file mode 100644 index 00000000000..c71bf50e82f --- /dev/null +++ b/tests/queries/0_stateless/01837_cast_to_array_from_empty_array.reference @@ -0,0 +1,2 @@ +[] +[] diff --git a/tests/queries/0_stateless/01837_cast_to_array_from_empty_array.sql b/tests/queries/0_stateless/01837_cast_to_array_from_empty_array.sql new file mode 100644 index 00000000000..f3aa595f6d5 --- /dev/null +++ b/tests/queries/0_stateless/01837_cast_to_array_from_empty_array.sql @@ -0,0 +1,2 @@ +SELECT CAST([] AS Array(Array(String))); +SELECT CAST([] AS Array(Array(Array(String)))); From ddcffcb7233a8261506de3461eb115cec7d7c05a Mon Sep 17 00:00:00 2001 From: Maksim Kita Date: Thu, 22 Apr 2021 00:19:01 +0300 Subject: [PATCH 2/2] Fixed tests --- src/DataTypes/IDataType.h | 3 ++- src/Functions/FunctionsConversion.h | 38 ++++++++++++----------------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/DataTypes/IDataType.h b/src/DataTypes/IDataType.h index 9b762cfa4c5..5a676819b77 100644 --- a/src/DataTypes/IDataType.h +++ b/src/DataTypes/IDataType.h @@ -360,7 +360,8 @@ inline bool isEnum(const DataTypePtr & data_type) { return WhichDataType(data_ty inline bool isDecimal(const DataTypePtr & data_type) { return WhichDataType(data_type).isDecimal(); } inline bool isTuple(const DataTypePtr & data_type) { return WhichDataType(data_type).isTuple(); } inline bool isArray(const DataTypePtr & data_type) { return WhichDataType(data_type).isArray(); } -inline bool isMap(const DataTypePtr & data_type) {return WhichDataType(data_type).isMap(); } +inline bool isMap(const DataTypePtr & data_type) { return WhichDataType(data_type).isMap(); } +inline bool isNothing(const DataTypePtr & data_type) { return WhichDataType(data_type).isNothing(); } template inline bool isUInt8(const T & data_type) diff --git a/src/Functions/FunctionsConversion.h b/src/Functions/FunctionsConversion.h index 5d38683b5f4..1cd308c774d 100644 --- a/src/Functions/FunctionsConversion.h +++ b/src/Functions/FunctionsConversion.h @@ -2496,7 +2496,7 @@ private: } } - WrapperType createArrayWrapper(const DataTypePtr & from_type_untyped, const DataTypeArray * to_type) const + WrapperType createArrayWrapper(const DataTypePtr & from_type_untyped, const DataTypeArray & to_type) const { /// Conversion from String through parsing. if (checkAndGetDataType(from_type_untyped.get())) @@ -2507,28 +2507,24 @@ private: }; } - DataTypePtr from_nested_type; - DataTypePtr to_nested_type; const auto * from_type = checkAndGetDataType(from_type_untyped.get()); - - /// get the most nested type - if (from_type && to_type) + if (!from_type) { - from_nested_type = from_type->getNestedType(); - to_nested_type = to_type->getNestedType(); - - if (from_type->getNumberOfDimensions() != to_type->getNumberOfDimensions()) - { - WhichDataType from_nested_data_type(from_nested_type); - - /// In query SELECT CAST([] AS Array(Array(String))) from type is Array(Nothing) - bool is_empty_array = from_nested_data_type.isNothing(); - if (!is_empty_array) - throw Exception(ErrorCodes::TYPE_MISMATCH, - "CAST AS Array can only be performed between same-dimensional array types or from String"); - } + throw Exception(ErrorCodes::TYPE_MISMATCH, + "CAST AS Array can only be perforamed between same-dimensional Array or String types"); } + DataTypePtr from_nested_type = from_type->getNestedType(); + + /// In query SELECT CAST([] AS Array(Array(String))) from type is Array(Nothing) + bool from_empty_array = isNothing(from_nested_type); + + if (from_type->getNumberOfDimensions() != to_type.getNumberOfDimensions() && !from_empty_array) + throw Exception(ErrorCodes::TYPE_MISMATCH, + "CAST AS Array can only be perforamed between same-dimensional array types"); + + const DataTypePtr & to_nested_type = to_type.getNestedType(); + /// Prepare nested type conversion const auto nested_function = prepareUnpackDictionaries(from_nested_type, to_nested_type); @@ -3093,14 +3089,12 @@ private: return createStringWrapper(from_type); case TypeIndex::FixedString: return createFixedStringWrapper(from_type, checkAndGetDataType(to_type.get())->getN()); - case TypeIndex::Array: - return createArrayWrapper(from_type, checkAndGetDataType(to_type.get())); + return createArrayWrapper(from_type, static_cast(*to_type)); case TypeIndex::Tuple: return createTupleWrapper(from_type, checkAndGetDataType(to_type.get())); case TypeIndex::Map: return createMapWrapper(from_type, checkAndGetDataType(to_type.get())); - case TypeIndex::AggregateFunction: return createAggregateFunctionWrapper(from_type, checkAndGetDataType(to_type.get())); default: