From cbada6fe03d7cd8d43e0e393cd7d39c121fb6041 Mon Sep 17 00:00:00 2001 From: avogar Date: Mon, 9 May 2022 15:42:59 +0000 Subject: [PATCH 1/7] Fix Illegal column Nothing while using arrayMap --- src/Functions/IFunction.cpp | 14 ++++++++++++++ .../02294_nothing_arguments_in_functions.reference | 6 ++++++ .../02294_nothing_arguments_in_functions.sql | 6 ++++++ 3 files changed, 26 insertions(+) create mode 100644 tests/queries/0_stateless/02294_nothing_arguments_in_functions.reference create mode 100644 tests/queries/0_stateless/02294_nothing_arguments_in_functions.sql diff --git a/src/Functions/IFunction.cpp b/src/Functions/IFunction.cpp index 19638c78daf..95dafcbb575 100644 --- a/src/Functions/IFunction.cpp +++ b/src/Functions/IFunction.cpp @@ -275,6 +275,11 @@ ColumnPtr IExecutableFunction::executeWithoutSparseColumns(const ColumnsWithType ColumnPtr IExecutableFunction::execute(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count, bool dry_run) const { + /// Result type Nothing means that we don't need to execute function at all. + /// Example: select arrayMap(x -> 2 * x, []); + if (isNothing(result_type)) + return result_type->createColumn(); + if (useDefaultImplementationForSparseColumns()) { size_t num_sparse_columns = 0; @@ -430,6 +435,15 @@ DataTypePtr IFunctionOverloadResolver::getReturnTypeWithoutLowCardinality(const } } + /// If one of the arguments is Nothing, then we won't really execute + /// the function and the result type should be also Nothing. + /// Example: select arrayMap(x -> 2 * x, []); + for (const auto & arg : arguments) + { + if (isNothing(arg.type)) + return std::make_shared(); + } + return getReturnTypeImpl(arguments); } diff --git a/tests/queries/0_stateless/02294_nothing_arguments_in_functions.reference b/tests/queries/0_stateless/02294_nothing_arguments_in_functions.reference new file mode 100644 index 00000000000..954015207ad --- /dev/null +++ b/tests/queries/0_stateless/02294_nothing_arguments_in_functions.reference @@ -0,0 +1,6 @@ +[] +Array(Nothing) +[] +Array(Nothing) +[] +Array(Nothing) diff --git a/tests/queries/0_stateless/02294_nothing_arguments_in_functions.sql b/tests/queries/0_stateless/02294_nothing_arguments_in_functions.sql new file mode 100644 index 00000000000..3df2577e465 --- /dev/null +++ b/tests/queries/0_stateless/02294_nothing_arguments_in_functions.sql @@ -0,0 +1,6 @@ +select arrayMap(x -> 2 * x, []); +select toTypeName(arrayMap(x -> 2 * x, [])); +select arrayMap((x, y) -> x + y, [], []); +select toTypeName(arrayMap((x, y) -> x + y, [], [])); +select arrayMap((x, y) -> x + y, [], CAST([], 'Array(Int32)')); +select toTypeName(arrayMap((x, y) -> x + y, [], CAST([], 'Array(Int32)'))); From 0311dbb42295cb7f4fad712f51771419fabc16fc Mon Sep 17 00:00:00 2001 From: avogar Date: Thu, 12 May 2022 15:15:31 +0000 Subject: [PATCH 2/7] Add default implementation for Nothing, support arrays of nullable for arrayFilter and similar functions --- .../Serializations/SerializationNothing.h | 2 +- src/Functions/CastOverloadResolver.h | 1 + src/Functions/FunctionsConversion.h | 1 + src/Functions/FunctionsMiscellaneous.h | 5 +- src/Functions/IFunction.cpp | 46 +++++++++++++---- src/Functions/IFunction.h | 25 ++++++++-- src/Functions/IFunctionAdaptors.h | 2 + src/Functions/array/FunctionArrayMapped.h | 50 ++++++++++++++++--- src/Functions/array/array.cpp | 1 + src/Functions/assumeNotNull.cpp | 1 + src/Functions/castOrDefault.cpp | 2 + src/Functions/indexHint.cpp | 2 + src/Functions/isConstant.cpp | 2 + src/Functions/map.cpp | 1 + src/Functions/materialize.h | 5 ++ src/Functions/toColumnTypeName.cpp | 2 + src/Functions/toNullable.cpp | 1 + src/Functions/toTypeName.cpp | 2 + src/Functions/tuple.cpp | 1 + .../0_stateless/01882_total_rows_approx.sh | 2 +- ...4_nothing_arguments_in_functions.reference | 29 +++++++++++ .../02294_nothing_arguments_in_functions.sql | 37 ++++++++++++++ .../0_stateless/02295_type_nothing.sql | 28 +++++++++++ ...llable_arguments_in_array_filter.reference | 4 ++ ...296_nullable_arguments_in_array_filter.sql | 4 ++ 25 files changed, 232 insertions(+), 24 deletions(-) create mode 100644 tests/queries/0_stateless/02295_type_nothing.sql create mode 100644 tests/queries/0_stateless/02296_nullable_arguments_in_array_filter.reference create mode 100644 tests/queries/0_stateless/02296_nullable_arguments_in_array_filter.sql diff --git a/src/DataTypes/Serializations/SerializationNothing.h b/src/DataTypes/Serializations/SerializationNothing.h index 2de93a29763..e46a1e6ed30 100644 --- a/src/DataTypes/Serializations/SerializationNothing.h +++ b/src/DataTypes/Serializations/SerializationNothing.h @@ -16,7 +16,7 @@ class SerializationNothing : public SimpleTextSerialization private: [[noreturn]] static void throwNoSerialization() { - throw Exception("Serialization is not implemented", ErrorCodes::NOT_IMPLEMENTED); + throw Exception("Serialization is not implemented for type Nothing", ErrorCodes::NOT_IMPLEMENTED); } public: void serializeBinary(const Field &, WriteBuffer &) const override { throwNoSerialization(); } diff --git a/src/Functions/CastOverloadResolver.h b/src/Functions/CastOverloadResolver.h index cff17d810fe..9b579c34923 100644 --- a/src/Functions/CastOverloadResolver.h +++ b/src/Functions/CastOverloadResolver.h @@ -98,6 +98,7 @@ protected: } bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForLowCardinalityColumns() const override { return false; } private: diff --git a/src/Functions/FunctionsConversion.h b/src/Functions/FunctionsConversion.h index 1363e91eb0d..846c8915f26 100644 --- a/src/Functions/FunctionsConversion.h +++ b/src/Functions/FunctionsConversion.h @@ -2509,6 +2509,7 @@ protected: } bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForConstants() const override { return true; } bool useDefaultImplementationForLowCardinalityColumns() const override { return false; } ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; } diff --git a/src/Functions/FunctionsMiscellaneous.h b/src/Functions/FunctionsMiscellaneous.h index 7e8cab842c8..ff27b0cc518 100644 --- a/src/Functions/FunctionsMiscellaneous.h +++ b/src/Functions/FunctionsMiscellaneous.h @@ -50,7 +50,8 @@ public: return expr_columns.getByName(signature->return_name).column; } -bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } private: ExpressionActionsPtr expression_actions; @@ -118,6 +119,7 @@ public: String getName() const override { return "FunctionCapture"; } bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForLowCardinalityColumns() const override { return false; } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override @@ -247,6 +249,7 @@ public: String getName() const override { return name; } bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForLowCardinalityColumns() const override { return false; } DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName &) const override { return return_type; } size_t getNumberOfArguments() const override { return capture->captured_types.size(); } diff --git a/src/Functions/IFunction.cpp b/src/Functions/IFunction.cpp index 95dafcbb575..453c31302a0 100644 --- a/src/Functions/IFunction.cpp +++ b/src/Functions/IFunction.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -203,6 +204,31 @@ ColumnPtr IExecutableFunction::defaultImplementationForNulls( return nullptr; } +ColumnPtr IExecutableFunction::defaultImplementationForNothing( + const ColumnsWithTypeAndName & args, const DataTypePtr & result_type, size_t input_rows_count) const +{ + if (!useDefaultImplementationForNothing()) + return nullptr; + + bool is_nothing_type_presented = false; + for (const auto & arg : args) + is_nothing_type_presented |= isNothing(arg.type); + + if (!is_nothing_type_presented) + return nullptr; + + if (!isNothing(result_type)) + throw Exception( + ErrorCodes::LOGICAL_ERROR, + "Function {} with argument with type Nothing and default implementation for Nothing " + "is expected to return result with type Nothing, got {}", + getName(), + result_type->getName()); + + return ColumnConst::create(ColumnNothing::create(1), input_rows_count); + +} + ColumnPtr IExecutableFunction::executeWithoutLowCardinalityColumns( const ColumnsWithTypeAndName & args, const DataTypePtr & result_type, size_t input_rows_count, bool dry_run) const { @@ -212,6 +238,9 @@ ColumnPtr IExecutableFunction::executeWithoutLowCardinalityColumns( if (auto res = defaultImplementationForNulls(args, result_type, input_rows_count, dry_run)) return res; + if (auto res = defaultImplementationForNothing(args, result_type, input_rows_count)) + return res; + ColumnPtr res; if (dry_run) res = executeDryRunImpl(args, result_type, input_rows_count); @@ -275,11 +304,6 @@ ColumnPtr IExecutableFunction::executeWithoutSparseColumns(const ColumnsWithType ColumnPtr IExecutableFunction::execute(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count, bool dry_run) const { - /// Result type Nothing means that we don't need to execute function at all. - /// Example: select arrayMap(x -> 2 * x, []); - if (isNothing(result_type)) - return result_type->createColumn(); - if (useDefaultImplementationForSparseColumns()) { size_t num_sparse_columns = 0; @@ -435,13 +459,13 @@ DataTypePtr IFunctionOverloadResolver::getReturnTypeWithoutLowCardinality(const } } - /// If one of the arguments is Nothing, then we won't really execute - /// the function and the result type should be also Nothing. - /// Example: select arrayMap(x -> 2 * x, []); - for (const auto & arg : arguments) + if (!arguments.empty() && useDefaultImplementationForNothing()) { - if (isNothing(arg.type)) - return std::make_shared(); + for (const auto & arg : arguments) + { + if (isNothing(arg.type)) + return std::make_shared(); + } } return getReturnTypeImpl(arguments); diff --git a/src/Functions/IFunction.h b/src/Functions/IFunction.h index 7b272fef53d..95af8a61aae 100644 --- a/src/Functions/IFunction.h +++ b/src/Functions/IFunction.h @@ -63,6 +63,11 @@ protected: */ virtual bool useDefaultImplementationForNulls() const { return true; } + /** Default implementation in presence of arguments with type Nothing is the following: + * If some of arguments have type Nothing then default implementation is to return constant column with type Nothing + */ + virtual bool useDefaultImplementationForNothing() const { return true; } + /** If the function have non-zero number of arguments, * and if all arguments are constant, that we could automatically provide default implementation: * arguments are converted to ordinary columns with single value, then function is executed as usual, @@ -100,6 +105,9 @@ private: ColumnPtr defaultImplementationForNulls( const ColumnsWithTypeAndName & args, const DataTypePtr & result_type, size_t input_rows_count, bool dry_run) const; + ColumnPtr defaultImplementationForNothing( + const ColumnsWithTypeAndName & args, const DataTypePtr & result_type, size_t input_rows_count) const; + ColumnPtr executeWithoutLowCardinalityColumns( const ColumnsWithTypeAndName & args, const DataTypePtr & result_type, size_t input_rows_count, bool dry_run) const; @@ -166,8 +174,8 @@ public: /** If function isSuitableForConstantFolding then, this method will be called during query analyzis * if some arguments are constants. For example logical functions (AndFunction, OrFunction) can * return they result based on some constant arguments. - * Arguments are passed without modifications, useDefaultImplementationForNulls, useDefaultImplementationForConstants, - * useDefaultImplementationForLowCardinality are not applied. + * Arguments are passed without modifications, useDefaultImplementationForNulls, useDefaultImplementationForNothing, + * useDefaultImplementationForConstants, useDefaultImplementationForLowCardinality are not applied. */ virtual ColumnPtr getConstantResultForNonConstArguments( const ColumnsWithTypeAndName & /* arguments */, const DataTypePtr & /* result_type */) const { return nullptr; } @@ -354,7 +362,13 @@ protected: */ virtual bool useDefaultImplementationForNulls() const { return true; } - /** If useDefaultImplementationForNulls() is true, then change arguments for getReturnType() and build(). + /** If useDefaultImplementationForNothing() is true, then change arguments for getReturnType() and build(): + * if some of arguments are Nothing then don't call getReturnType(), call build() with return_type = Nothing, + * Otherwise build returns build(arguments, getReturnType(arguments)); + */ + virtual bool useDefaultImplementationForNothing() const { return true; } + + /** If useDefaultImplementationForLowCardinalityColumns() is true, then change arguments for getReturnType() and build(). * If function arguments has low cardinality types, convert them to ordinary types. * getReturnType returns ColumnLowCardinality if at least one argument type is ColumnLowCardinality. */ @@ -403,6 +417,11 @@ public: */ virtual bool useDefaultImplementationForNulls() const { return true; } + /** Default implementation in presence of arguments with type Nothing is the following: + * If some of arguments have type Nothing then default implementation is to return constant column with type Nothing + */ + virtual bool useDefaultImplementationForNothing() const { return true; } + /** If the function have non-zero number of arguments, * and if all arguments are constant, that we could automatically provide default implementation: * arguments are converted to ordinary columns with single value, then function is executed as usual, diff --git a/src/Functions/IFunctionAdaptors.h b/src/Functions/IFunctionAdaptors.h index ec43087ad66..dfb90fd3975 100644 --- a/src/Functions/IFunctionAdaptors.h +++ b/src/Functions/IFunctionAdaptors.h @@ -27,6 +27,7 @@ protected: } bool useDefaultImplementationForNulls() const final { return function->useDefaultImplementationForNulls(); } + bool useDefaultImplementationForNothing() const final { return function->useDefaultImplementationForNothing(); } bool useDefaultImplementationForConstants() const final { return function->useDefaultImplementationForConstants(); } bool useDefaultImplementationForLowCardinalityColumns() const final { return function->useDefaultImplementationForLowCardinalityColumns(); } bool useDefaultImplementationForSparseColumns() const final { return function->useDefaultImplementationForSparseColumns(); } @@ -124,6 +125,7 @@ public: DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override { return function->getReturnTypeImpl(arguments); } bool useDefaultImplementationForNulls() const override { return function->useDefaultImplementationForNulls(); } + bool useDefaultImplementationForNothing() const override { return function->useDefaultImplementationForNothing(); } bool useDefaultImplementationForLowCardinalityColumns() const override { return function->useDefaultImplementationForLowCardinalityColumns(); } bool useDefaultImplementationForSparseColumns() const override { return function->useDefaultImplementationForSparseColumns(); } bool canBeExecutedOnLowCardinalityDictionary() const override { return function->canBeExecutedOnLowCardinalityDictionary(); } diff --git a/src/Functions/array/FunctionArrayMapped.h b/src/Functions/array/FunctionArrayMapped.h index 58e6db86f75..f4f1d39d07f 100644 --- a/src/Functions/array/FunctionArrayMapped.h +++ b/src/Functions/array/FunctionArrayMapped.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -16,11 +17,13 @@ #include #include #include +#include #include #include #include +#include #include @@ -156,7 +159,7 @@ public: DataTypePtr nested_type = data_type->getNestedType(); - if (Impl::needBoolean() && !WhichDataType(nested_type).isUInt8()) + if (Impl::needBoolean() && !isUInt8(nested_type)) throw Exception("The only argument for function " + getName() + " must be array of UInt8. Found " + arguments[0].type->getName() + " instead", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); @@ -180,8 +183,14 @@ public: /// The types of the remaining arguments are already checked in getLambdaArgumentTypes. DataTypePtr return_type = removeLowCardinality(data_type_function->getReturnType()); - if (Impl::needBoolean() && !WhichDataType(return_type).isUInt8()) - throw Exception("Expression for function " + getName() + " must return UInt8, found " + + /// Special cases when we need boolean lambda result: + /// - lambda may return Nullable(UInt8) column, in this case after lambda execution we will + /// replace all NULLs with 0 and return nested UInt8 column. + /// - lambda may return Nothing or Nullable(Nothing) because of default implementation of functions + /// for these types. In this case we will just create UInt8 const column full of 0. + if (Impl::needBoolean() && !isUInt8(removeNullable(return_type)) && !isNothing(removeNullable(return_type))) + throw Exception("Expression for function " + getName() + " must return UInt8 or Nullable(UInt8), found " + return_type->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); static_assert( @@ -316,11 +325,38 @@ public: auto * replicated_column_function = typeid_cast(replicated_column_function_ptr.get()); replicated_column_function->appendArguments(arrays); - auto lambda_result = replicated_column_function->reduce().column; - if (lambda_result->lowCardinality()) - lambda_result = lambda_result->convertToFullColumnIfLowCardinality(); + auto lambda_result = replicated_column_function->reduce(); + if (lambda_result.column->lowCardinality()) + lambda_result.column = lambda_result.column->convertToFullColumnIfLowCardinality(); - return Impl::execute(*column_first_array, lambda_result); + if (Impl::needBoolean()) + { + toColumnTypeName + /// If result column is Nothing or Nullable(Nothing), just create const UInt8 column with 0 value. + if (isNothing(removeNullable(lambda_result.type))) + { + auto result_type = std::make_shared(); + lambda_result.column = result_type->createColumnConst(lambda_result.column->size(), 0); + } + /// If result column is Nullable(UInt8), then extract nested column and write 0 in all rows + /// when we have NULL. + else if (lambda_result.column->isNullable()) + { + auto result_column = IColumn::mutate(std::move(lambda_result.column)); + auto * column_nullable = assert_cast(result_column.get()); + auto & null_map = column_nullable->getNullMapData(); + auto nested_column = IColumn::mutate(std::move(column_nullable->getNestedColumnPtr())); + auto & nested_data = assert_cast(nested_column.get())->getData(); + for (size_t i = 0; i != nested_data.size(); ++i) + { + if (null_map[i]) + nested_data[i] = 0; + } + lambda_result.column = std::move(nested_column); + } + } + + return Impl::execute(*column_first_array, lambda_result.column); } } }; diff --git a/src/Functions/array/array.cpp b/src/Functions/array/array.cpp index 72380c0a2bf..4ef530e9c88 100644 --- a/src/Functions/array/array.cpp +++ b/src/Functions/array/array.cpp @@ -20,6 +20,7 @@ public: } bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForConstants() const override { return true; } bool isVariadic() const override { return true; } diff --git a/src/Functions/assumeNotNull.cpp b/src/Functions/assumeNotNull.cpp index b180931a83a..0fd1c08f855 100644 --- a/src/Functions/assumeNotNull.cpp +++ b/src/Functions/assumeNotNull.cpp @@ -33,6 +33,7 @@ public: size_t getNumberOfArguments() const override { return 1; } bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForConstants() const override { return true; } ColumnNumbers getArgumentsThatDontImplyNullableReturnType(size_t /*number_of_arguments*/) const override { return {0}; } diff --git a/src/Functions/castOrDefault.cpp b/src/Functions/castOrDefault.cpp index f7b93ec2e83..2e9f13545fd 100644 --- a/src/Functions/castOrDefault.cpp +++ b/src/Functions/castOrDefault.cpp @@ -52,6 +52,7 @@ public: ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; } bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForConstants() const override { return false; } bool useDefaultImplementationForLowCardinalityColumns() const override { return true; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; } @@ -194,6 +195,7 @@ private: bool isVariadic() const override { return true; } bool useDefaultImplementationForNulls() const override { return impl.useDefaultImplementationForNulls(); } + bool useDefaultImplementationForNothing() const override { return impl.useDefaultImplementationForNothing(); } bool useDefaultImplementationForLowCardinalityColumns() const override { return impl.useDefaultImplementationForLowCardinalityColumns();} bool useDefaultImplementationForConstants() const override { return impl.useDefaultImplementationForConstants();} bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & arguments) const override diff --git a/src/Functions/indexHint.cpp b/src/Functions/indexHint.cpp index bb38a56cf27..1f3dd23cc31 100644 --- a/src/Functions/indexHint.cpp +++ b/src/Functions/indexHint.cpp @@ -39,6 +39,8 @@ public: bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } + bool isSuitableForConstantFolding() const override { return false; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; } diff --git a/src/Functions/isConstant.cpp b/src/Functions/isConstant.cpp index 7ea3e26cb82..6d76cfc1dcc 100644 --- a/src/Functions/isConstant.cpp +++ b/src/Functions/isConstant.cpp @@ -27,6 +27,8 @@ public: bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } + bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; } size_t getNumberOfArguments() const override diff --git a/src/Functions/map.cpp b/src/Functions/map.cpp index 471d6fc575c..28c949b5dc3 100644 --- a/src/Functions/map.cpp +++ b/src/Functions/map.cpp @@ -65,6 +65,7 @@ public: bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForConstants() const override { return true; } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override diff --git a/src/Functions/materialize.h b/src/Functions/materialize.h index aab4e5bdbdf..e71e463066e 100644 --- a/src/Functions/materialize.h +++ b/src/Functions/materialize.h @@ -23,6 +23,11 @@ public: return false; } + bool useDefaultImplementationForNothing() const override + { + return false; + } + /// Get the function name. String getName() const override { diff --git a/src/Functions/toColumnTypeName.cpp b/src/Functions/toColumnTypeName.cpp index 95c35243567..345de2954c4 100644 --- a/src/Functions/toColumnTypeName.cpp +++ b/src/Functions/toColumnTypeName.cpp @@ -26,6 +26,8 @@ public: bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } + bool isShortCircuit(ShortCircuitSettings & settings, size_t /*number_of_arguments*/) const override { settings.enable_lazy_execution_for_first_argument = true; diff --git a/src/Functions/toNullable.cpp b/src/Functions/toNullable.cpp index b7fe831f4ff..16d9f9198cd 100644 --- a/src/Functions/toNullable.cpp +++ b/src/Functions/toNullable.cpp @@ -28,6 +28,7 @@ public: size_t getNumberOfArguments() const override { return 1; } bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForConstants() const override { return true; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; } diff --git a/src/Functions/toTypeName.cpp b/src/Functions/toTypeName.cpp index 41567ac1ee3..f3af49315ed 100644 --- a/src/Functions/toTypeName.cpp +++ b/src/Functions/toTypeName.cpp @@ -30,6 +30,8 @@ public: bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } + bool isShortCircuit(ShortCircuitSettings & settings, size_t /*number_of_arguments*/) const override { settings.enable_lazy_execution_for_first_argument = false; diff --git a/src/Functions/tuple.cpp b/src/Functions/tuple.cpp index 6d5c53c0770..5a06ac21be4 100644 --- a/src/Functions/tuple.cpp +++ b/src/Functions/tuple.cpp @@ -52,6 +52,7 @@ public: bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; } bool useDefaultImplementationForNulls() const override { return false; } + bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForConstants() const override { return true; } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override diff --git a/tests/queries/0_stateless/01882_total_rows_approx.sh b/tests/queries/0_stateless/01882_total_rows_approx.sh index 26333f61692..fe0163919a7 100755 --- a/tests/queries/0_stateless/01882_total_rows_approx.sh +++ b/tests/queries/0_stateless/01882_total_rows_approx.sh @@ -19,7 +19,7 @@ $CLICKHOUSE_CLIENT -q "create table data_01882 (key Int) Engine=MergeTree() part # thus check few times to be sure that this is not coincidence. for _ in {1..30}; do $CLICKHOUSE_CURL -vsS "${CLICKHOUSE_URL}&max_threads=1&default_format=Null&send_progress_in_http_headers=1&http_headers_progress_interval_ms=1" --data-binary @- <<< "select * from data_01882" |& { - grep -o -F '"total_rows_to_read":"10"' + grep -F '"total_rows_to_read"' } | { # grep out final result grep -v -F '"read_rows":"10"' diff --git a/tests/queries/0_stateless/02294_nothing_arguments_in_functions.reference b/tests/queries/0_stateless/02294_nothing_arguments_in_functions.reference index 954015207ad..9360b9a1922 100644 --- a/tests/queries/0_stateless/02294_nothing_arguments_in_functions.reference +++ b/tests/queries/0_stateless/02294_nothing_arguments_in_functions.reference @@ -4,3 +4,32 @@ Array(Nothing) Array(Nothing) [] Array(Nothing) +Array(Nothing) +Array(Nothing) +[] +Array(Nothing) +Array(Nothing) +Array(Nothing) + +Nothing +Const(Nothing) +Nothing +Const(Nothing) +Nothing +Nothing +Array(Nothing) +Const(Array(Nothing)) +Array(Nothing) +Array(Nothing) +Map(UInt8, Nothing) +Const(Map(UInt8, Nothing)) +Map(UInt8, Nothing) +Map(UInt8, Nothing) +Tuple(UInt8, Nothing) +Const(Tuple(UInt8, Nothing)) +Tuple(UInt8, Nothing) +Tuple(UInt8, Nothing) +Nothing +Const(Nothing) +Nothing +Nothing diff --git a/tests/queries/0_stateless/02294_nothing_arguments_in_functions.sql b/tests/queries/0_stateless/02294_nothing_arguments_in_functions.sql index 3df2577e465..732664e081f 100644 --- a/tests/queries/0_stateless/02294_nothing_arguments_in_functions.sql +++ b/tests/queries/0_stateless/02294_nothing_arguments_in_functions.sql @@ -4,3 +4,40 @@ select arrayMap((x, y) -> x + y, [], []); select toTypeName(arrayMap((x, y) -> x + y, [], [])); select arrayMap((x, y) -> x + y, [], CAST([], 'Array(Int32)')); select toTypeName(arrayMap((x, y) -> x + y, [], CAST([], 'Array(Int32)'))); + +select toTypeName(arrayMap(x -> 2 * x, [assumeNotNull(NULL)])); +select toColumnTypeName(arrayMap(x -> 2 * x, [assumeNotNull(NULL)])); + +select arrayFilter(x -> 2 * x < 0, []); +select toTypeName(arrayFilter(x -> 2 * x < 0, [])); +select toTypeName(arrayFilter(x -> 2 * x < 0, [assumeNotNull(NULL)])); +select toColumnTypeName(arrayFilter(x -> 2 * x < 0, [assumeNotNull(NULL)])); + +select CAST(assumeNotNull(NULL), 'String'); +select toTypeName(toInt32(assumeNotNull(NULL))); +select toColumnTypeName(toInt32(assumeNotNull(NULL))); + +select toTypeName(assumeNotNull(NULL)); +select toColumnTypeName(assumeNotNull(NULL)); +select toTypeName(assumeNotNull(materialize(NULL))); +select toColumnTypeName(assumeNotNull(materialize(NULL))); + +select toTypeName([assumeNotNull(NULL)]); +select toColumnTypeName([assumeNotNull(NULL)]); +select toTypeName([assumeNotNull(materialize(NULL))]); +select toColumnTypeName([assumeNotNull(materialize(NULL))]); + +select toTypeName(map(1, assumeNotNull(NULL))); +select toColumnTypeName(map(1, assumeNotNull(NULL))); +select toTypeName(map(1, assumeNotNull(materialize(NULL)))); +select toColumnTypeName(map(1, assumeNotNull(materialize(NULL)))); + +select toTypeName(tuple(1, assumeNotNull(NULL))); +select toColumnTypeName(tuple(1, assumeNotNull(NULL))); +select toTypeName(tuple(1, assumeNotNull(materialize(NULL)))); +select toColumnTypeName(tuple(1, assumeNotNull(materialize(NULL)))); + +select toTypeName(assumeNotNull(NULL) * 2); +select toColumnTypeName(assumeNotNull(NULL) * 2); +select toTypeName(assumeNotNull(materialize(NULL)) * 2); +select toColumnTypeName(assumeNotNull(materialize(NULL)) * 2); diff --git a/tests/queries/0_stateless/02295_type_nothing.sql b/tests/queries/0_stateless/02295_type_nothing.sql new file mode 100644 index 00000000000..4848a3bb751 --- /dev/null +++ b/tests/queries/0_stateless/02295_type_nothing.sql @@ -0,0 +1,28 @@ +select CAST(assumeNotNull(NULL), 'String') + +select toTypeName(assumeNotNull(NULL)); +select toColumnName(assumeNotNull(NULL)); +select toTypeName(assumeNotNull(materialize(NULL))); +select toColumnName(assumeNotNull(materialize(NULL))); + +select toTypeName([assumeNotNull(NULL)]); +select toColumnName([assumeNotNull(NULL)]); +select toTypeName([assumeNotNull(materialize(NULL))]); +select toColumnName([assumeNotNull(materialize(NULL))]); + +select toTypeName(map(1, assumeNotNull(NULL))); +select toColumnName(map(1, assumeNotNull(NULL))); +select toTypeName(map(1, assumeNotNull(materialize(NULL)))); +select toColumnName(map(1, assumeNotNull(materialize(NULL)))); + +select toTypeName(tuple(1, assumeNotNull(NULL))); +select toColumnName(tuple(1, assumeNotNull(NULL))); +select toTypeName(tuple(1, assumeNotNull(materialize(NULL)))); +select toColumnName(tuple(1, assumeNotNull(materialize(NULL)))); + +select toTypeName(assumeNotNull(NULL) * 2); +select toColumnName(assumeNotNull(NULL) * 2); +select toTypeName(assumeNotNull(materialize(NULL)) * 2); +select toColumnName(assumeNotNull(materialize(NULL)) * 2); + + diff --git a/tests/queries/0_stateless/02296_nullable_arguments_in_array_filter.reference b/tests/queries/0_stateless/02296_nullable_arguments_in_array_filter.reference new file mode 100644 index 00000000000..8c11de86262 --- /dev/null +++ b/tests/queries/0_stateless/02296_nullable_arguments_in_array_filter.reference @@ -0,0 +1,4 @@ +[] +[] +[2,4] +[1,3] diff --git a/tests/queries/0_stateless/02296_nullable_arguments_in_array_filter.sql b/tests/queries/0_stateless/02296_nullable_arguments_in_array_filter.sql new file mode 100644 index 00000000000..3c1f2b41909 --- /dev/null +++ b/tests/queries/0_stateless/02296_nullable_arguments_in_array_filter.sql @@ -0,0 +1,4 @@ +select arrayFilter(x -> 2 * x > 0, []); +select arrayFilter(x -> 2 * x > 0, [NULL]); +select arrayFilter(x -> x % 2 ? NULL : 1, [1, 2, 3, 4]); +select arrayFilter(x -> x % 2, [1, NULL, 3, NULL]); From 4c945d7fe58c68134918c95d3eb2eccd80a1f604 Mon Sep 17 00:00:00 2001 From: avogar Date: Thu, 12 May 2022 16:07:58 +0000 Subject: [PATCH 3/7] Fix --- src/Functions/array/FunctionArrayMapped.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Functions/array/FunctionArrayMapped.h b/src/Functions/array/FunctionArrayMapped.h index f4f1d39d07f..0af68910b70 100644 --- a/src/Functions/array/FunctionArrayMapped.h +++ b/src/Functions/array/FunctionArrayMapped.h @@ -331,7 +331,6 @@ public: if (Impl::needBoolean()) { - toColumnTypeName /// If result column is Nothing or Nullable(Nothing), just create const UInt8 column with 0 value. if (isNothing(removeNullable(lambda_result.type))) { From d1b5362250df0aacf150c27ecc97986f9ab78a33 Mon Sep 17 00:00:00 2001 From: Kruglov Pavel <48961922+Avogar@users.noreply.github.com> Date: Thu, 12 May 2022 18:59:26 +0200 Subject: [PATCH 4/7] Fix tests --- tests/queries/0_stateless/01882_total_rows_approx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/queries/0_stateless/01882_total_rows_approx.sh b/tests/queries/0_stateless/01882_total_rows_approx.sh index fe0163919a7..26333f61692 100755 --- a/tests/queries/0_stateless/01882_total_rows_approx.sh +++ b/tests/queries/0_stateless/01882_total_rows_approx.sh @@ -19,7 +19,7 @@ $CLICKHOUSE_CLIENT -q "create table data_01882 (key Int) Engine=MergeTree() part # thus check few times to be sure that this is not coincidence. for _ in {1..30}; do $CLICKHOUSE_CURL -vsS "${CLICKHOUSE_URL}&max_threads=1&default_format=Null&send_progress_in_http_headers=1&http_headers_progress_interval_ms=1" --data-binary @- <<< "select * from data_01882" |& { - grep -F '"total_rows_to_read"' + grep -o -F '"total_rows_to_read":"10"' } | { # grep out final result grep -v -F '"read_rows":"10"' From 3a1f6f4fb22ab3e834c06b8644af962486e776c2 Mon Sep 17 00:00:00 2001 From: Kruglov Pavel <48961922+Avogar@users.noreply.github.com> Date: Thu, 12 May 2022 18:59:48 +0200 Subject: [PATCH 5/7] Delete 02295_type_nothing.sql --- .../0_stateless/02295_type_nothing.sql | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 tests/queries/0_stateless/02295_type_nothing.sql diff --git a/tests/queries/0_stateless/02295_type_nothing.sql b/tests/queries/0_stateless/02295_type_nothing.sql deleted file mode 100644 index 4848a3bb751..00000000000 --- a/tests/queries/0_stateless/02295_type_nothing.sql +++ /dev/null @@ -1,28 +0,0 @@ -select CAST(assumeNotNull(NULL), 'String') - -select toTypeName(assumeNotNull(NULL)); -select toColumnName(assumeNotNull(NULL)); -select toTypeName(assumeNotNull(materialize(NULL))); -select toColumnName(assumeNotNull(materialize(NULL))); - -select toTypeName([assumeNotNull(NULL)]); -select toColumnName([assumeNotNull(NULL)]); -select toTypeName([assumeNotNull(materialize(NULL))]); -select toColumnName([assumeNotNull(materialize(NULL))]); - -select toTypeName(map(1, assumeNotNull(NULL))); -select toColumnName(map(1, assumeNotNull(NULL))); -select toTypeName(map(1, assumeNotNull(materialize(NULL)))); -select toColumnName(map(1, assumeNotNull(materialize(NULL)))); - -select toTypeName(tuple(1, assumeNotNull(NULL))); -select toColumnName(tuple(1, assumeNotNull(NULL))); -select toTypeName(tuple(1, assumeNotNull(materialize(NULL)))); -select toColumnName(tuple(1, assumeNotNull(materialize(NULL)))); - -select toTypeName(assumeNotNull(NULL) * 2); -select toColumnName(assumeNotNull(NULL) * 2); -select toTypeName(assumeNotNull(materialize(NULL)) * 2); -select toColumnName(assumeNotNull(materialize(NULL)) * 2); - - From f69c3175af1265f2525d25a69dd76048dd831175 Mon Sep 17 00:00:00 2001 From: avogar Date: Thu, 19 May 2022 10:13:44 +0000 Subject: [PATCH 6/7] Fix comments --- src/Functions/FunctionsConversion.h | 1 + src/Functions/FunctionsMiscellaneous.h | 7 ++++ src/Functions/IFunction.cpp | 5 +-- src/Functions/array/array.cpp | 1 + src/Functions/assumeNotNull.cpp | 10 +++++- src/Functions/indexHint.cpp | 2 -- src/Functions/map.cpp | 1 + src/Functions/materialize.h | 5 --- src/Functions/tuple.cpp | 1 + ...4_nothing_arguments_in_functions.reference | 24 +++++--------- .../02294_nothing_arguments_in_functions.sql | 33 +++++++++---------- ...ng_arguments_in_functions_errors.reference | 3 ++ ...4_nothing_arguments_in_functions_errors.sh | 10 ++++++ 13 files changed, 60 insertions(+), 43 deletions(-) create mode 100644 tests/queries/0_stateless/02294_nothing_arguments_in_functions_errors.reference create mode 100755 tests/queries/0_stateless/02294_nothing_arguments_in_functions_errors.sh diff --git a/src/Functions/FunctionsConversion.h b/src/Functions/FunctionsConversion.h index f8e8db5a0e9..bffc15cdc57 100644 --- a/src/Functions/FunctionsConversion.h +++ b/src/Functions/FunctionsConversion.h @@ -2516,6 +2516,7 @@ protected: } bool useDefaultImplementationForNulls() const override { return false; } + /// CAST(Nothing, T) -> T bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForConstants() const override { return true; } bool useDefaultImplementationForLowCardinalityColumns() const override { return false; } diff --git a/src/Functions/FunctionsMiscellaneous.h b/src/Functions/FunctionsMiscellaneous.h index ff27b0cc518..49da8f49c82 100644 --- a/src/Functions/FunctionsMiscellaneous.h +++ b/src/Functions/FunctionsMiscellaneous.h @@ -51,6 +51,9 @@ public: } bool useDefaultImplementationForNulls() const override { return false; } + /// It's possible if expression_actions contains function that don't use + /// default implementation for Nothing. + /// Example: arrayMap(x -> CAST(x, 'UInt8'), []); bool useDefaultImplementationForNothing() const override { return false; } private: @@ -119,6 +122,9 @@ public: String getName() const override { return "FunctionCapture"; } bool useDefaultImplementationForNulls() const override { return false; } + /// It's possible if expression_actions contains function that don't use + /// default implementation for Nothing and one of captured columns can be Nothing + /// Example: SELECT arrayMap(x -> [x, arrayElement(y, 0)], []), [] as y bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForLowCardinalityColumns() const override { return false; } @@ -249,6 +255,7 @@ public: String getName() const override { return name; } bool useDefaultImplementationForNulls() const override { return false; } + /// See comment in ExecutableFunctionCapture. bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForLowCardinalityColumns() const override { return false; } DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName &) const override { return return_type; } diff --git a/src/Functions/IFunction.cpp b/src/Functions/IFunction.cpp index 453c31302a0..cb03fdea1d1 100644 --- a/src/Functions/IFunction.cpp +++ b/src/Functions/IFunction.cpp @@ -225,8 +225,9 @@ ColumnPtr IExecutableFunction::defaultImplementationForNothing( getName(), result_type->getName()); - return ColumnConst::create(ColumnNothing::create(1), input_rows_count); - + if (input_rows_count > 0) + throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Cannot create non-empty column with type Nothing"); + return ColumnNothing::create(0); } ColumnPtr IExecutableFunction::executeWithoutLowCardinalityColumns( diff --git a/src/Functions/array/array.cpp b/src/Functions/array/array.cpp index 4ef530e9c88..b0a7daac522 100644 --- a/src/Functions/array/array.cpp +++ b/src/Functions/array/array.cpp @@ -20,6 +20,7 @@ public: } bool useDefaultImplementationForNulls() const override { return false; } + /// array(..., Nothing, ...) -> Array(..., Nothing, ...) bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForConstants() const override { return true; } diff --git a/src/Functions/assumeNotNull.cpp b/src/Functions/assumeNotNull.cpp index 0fd1c08f855..8f999af9ef0 100644 --- a/src/Functions/assumeNotNull.cpp +++ b/src/Functions/assumeNotNull.cpp @@ -7,6 +7,12 @@ namespace DB { + +namespace ErrorCodes +{ + extern const int ILLEGAL_COLUMN; +} + namespace { @@ -33,7 +39,6 @@ public: size_t getNumberOfArguments() const override { return 1; } bool useDefaultImplementationForNulls() const override { return false; } - bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForConstants() const override { return true; } ColumnNumbers getArgumentsThatDontImplyNullableReturnType(size_t /*number_of_arguments*/) const override { return {0}; } @@ -46,6 +51,9 @@ public: { const ColumnPtr & col = arguments[0].column; + if (arguments[0].type->onlyNull() && !col->empty()) + throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Cannot create non-empty column with type Nothing"); + if (const auto * nullable_col = checkAndGetColumn(*col)) return nullable_col->getNestedColumnPtr(); else diff --git a/src/Functions/indexHint.cpp b/src/Functions/indexHint.cpp index 1f3dd23cc31..bb38a56cf27 100644 --- a/src/Functions/indexHint.cpp +++ b/src/Functions/indexHint.cpp @@ -39,8 +39,6 @@ public: bool useDefaultImplementationForNulls() const override { return false; } - bool useDefaultImplementationForNothing() const override { return false; } - bool isSuitableForConstantFolding() const override { return false; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; } diff --git a/src/Functions/map.cpp b/src/Functions/map.cpp index 28c949b5dc3..8c891fdec81 100644 --- a/src/Functions/map.cpp +++ b/src/Functions/map.cpp @@ -65,6 +65,7 @@ public: bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } bool useDefaultImplementationForNulls() const override { return false; } + /// map(..., Nothing) -> Map(..., Nothing) bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForConstants() const override { return true; } diff --git a/src/Functions/materialize.h b/src/Functions/materialize.h index e71e463066e..aab4e5bdbdf 100644 --- a/src/Functions/materialize.h +++ b/src/Functions/materialize.h @@ -23,11 +23,6 @@ public: return false; } - bool useDefaultImplementationForNothing() const override - { - return false; - } - /// Get the function name. String getName() const override { diff --git a/src/Functions/tuple.cpp b/src/Functions/tuple.cpp index 5a06ac21be4..4238b12157a 100644 --- a/src/Functions/tuple.cpp +++ b/src/Functions/tuple.cpp @@ -52,6 +52,7 @@ public: bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; } bool useDefaultImplementationForNulls() const override { return false; } + /// tuple(..., Nothing, ...) -> Tuple(..., Nothing, ...) bool useDefaultImplementationForNothing() const override { return false; } bool useDefaultImplementationForConstants() const override { return true; } diff --git a/tests/queries/0_stateless/02294_nothing_arguments_in_functions.reference b/tests/queries/0_stateless/02294_nothing_arguments_in_functions.reference index 9360b9a1922..665931efb71 100644 --- a/tests/queries/0_stateless/02294_nothing_arguments_in_functions.reference +++ b/tests/queries/0_stateless/02294_nothing_arguments_in_functions.reference @@ -4,32 +4,26 @@ Array(Nothing) Array(Nothing) [] Array(Nothing) -Array(Nothing) -Array(Nothing) [] Array(Nothing) +Array(String) Array(Nothing) Array(Nothing) - -Nothing -Const(Nothing) -Nothing -Const(Nothing) +Array(Array(Nothing)) +Array(Array(Nothing)) +Array(Map(UInt8, Nothing)) +Array(Map(UInt8, Nothing)) +Array(Tuple(Nothing)) +Array(Tuple(UInt8, Nothing)) +Nothing +Nothing Nothing Nothing -Array(Nothing) -Const(Array(Nothing)) Array(Nothing) Array(Nothing) Map(UInt8, Nothing) -Const(Map(UInt8, Nothing)) -Map(UInt8, Nothing) Map(UInt8, Nothing) Tuple(UInt8, Nothing) -Const(Tuple(UInt8, Nothing)) -Tuple(UInt8, Nothing) Tuple(UInt8, Nothing) Nothing -Const(Nothing) -Nothing Nothing diff --git a/tests/queries/0_stateless/02294_nothing_arguments_in_functions.sql b/tests/queries/0_stateless/02294_nothing_arguments_in_functions.sql index 732664e081f..4406a05df0c 100644 --- a/tests/queries/0_stateless/02294_nothing_arguments_in_functions.sql +++ b/tests/queries/0_stateless/02294_nothing_arguments_in_functions.sql @@ -5,39 +5,36 @@ select toTypeName(arrayMap((x, y) -> x + y, [], [])); select arrayMap((x, y) -> x + y, [], CAST([], 'Array(Int32)')); select toTypeName(arrayMap((x, y) -> x + y, [], CAST([], 'Array(Int32)'))); -select toTypeName(arrayMap(x -> 2 * x, [assumeNotNull(NULL)])); -select toColumnTypeName(arrayMap(x -> 2 * x, [assumeNotNull(NULL)])); - select arrayFilter(x -> 2 * x < 0, []); select toTypeName(arrayFilter(x -> 2 * x < 0, [])); -select toTypeName(arrayFilter(x -> 2 * x < 0, [assumeNotNull(NULL)])); -select toColumnTypeName(arrayFilter(x -> 2 * x < 0, [assumeNotNull(NULL)])); -select CAST(assumeNotNull(NULL), 'String'); -select toTypeName(toInt32(assumeNotNull(NULL))); -select toColumnTypeName(toInt32(assumeNotNull(NULL))); +select toTypeName(arrayMap(x -> CAST(x, 'String'), [])); +select toTypeName(arrayMap(x -> toInt32(x), [])); +select toColumnTypeName(arrayMap(x -> toInt32(x), [])); + +select toTypeName(arrayMap(x -> [x], [])); +select toColumnTypeName(arrayMap(x -> [x], [])); + +select toTypeName(arrayMap(x ->map(1, x), [])); +select toColumnTypeName(arrayMap(x -> map(1, x), [])); + +select toTypeName(arrayMap(x ->tuple(x), [])); +select toColumnTypeName(arrayMap(x -> tuple(1, x), [])); + +select toTypeName(toInt32(assumeNotNull(materialize(NULL)))); +select toColumnTypeName(toInt32(assumeNotNull(materialize(NULL)))); -select toTypeName(assumeNotNull(NULL)); -select toColumnTypeName(assumeNotNull(NULL)); select toTypeName(assumeNotNull(materialize(NULL))); select toColumnTypeName(assumeNotNull(materialize(NULL))); -select toTypeName([assumeNotNull(NULL)]); -select toColumnTypeName([assumeNotNull(NULL)]); select toTypeName([assumeNotNull(materialize(NULL))]); select toColumnTypeName([assumeNotNull(materialize(NULL))]); -select toTypeName(map(1, assumeNotNull(NULL))); -select toColumnTypeName(map(1, assumeNotNull(NULL))); select toTypeName(map(1, assumeNotNull(materialize(NULL)))); select toColumnTypeName(map(1, assumeNotNull(materialize(NULL)))); -select toTypeName(tuple(1, assumeNotNull(NULL))); -select toColumnTypeName(tuple(1, assumeNotNull(NULL))); select toTypeName(tuple(1, assumeNotNull(materialize(NULL)))); select toColumnTypeName(tuple(1, assumeNotNull(materialize(NULL)))); -select toTypeName(assumeNotNull(NULL) * 2); -select toColumnTypeName(assumeNotNull(NULL) * 2); select toTypeName(assumeNotNull(materialize(NULL)) * 2); select toColumnTypeName(assumeNotNull(materialize(NULL)) * 2); diff --git a/tests/queries/0_stateless/02294_nothing_arguments_in_functions_errors.reference b/tests/queries/0_stateless/02294_nothing_arguments_in_functions_errors.reference new file mode 100644 index 00000000000..0eabe367130 --- /dev/null +++ b/tests/queries/0_stateless/02294_nothing_arguments_in_functions_errors.reference @@ -0,0 +1,3 @@ +OK +OK +OK diff --git a/tests/queries/0_stateless/02294_nothing_arguments_in_functions_errors.sh b/tests/queries/0_stateless/02294_nothing_arguments_in_functions_errors.sh new file mode 100755 index 00000000000..931985340c2 --- /dev/null +++ b/tests/queries/0_stateless/02294_nothing_arguments_in_functions_errors.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +# shellcheck source=../shell_config.sh +. "$CUR_DIR"/../shell_config.sh + +$CLICKHOUSE_LOCAL -q "SELECT assumeNotNull(NULL)" 2>&1 | grep -q "ILLEGAL_COLUMN" && echo "OK" || echo "FAIL" +$CLICKHOUSE_LOCAL -q "SELECT assumeNotNull(materialize(NULL))" 2>&1 | grep -q "ILLEGAL_TYPE_OF_ARGUMENT" && echo "OK" || echo "FAIL" +$CLICKHOUSE_LOCAL -q "SELECT assumeNotNull(materialize(NULL)) from numbers(10)" 2>&1 | grep -q "ILLEGAL_TYPE_OF_ARGUMENT" && echo "OK" || echo "FAIL" + From bb2fb48ad78c5a339f66d309c36dc9299f5082fc Mon Sep 17 00:00:00 2001 From: avogar Date: Fri, 20 May 2022 10:53:20 +0000 Subject: [PATCH 7/7] Fix tests --- tests/queries/0_stateless/00948_values_interpreter_template.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/queries/0_stateless/00948_values_interpreter_template.sql b/tests/queries/0_stateless/00948_values_interpreter_template.sql index 2404c99f736..a3d2ffd7452 100644 --- a/tests/queries/0_stateless/00948_values_interpreter_template.sql +++ b/tests/queries/0_stateless/00948_values_interpreter_template.sql @@ -21,7 +21,7 @@ INSERT INTO type_names VALUES (1, toTypeName([1, 2]), toTypeName((256, -1, 3.14, -- _NUM_5: Float64 -> Int64 INSERT INTO values_template VALUES ((1), lower(replaceAll('Hella', 'a', 'o')), 1 + 2 + 3, round(-4 * 5.0), nan / CAST('42', 'Int8'), reverse([1, 2, 3])), ((2), lower(replaceAll('Warld', 'a', 'o')), -4 + 5 + 6, round(18446744073709551615 * 1e-19), 1.0 / CAST('0', 'Int8'), reverse([])), ((3), lower(replaceAll('Test', 'a', 'o')), 3 + 2 + 1, round(9223372036854775807 * -1), 6.28 / CAST('2', 'Int8'), reverse([4, 5])), ((4), lower(replaceAll('Expressians', 'a', 'o')), 6 + 5 + 4, round(1 * -9223372036854775807), 127.0 / CAST('127', 'Int8'), reverse([6, 7, 8, 9, 0])); -INSERT INTO values_template_nullable VALUES ((1), lower(replaceAll('Hella', 'a', 'o')), 1 + 2 + 3, arraySort(x -> assumeNotNull(x), [null, NULL])), ((2), lower(replaceAll('Warld', 'b', 'o')), 4 - 5 + 6, arraySort(x -> assumeNotNull(x), [+1, -1, Null])), ((3), lower(replaceAll('Test', 'c', 'o')), 3 + 2 - 1, arraySort(x -> assumeNotNull(x), [1, nUlL, 3.14])), ((4), lower(replaceAll(null, 'c', 'o')), 6 + 5 - null, arraySort(x -> assumeNotNull(x), [3, 2, 1])); +INSERT INTO values_template_nullable VALUES ((1), lower(replaceAll('Hella', 'a', 'o')), 1 + 2 + 3, arraySort(x -> assumeNotNull(x), [null, NULL::Nullable(UInt8)])), ((2), lower(replaceAll('Warld', 'b', 'o')), 4 - 5 + 6, arraySort(x -> assumeNotNull(x), [+1, -1, Null])), ((3), lower(replaceAll('Test', 'c', 'o')), 3 + 2 - 1, arraySort(x -> assumeNotNull(x), [1, nUlL, 3.14])), ((4), lower(replaceAll(null, 'c', 'o')), 6 + 5 - null, arraySort(x -> assumeNotNull(x), [3, 2, 1])); INSERT INTO values_template_fallback VALUES (1 + x); -- { clientError 62 } INSERT INTO values_template_fallback VALUES (abs(functionThatDoesNotExists(42))); -- { clientError 46 }