mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-24 00:22:29 +00:00
CAST keep nullable (#11733)
This commit is contained in:
parent
d0beeaf7c4
commit
6af36cb703
@ -379,6 +379,7 @@ struct Settings : public SettingsCollection<Settings>
|
||||
\
|
||||
M(SettingBool, allow_experimental_geo_types, false, "Allow geo data types such as Point, Ring, Polygon, MultiPolygon", 0) \
|
||||
M(SettingBool, data_type_default_nullable, false, "Data types without NULL or NOT NULL will make Nullable", 0) \
|
||||
M(SettingBool, cast_keep_nullable, false, "CAST operator keep Nullable for result data type", 0) \
|
||||
\
|
||||
/** Obsolete settings that do nothing but left for compatibility reasons. Remove each one after half a year of obsolescence. */ \
|
||||
\
|
||||
|
@ -1,10 +1,16 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionsConversion.h>
|
||||
#include <Interpreters/Context.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
FunctionOverloadResolverImplPtr CastOverloadResolver::create(const Context & context)
|
||||
{
|
||||
return createImpl(context.getSettingsRef().cast_keep_nullable);
|
||||
}
|
||||
|
||||
void registerFunctionsConversion(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionToUInt8>();
|
||||
|
@ -2377,10 +2377,13 @@ public:
|
||||
using MonotonicityForRange = FunctionCast::MonotonicityForRange;
|
||||
|
||||
static constexpr auto name = "CAST";
|
||||
static FunctionOverloadResolverImplPtr create(const Context &) { return createImpl(); }
|
||||
static FunctionOverloadResolverImplPtr createImpl() { return std::make_unique<CastOverloadResolver>(); }
|
||||
|
||||
CastOverloadResolver() {}
|
||||
static FunctionOverloadResolverImplPtr create(const Context & context);
|
||||
static FunctionOverloadResolverImplPtr createImpl(bool keep_nullable) { return std::make_unique<CastOverloadResolver>(keep_nullable); }
|
||||
|
||||
CastOverloadResolver(bool keep_nullable_)
|
||||
: keep_nullable(keep_nullable_)
|
||||
{}
|
||||
|
||||
String getName() const override { return name; }
|
||||
|
||||
@ -2415,13 +2418,18 @@ protected:
|
||||
" Instead there is a column with the following structure: " + column->dumpStructure(),
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
|
||||
return DataTypeFactory::instance().get(type_col->getValue<String>());
|
||||
DataTypePtr type = DataTypeFactory::instance().get(type_col->getValue<String>());
|
||||
if (keep_nullable && arguments.front().type->isNullable())
|
||||
return makeNullable(type);
|
||||
return type;
|
||||
}
|
||||
|
||||
bool useDefaultImplementationForNulls() const override { return false; }
|
||||
bool useDefaultImplementationForLowCardinalityColumns() const override { return false; }
|
||||
|
||||
private:
|
||||
bool keep_nullable;
|
||||
|
||||
template <typename DataType>
|
||||
static auto monotonicityForType(const DataType * const)
|
||||
{
|
||||
|
@ -693,11 +693,12 @@ private:
|
||||
|
||||
static ColumnPtr makeNullableColumnIfNot(const ColumnPtr & column)
|
||||
{
|
||||
if (isColumnNullable(*column))
|
||||
return column;
|
||||
auto materialized = materializeColumnIfConst(column);
|
||||
|
||||
return ColumnNullable::create(
|
||||
materializeColumnIfConst(column), ColumnUInt8::create(column->size(), 0));
|
||||
if (isColumnNullable(*materialized))
|
||||
return materialized;
|
||||
|
||||
return ColumnNullable::create(materialized, ColumnUInt8::create(column->size(), 0));
|
||||
}
|
||||
|
||||
static ColumnPtr getNestedColumn(const ColumnPtr & column)
|
||||
|
@ -29,7 +29,8 @@ ColumnPtr castColumn(const ColumnWithTypeAndName & arg, const DataTypePtr & type
|
||||
}
|
||||
};
|
||||
|
||||
FunctionOverloadResolverPtr func_builder_cast = std::make_shared<FunctionOverloadResolverAdaptor>(CastOverloadResolver::createImpl());
|
||||
FunctionOverloadResolverPtr func_builder_cast =
|
||||
std::make_shared<FunctionOverloadResolverAdaptor>(CastOverloadResolver::createImpl(false));
|
||||
|
||||
ColumnsWithTypeAndName arguments{ temporary_block.getByPosition(0), temporary_block.getByPosition(1) };
|
||||
auto func_cast = func_builder_cast->build(arguments);
|
||||
|
10
tests/queries/0_stateless/01322_cast_keep_nullable.reference
Normal file
10
tests/queries/0_stateless/01322_cast_keep_nullable.reference
Normal file
@ -0,0 +1,10 @@
|
||||
0 Int32
|
||||
0 Int32
|
||||
1 Nullable(Int32)
|
||||
1 Nullable(Int32)
|
||||
2 Nullable(Float32)
|
||||
2 Nullable(UInt8)
|
||||
3 Nullable(Int32)
|
||||
\N Nullable(Int32)
|
||||
42 Nullable(Int32)
|
||||
\N Nullable(Int32)
|
19
tests/queries/0_stateless/01322_cast_keep_nullable.sql
Normal file
19
tests/queries/0_stateless/01322_cast_keep_nullable.sql
Normal file
@ -0,0 +1,19 @@
|
||||
SET cast_keep_nullable = 0;
|
||||
|
||||
SELECT CAST(toNullable(toInt32(0)) AS Int32) as x, toTypeName(x);
|
||||
SELECT CAST(toNullable(toInt8(0)) AS Int32) as x, toTypeName(x);
|
||||
|
||||
SET cast_keep_nullable = 1;
|
||||
|
||||
SELECT CAST(toNullable(toInt32(1)) AS Int32) as x, toTypeName(x);
|
||||
SELECT CAST(toNullable(toInt8(1)) AS Int32) as x, toTypeName(x);
|
||||
|
||||
SELECT CAST(toNullable(toFloat32(2)), 'Float32') as x, toTypeName(x);
|
||||
SELECT CAST(toNullable(toFloat32(2)), 'UInt8') as x, toTypeName(x);
|
||||
SELECT CAST(toNullable(toFloat32(2)), 'UUID') as x, toTypeName(x); -- { serverError 70 }
|
||||
|
||||
SELECT CAST(if(1 = 1, toNullable(toInt8(3)), NULL) AS Int32) as x, toTypeName(x);
|
||||
SELECT CAST(if(1 = 0, toNullable(toInt8(3)), NULL) AS Int32) as x, toTypeName(x);
|
||||
|
||||
SELECT CAST(a, 'Int32') as x, toTypeName(x) FROM (SELECT materialize(CAST(42, 'Nullable(UInt8)')) AS a);
|
||||
SELECT CAST(a, 'Int32') as x, toTypeName(x) FROM (SELECT materialize(CAST(NULL, 'Nullable(UInt8)')) AS a);
|
Loading…
Reference in New Issue
Block a user