CAST keep nullable (#11733)

This commit is contained in:
Artem Zuikov 2020-06-18 13:18:28 +03:00 committed by GitHub
parent d0beeaf7c4
commit 6af36cb703
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 55 additions and 9 deletions

View File

@ -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. */ \
\

View File

@ -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>();

View File

@ -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)
{

View File

@ -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)

View File

@ -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);

View 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)

View 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);