From df9ada58fb93428012e5e09107c3bea36f888aa2 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Thu, 2 Feb 2017 16:15:04 +0300 Subject: [PATCH] Add CAST(NULL AS Null) support. [#CLICKHOUSE-2787] --- .../DB/Functions/FunctionsConversion.h | 20 ++++++++++++++++++- .../00420_null_in_scalar_subqueries.reference | 2 ++ .../00420_null_in_scalar_subqueries.sql | 4 +++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/dbms/include/DB/Functions/FunctionsConversion.h b/dbms/include/DB/Functions/FunctionsConversion.h index ec2f0fdf603..8b6b98b3399 100644 --- a/dbms/include/DB/Functions/FunctionsConversion.h +++ b/dbms/include/DB/Functions/FunctionsConversion.h @@ -1498,6 +1498,22 @@ private: }; } + /// Only trivial NULL -> NULL case + WrapperType createNullWrapper(const DataTypePtr & from_type, const DataTypeNull * to_type) + { + if (!typeid_cast(from_type.get())) + throw Exception("Conversion from " + from_type->getName() + " to " + to_type->getName() + " is not supported", + ErrorCodes::CANNOT_CONVERT_TYPE); + + return [] (Block & block, const ColumnNumbers & arguments, const size_t result) + { + // just copy pointer to Null column + ColumnWithTypeAndName & res_col = block.safeGetByPosition(result); + const ColumnWithTypeAndName & src_col = block.safeGetByPosition(arguments.front()); + res_col.column = src_col.column; + }; + } + /// Actions to be taken when performing a conversion. struct Action { @@ -1622,6 +1638,8 @@ private: return createEnumWrapper(from_type, type_enum); else if (const auto type_enum = typeid_cast(to_type)) return createEnumWrapper(from_type, type_enum); + else if (const auto type_null = typeid_cast(to_type)) + return createNullWrapper(from_type, type_null); /// It's possible to use ConvertImplGenericFromString to convert from String to AggregateFunction, /// but it is disabled because deserializing aggregate functions state might be unsafe. @@ -1704,7 +1722,7 @@ public: if (from_type->isNullable()) action |= Action::UNWRAP_NULLABLE_INPUT; - else if (from_type->isNull()) + else if (from_type->isNull() && !out_return_type->isNull()) action |= Action::CONVERT_NULL; if (out_return_type->isNullable()) diff --git a/dbms/tests/queries/0_stateless/00420_null_in_scalar_subqueries.reference b/dbms/tests/queries/0_stateless/00420_null_in_scalar_subqueries.reference index c80c970ccef..e4076fb6ab0 100644 --- a/dbms/tests/queries/0_stateless/00420_null_in_scalar_subqueries.reference +++ b/dbms/tests/queries/0_stateless/00420_null_in_scalar_subqueries.reference @@ -3,3 +3,5 @@ \N \N \N +\N +\N diff --git a/dbms/tests/queries/0_stateless/00420_null_in_scalar_subqueries.sql b/dbms/tests/queries/0_stateless/00420_null_in_scalar_subqueries.sql index e929d5fe4c0..77f3fb51b30 100644 --- a/dbms/tests/queries/0_stateless/00420_null_in_scalar_subqueries.sql +++ b/dbms/tests/queries/0_stateless/00420_null_in_scalar_subqueries.sql @@ -1,5 +1,7 @@ SELECT (SELECT 1 WHERE 0); SELECT (SELECT * FROM (SELECT * FROM system.numbers LIMIT 2) WHERE number = number + 1); -SELECT (SELECT Null WHERE 1); SELECT (SELECT NULL WHERE 0); SELECT (SELECT Null WHERE nuLL IS NOT NULL); +SELECT (SELECT Null WHERE 1); +SELECT CAST(NULL as Null); +SELECT (SELECT CAST(NULL as Null) WHERE 0);