mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-20 00:30:49 +00:00
Merge pull request #37048 from Avogar/fix-array-map-nothing
Add default implementation for Nothing in functions
This commit is contained in:
commit
ff98c24d44
@ -16,7 +16,7 @@ class SerializationNothing : public SimpleTextSerialization
|
|||||||
private:
|
private:
|
||||||
[[noreturn]] static void throwNoSerialization()
|
[[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:
|
public:
|
||||||
void serializeBinary(const Field &, WriteBuffer &) const override { throwNoSerialization(); }
|
void serializeBinary(const Field &, WriteBuffer &) const override { throwNoSerialization(); }
|
||||||
|
@ -98,6 +98,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool useDefaultImplementationForNulls() const override { return false; }
|
bool useDefaultImplementationForNulls() const override { return false; }
|
||||||
|
bool useDefaultImplementationForNothing() const override { return false; }
|
||||||
bool useDefaultImplementationForLowCardinalityColumns() const override { return false; }
|
bool useDefaultImplementationForLowCardinalityColumns() const override { return false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -2516,6 +2516,8 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool useDefaultImplementationForNulls() const override { return false; }
|
bool useDefaultImplementationForNulls() const override { return false; }
|
||||||
|
/// CAST(Nothing, T) -> T
|
||||||
|
bool useDefaultImplementationForNothing() const override { return false; }
|
||||||
bool useDefaultImplementationForConstants() const override { return true; }
|
bool useDefaultImplementationForConstants() const override { return true; }
|
||||||
bool useDefaultImplementationForLowCardinalityColumns() const override { return false; }
|
bool useDefaultImplementationForLowCardinalityColumns() const override { return false; }
|
||||||
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
|
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
|
||||||
|
@ -50,7 +50,11 @@ public:
|
|||||||
return expr_columns.getByName(signature->return_name).column;
|
return expr_columns.getByName(signature->return_name).column;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool useDefaultImplementationForNulls() const override { return false; }
|
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:
|
private:
|
||||||
ExpressionActionsPtr expression_actions;
|
ExpressionActionsPtr expression_actions;
|
||||||
@ -118,6 +122,10 @@ public:
|
|||||||
String getName() const override { return "FunctionCapture"; }
|
String getName() const override { return "FunctionCapture"; }
|
||||||
|
|
||||||
bool useDefaultImplementationForNulls() const override { return false; }
|
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; }
|
bool useDefaultImplementationForLowCardinalityColumns() const override { return false; }
|
||||||
|
|
||||||
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
|
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
|
||||||
@ -247,6 +255,8 @@ public:
|
|||||||
|
|
||||||
String getName() const override { return name; }
|
String getName() const override { return name; }
|
||||||
bool useDefaultImplementationForNulls() const override { return false; }
|
bool useDefaultImplementationForNulls() const override { return false; }
|
||||||
|
/// See comment in ExecutableFunctionCapture.
|
||||||
|
bool useDefaultImplementationForNothing() const override { return false; }
|
||||||
bool useDefaultImplementationForLowCardinalityColumns() const override { return false; }
|
bool useDefaultImplementationForLowCardinalityColumns() const override { return false; }
|
||||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName &) const override { return return_type; }
|
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName &) const override { return return_type; }
|
||||||
size_t getNumberOfArguments() const override { return capture->captured_types.size(); }
|
size_t getNumberOfArguments() const override { return capture->captured_types.size(); }
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <Columns/ColumnTuple.h>
|
#include <Columns/ColumnTuple.h>
|
||||||
#include <Columns/ColumnLowCardinality.h>
|
#include <Columns/ColumnLowCardinality.h>
|
||||||
#include <Columns/ColumnSparse.h>
|
#include <Columns/ColumnSparse.h>
|
||||||
|
#include <Columns/ColumnNothing.h>
|
||||||
#include <DataTypes/DataTypeNothing.h>
|
#include <DataTypes/DataTypeNothing.h>
|
||||||
#include <DataTypes/DataTypeNullable.h>
|
#include <DataTypes/DataTypeNullable.h>
|
||||||
#include <DataTypes/Native.h>
|
#include <DataTypes/Native.h>
|
||||||
@ -203,6 +204,32 @@ ColumnPtr IExecutableFunction::defaultImplementationForNulls(
|
|||||||
return nullptr;
|
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());
|
||||||
|
|
||||||
|
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(
|
ColumnPtr IExecutableFunction::executeWithoutLowCardinalityColumns(
|
||||||
const ColumnsWithTypeAndName & args, const DataTypePtr & result_type, size_t input_rows_count, bool dry_run) const
|
const ColumnsWithTypeAndName & args, const DataTypePtr & result_type, size_t input_rows_count, bool dry_run) const
|
||||||
{
|
{
|
||||||
@ -212,6 +239,9 @@ ColumnPtr IExecutableFunction::executeWithoutLowCardinalityColumns(
|
|||||||
if (auto res = defaultImplementationForNulls(args, result_type, input_rows_count, dry_run))
|
if (auto res = defaultImplementationForNulls(args, result_type, input_rows_count, dry_run))
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
if (auto res = defaultImplementationForNothing(args, result_type, input_rows_count))
|
||||||
|
return res;
|
||||||
|
|
||||||
ColumnPtr res;
|
ColumnPtr res;
|
||||||
if (dry_run)
|
if (dry_run)
|
||||||
res = executeDryRunImpl(args, result_type, input_rows_count);
|
res = executeDryRunImpl(args, result_type, input_rows_count);
|
||||||
@ -436,6 +466,15 @@ DataTypePtr IFunctionOverloadResolver::getReturnTypeWithoutLowCardinality(const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!arguments.empty() && useDefaultImplementationForNothing())
|
||||||
|
{
|
||||||
|
for (const auto & arg : arguments)
|
||||||
|
{
|
||||||
|
if (isNothing(arg.type))
|
||||||
|
return std::make_shared<DataTypeNothing>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return getReturnTypeImpl(arguments);
|
return getReturnTypeImpl(arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +63,11 @@ protected:
|
|||||||
*/
|
*/
|
||||||
virtual bool useDefaultImplementationForNulls() const { return true; }
|
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,
|
/** If the function have non-zero number of arguments,
|
||||||
* and if all arguments are constant, that we could automatically provide default implementation:
|
* 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,
|
* arguments are converted to ordinary columns with single value, then function is executed as usual,
|
||||||
@ -100,6 +105,9 @@ private:
|
|||||||
ColumnPtr defaultImplementationForNulls(
|
ColumnPtr defaultImplementationForNulls(
|
||||||
const ColumnsWithTypeAndName & args, const DataTypePtr & result_type, size_t input_rows_count, bool dry_run) const;
|
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(
|
ColumnPtr executeWithoutLowCardinalityColumns(
|
||||||
const ColumnsWithTypeAndName & args, const DataTypePtr & result_type, size_t input_rows_count, bool dry_run) const;
|
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 function isSuitableForConstantFolding then, this method will be called during query analyzis
|
||||||
* if some arguments are constants. For example logical functions (AndFunction, OrFunction) can
|
* if some arguments are constants. For example logical functions (AndFunction, OrFunction) can
|
||||||
* return they result based on some constant arguments.
|
* return they result based on some constant arguments.
|
||||||
* Arguments are passed without modifications, useDefaultImplementationForNulls, useDefaultImplementationForConstants,
|
* Arguments are passed without modifications, useDefaultImplementationForNulls, useDefaultImplementationForNothing,
|
||||||
* useDefaultImplementationForLowCardinality are not applied.
|
* useDefaultImplementationForConstants, useDefaultImplementationForLowCardinality are not applied.
|
||||||
*/
|
*/
|
||||||
virtual ColumnPtr getConstantResultForNonConstArguments(
|
virtual ColumnPtr getConstantResultForNonConstArguments(
|
||||||
const ColumnsWithTypeAndName & /* arguments */, const DataTypePtr & /* result_type */) const { return nullptr; }
|
const ColumnsWithTypeAndName & /* arguments */, const DataTypePtr & /* result_type */) const { return nullptr; }
|
||||||
@ -354,7 +362,13 @@ protected:
|
|||||||
*/
|
*/
|
||||||
virtual bool useDefaultImplementationForNulls() const { return true; }
|
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.
|
* If function arguments has low cardinality types, convert them to ordinary types.
|
||||||
* getReturnType returns ColumnLowCardinality if at least one argument type is ColumnLowCardinality.
|
* getReturnType returns ColumnLowCardinality if at least one argument type is ColumnLowCardinality.
|
||||||
*/
|
*/
|
||||||
@ -403,6 +417,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual bool useDefaultImplementationForNulls() const { return true; }
|
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,
|
/** If the function have non-zero number of arguments,
|
||||||
* and if all arguments are constant, that we could automatically provide default implementation:
|
* 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,
|
* arguments are converted to ordinary columns with single value, then function is executed as usual,
|
||||||
|
@ -27,6 +27,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool useDefaultImplementationForNulls() const final { return function->useDefaultImplementationForNulls(); }
|
bool useDefaultImplementationForNulls() const final { return function->useDefaultImplementationForNulls(); }
|
||||||
|
bool useDefaultImplementationForNothing() const final { return function->useDefaultImplementationForNothing(); }
|
||||||
bool useDefaultImplementationForConstants() const final { return function->useDefaultImplementationForConstants(); }
|
bool useDefaultImplementationForConstants() const final { return function->useDefaultImplementationForConstants(); }
|
||||||
bool useDefaultImplementationForLowCardinalityColumns() const final { return function->useDefaultImplementationForLowCardinalityColumns(); }
|
bool useDefaultImplementationForLowCardinalityColumns() const final { return function->useDefaultImplementationForLowCardinalityColumns(); }
|
||||||
bool useDefaultImplementationForSparseColumns() const final { return function->useDefaultImplementationForSparseColumns(); }
|
bool useDefaultImplementationForSparseColumns() const final { return function->useDefaultImplementationForSparseColumns(); }
|
||||||
@ -124,6 +125,7 @@ public:
|
|||||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override { return function->getReturnTypeImpl(arguments); }
|
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override { return function->getReturnTypeImpl(arguments); }
|
||||||
|
|
||||||
bool useDefaultImplementationForNulls() const override { return function->useDefaultImplementationForNulls(); }
|
bool useDefaultImplementationForNulls() const override { return function->useDefaultImplementationForNulls(); }
|
||||||
|
bool useDefaultImplementationForNothing() const override { return function->useDefaultImplementationForNothing(); }
|
||||||
bool useDefaultImplementationForLowCardinalityColumns() const override { return function->useDefaultImplementationForLowCardinalityColumns(); }
|
bool useDefaultImplementationForLowCardinalityColumns() const override { return function->useDefaultImplementationForLowCardinalityColumns(); }
|
||||||
bool useDefaultImplementationForSparseColumns() const override { return function->useDefaultImplementationForSparseColumns(); }
|
bool useDefaultImplementationForSparseColumns() const override { return function->useDefaultImplementationForSparseColumns(); }
|
||||||
bool canBeExecutedOnLowCardinalityDictionary() const override { return function->canBeExecutedOnLowCardinalityDictionary(); }
|
bool canBeExecutedOnLowCardinalityDictionary() const override { return function->canBeExecutedOnLowCardinalityDictionary(); }
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <Columns/ColumnConst.h>
|
#include <Columns/ColumnConst.h>
|
||||||
#include <Columns/ColumnFunction.h>
|
#include <Columns/ColumnFunction.h>
|
||||||
#include <Columns/ColumnMap.h>
|
#include <Columns/ColumnMap.h>
|
||||||
|
#include <Columns/ColumnNullable.h>
|
||||||
#include <Columns/IColumn.h>
|
#include <Columns/IColumn.h>
|
||||||
|
|
||||||
#include <Common/Exception.h>
|
#include <Common/Exception.h>
|
||||||
@ -16,11 +17,13 @@
|
|||||||
#include <DataTypes/DataTypeFunction.h>
|
#include <DataTypes/DataTypeFunction.h>
|
||||||
#include <DataTypes/DataTypeLowCardinality.h>
|
#include <DataTypes/DataTypeLowCardinality.h>
|
||||||
#include <DataTypes/DataTypeMap.h>
|
#include <DataTypes/DataTypeMap.h>
|
||||||
|
#include <DataTypes/DataTypesNumber.h>
|
||||||
|
|
||||||
#include <Functions/FunctionHelpers.h>
|
#include <Functions/FunctionHelpers.h>
|
||||||
#include <Functions/IFunction.h>
|
#include <Functions/IFunction.h>
|
||||||
|
|
||||||
#include <Interpreters/Context_fwd.h>
|
#include <Interpreters/Context_fwd.h>
|
||||||
|
#include <Interpreters/castColumn.h>
|
||||||
|
|
||||||
#include <IO/WriteHelpers.h>
|
#include <IO/WriteHelpers.h>
|
||||||
|
|
||||||
@ -156,7 +159,7 @@ public:
|
|||||||
|
|
||||||
DataTypePtr nested_type = data_type->getNestedType();
|
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 "
|
throw Exception("The only argument for function " + getName() + " must be array of UInt8. Found "
|
||||||
+ arguments[0].type->getName() + " instead", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
+ 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.
|
/// The types of the remaining arguments are already checked in getLambdaArgumentTypes.
|
||||||
|
|
||||||
DataTypePtr return_type = removeLowCardinality(data_type_function->getReturnType());
|
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);
|
+ return_type->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||||
|
|
||||||
static_assert(
|
static_assert(
|
||||||
@ -316,11 +325,37 @@ public:
|
|||||||
auto * replicated_column_function = typeid_cast<ColumnFunction *>(replicated_column_function_ptr.get());
|
auto * replicated_column_function = typeid_cast<ColumnFunction *>(replicated_column_function_ptr.get());
|
||||||
replicated_column_function->appendArguments(arrays);
|
replicated_column_function->appendArguments(arrays);
|
||||||
|
|
||||||
auto lambda_result = replicated_column_function->reduce().column;
|
auto lambda_result = replicated_column_function->reduce();
|
||||||
if (lambda_result->lowCardinality())
|
if (lambda_result.column->lowCardinality())
|
||||||
lambda_result = lambda_result->convertToFullColumnIfLowCardinality();
|
lambda_result.column = lambda_result.column->convertToFullColumnIfLowCardinality();
|
||||||
|
|
||||||
return Impl::execute(*column_first_array, lambda_result);
|
if (Impl::needBoolean())
|
||||||
|
{
|
||||||
|
/// 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<DataTypeUInt8>();
|
||||||
|
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<ColumnNullable *>(result_column.get());
|
||||||
|
auto & null_map = column_nullable->getNullMapData();
|
||||||
|
auto nested_column = IColumn::mutate(std::move(column_nullable->getNestedColumnPtr()));
|
||||||
|
auto & nested_data = assert_cast<ColumnUInt8 *>(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -20,6 +20,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool useDefaultImplementationForNulls() const override { return false; }
|
bool useDefaultImplementationForNulls() const override { return false; }
|
||||||
|
/// array(..., Nothing, ...) -> Array(..., Nothing, ...)
|
||||||
|
bool useDefaultImplementationForNothing() const override { return false; }
|
||||||
bool useDefaultImplementationForConstants() const override { return true; }
|
bool useDefaultImplementationForConstants() const override { return true; }
|
||||||
|
|
||||||
bool isVariadic() const override { return true; }
|
bool isVariadic() const override { return true; }
|
||||||
|
@ -7,6 +7,12 @@
|
|||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace ErrorCodes
|
||||||
|
{
|
||||||
|
extern const int ILLEGAL_COLUMN;
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -45,6 +51,9 @@ public:
|
|||||||
{
|
{
|
||||||
const ColumnPtr & col = arguments[0].column;
|
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<ColumnNullable>(*col))
|
if (const auto * nullable_col = checkAndGetColumn<ColumnNullable>(*col))
|
||||||
return nullable_col->getNestedColumnPtr();
|
return nullable_col->getNestedColumnPtr();
|
||||||
else
|
else
|
||||||
|
@ -52,6 +52,7 @@ public:
|
|||||||
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
|
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
|
||||||
|
|
||||||
bool useDefaultImplementationForNulls() const override { return false; }
|
bool useDefaultImplementationForNulls() const override { return false; }
|
||||||
|
bool useDefaultImplementationForNothing() const override { return false; }
|
||||||
bool useDefaultImplementationForConstants() const override { return false; }
|
bool useDefaultImplementationForConstants() const override { return false; }
|
||||||
bool useDefaultImplementationForLowCardinalityColumns() const override { return true; }
|
bool useDefaultImplementationForLowCardinalityColumns() const override { return true; }
|
||||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
|
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
|
||||||
@ -194,6 +195,7 @@ private:
|
|||||||
bool isVariadic() const override { return true; }
|
bool isVariadic() const override { return true; }
|
||||||
|
|
||||||
bool useDefaultImplementationForNulls() const override { return impl.useDefaultImplementationForNulls(); }
|
bool useDefaultImplementationForNulls() const override { return impl.useDefaultImplementationForNulls(); }
|
||||||
|
bool useDefaultImplementationForNothing() const override { return impl.useDefaultImplementationForNothing(); }
|
||||||
bool useDefaultImplementationForLowCardinalityColumns() const override { return impl.useDefaultImplementationForLowCardinalityColumns();}
|
bool useDefaultImplementationForLowCardinalityColumns() const override { return impl.useDefaultImplementationForLowCardinalityColumns();}
|
||||||
bool useDefaultImplementationForConstants() const override { return impl.useDefaultImplementationForConstants();}
|
bool useDefaultImplementationForConstants() const override { return impl.useDefaultImplementationForConstants();}
|
||||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & arguments) const override
|
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & arguments) const override
|
||||||
|
@ -27,6 +27,8 @@ public:
|
|||||||
|
|
||||||
bool useDefaultImplementationForNulls() const override { return false; }
|
bool useDefaultImplementationForNulls() const override { return false; }
|
||||||
|
|
||||||
|
bool useDefaultImplementationForNothing() const override { return false; }
|
||||||
|
|
||||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
|
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
|
||||||
|
|
||||||
size_t getNumberOfArguments() const override
|
size_t getNumberOfArguments() const override
|
||||||
|
@ -65,6 +65,8 @@ public:
|
|||||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
|
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
|
||||||
|
|
||||||
bool useDefaultImplementationForNulls() const override { return false; }
|
bool useDefaultImplementationForNulls() const override { return false; }
|
||||||
|
/// map(..., Nothing) -> Map(..., Nothing)
|
||||||
|
bool useDefaultImplementationForNothing() const override { return false; }
|
||||||
bool useDefaultImplementationForConstants() const override { return true; }
|
bool useDefaultImplementationForConstants() const override { return true; }
|
||||||
|
|
||||||
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
||||||
|
@ -26,6 +26,8 @@ public:
|
|||||||
|
|
||||||
bool useDefaultImplementationForNulls() const override { return false; }
|
bool useDefaultImplementationForNulls() const override { return false; }
|
||||||
|
|
||||||
|
bool useDefaultImplementationForNothing() const override { return false; }
|
||||||
|
|
||||||
bool isShortCircuit(ShortCircuitSettings & settings, size_t /*number_of_arguments*/) const override
|
bool isShortCircuit(ShortCircuitSettings & settings, size_t /*number_of_arguments*/) const override
|
||||||
{
|
{
|
||||||
settings.enable_lazy_execution_for_first_argument = true;
|
settings.enable_lazy_execution_for_first_argument = true;
|
||||||
|
@ -28,6 +28,7 @@ public:
|
|||||||
|
|
||||||
size_t getNumberOfArguments() const override { return 1; }
|
size_t getNumberOfArguments() const override { return 1; }
|
||||||
bool useDefaultImplementationForNulls() const override { return false; }
|
bool useDefaultImplementationForNulls() const override { return false; }
|
||||||
|
bool useDefaultImplementationForNothing() const override { return false; }
|
||||||
bool useDefaultImplementationForConstants() const override { return true; }
|
bool useDefaultImplementationForConstants() const override { return true; }
|
||||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
|
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@ public:
|
|||||||
|
|
||||||
bool useDefaultImplementationForNulls() const override { return false; }
|
bool useDefaultImplementationForNulls() const override { return false; }
|
||||||
|
|
||||||
|
bool useDefaultImplementationForNothing() const override { return false; }
|
||||||
|
|
||||||
bool isShortCircuit(ShortCircuitSettings & settings, size_t /*number_of_arguments*/) const override
|
bool isShortCircuit(ShortCircuitSettings & settings, size_t /*number_of_arguments*/) const override
|
||||||
{
|
{
|
||||||
settings.enable_lazy_execution_for_first_argument = false;
|
settings.enable_lazy_execution_for_first_argument = false;
|
||||||
|
@ -52,6 +52,8 @@ public:
|
|||||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
|
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
|
||||||
|
|
||||||
bool useDefaultImplementationForNulls() 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; }
|
bool useDefaultImplementationForConstants() const override { return true; }
|
||||||
|
|
||||||
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
||||||
|
@ -21,7 +21,7 @@ INSERT INTO type_names VALUES (1, toTypeName([1, 2]), toTypeName((256, -1, 3.14,
|
|||||||
-- _NUM_5: Float64 -> Int64
|
-- _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 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 (1 + x); -- { clientError 62 }
|
||||||
INSERT INTO values_template_fallback VALUES (abs(functionThatDoesNotExists(42))); -- { clientError 46 }
|
INSERT INTO values_template_fallback VALUES (abs(functionThatDoesNotExists(42))); -- { clientError 46 }
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
[]
|
||||||
|
Array(Nothing)
|
||||||
|
[]
|
||||||
|
Array(Nothing)
|
||||||
|
[]
|
||||||
|
Array(Nothing)
|
||||||
|
[]
|
||||||
|
Array(Nothing)
|
||||||
|
Array(String)
|
||||||
|
Array(Nothing)
|
||||||
|
Array(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)
|
||||||
|
Array(Nothing)
|
||||||
|
Map(UInt8, Nothing)
|
||||||
|
Map(UInt8, Nothing)
|
||||||
|
Tuple(UInt8, Nothing)
|
||||||
|
Tuple(UInt8, Nothing)
|
||||||
|
Nothing
|
||||||
|
Nothing
|
@ -0,0 +1,40 @@
|
|||||||
|
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)')));
|
||||||
|
|
||||||
|
select arrayFilter(x -> 2 * x < 0, []);
|
||||||
|
select toTypeName(arrayFilter(x -> 2 * x < 0, []));
|
||||||
|
|
||||||
|
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(materialize(NULL)));
|
||||||
|
select toColumnTypeName(assumeNotNull(materialize(NULL)));
|
||||||
|
|
||||||
|
select toTypeName([assumeNotNull(materialize(NULL))]);
|
||||||
|
select toColumnTypeName([assumeNotNull(materialize(NULL))]);
|
||||||
|
|
||||||
|
select toTypeName(map(1, assumeNotNull(materialize(NULL))));
|
||||||
|
select toColumnTypeName(map(1, assumeNotNull(materialize(NULL))));
|
||||||
|
|
||||||
|
select toTypeName(tuple(1, assumeNotNull(materialize(NULL))));
|
||||||
|
select toColumnTypeName(tuple(1, assumeNotNull(materialize(NULL))));
|
||||||
|
|
||||||
|
select toTypeName(assumeNotNull(materialize(NULL)) * 2);
|
||||||
|
select toColumnTypeName(assumeNotNull(materialize(NULL)) * 2);
|
@ -0,0 +1,3 @@
|
|||||||
|
OK
|
||||||
|
OK
|
||||||
|
OK
|
10
tests/queries/0_stateless/02294_nothing_arguments_in_functions_errors.sh
Executable file
10
tests/queries/0_stateless/02294_nothing_arguments_in_functions_errors.sh
Executable file
@ -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"
|
||||||
|
|
@ -0,0 +1,4 @@
|
|||||||
|
[]
|
||||||
|
[]
|
||||||
|
[2,4]
|
||||||
|
[1,3]
|
@ -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]);
|
Loading…
Reference in New Issue
Block a user