Skip to content

Commit

Permalink
Merge pull request #54629 from aiven-sal/aiven-sal/cast2
Browse files Browse the repository at this point in the history
Re-add fix for accurateCastOrNull
  • Loading branch information
rschu1ze committed Oct 25, 2023
2 parents bee9eb5 + 4cf17dc commit 975f954
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 13 deletions.
66 changes: 55 additions & 11 deletions src/Functions/FunctionsConversion.h
Expand Up @@ -89,6 +89,7 @@ namespace ErrorCodes
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
extern const int NOT_IMPLEMENTED;
extern const int CANNOT_INSERT_NULL_IN_ORDINARY_COLUMN;
extern const int CANNOT_PARSE_BOOL;
}


Expand Down Expand Up @@ -1683,7 +1684,25 @@ struct ConvertImplGenericFromString

const auto & val = col_from_string->getDataAt(i);
ReadBufferFromMemory read_buffer(val.data, val.size);
serialization_from.deserializeWholeText(column_to, read_buffer, format_settings);
try
{
serialization_from.deserializeWholeText(column_to, read_buffer, format_settings);
}
catch (const Exception & e)
{
auto * nullable_column = typeid_cast<ColumnNullable *>(&column_to);
if (e.code() == ErrorCodes::CANNOT_PARSE_BOOL && nullable_column)
{
auto & col_nullmap = nullable_column->getNullMapData();
if (col_nullmap.size() != nullable_column->size())
col_nullmap.resize_fill(nullable_column->size());
if (nullable_column->size() == (i + 1))
nullable_column->popBack(1);
nullable_column->insertDefault();
continue;
}
throw;
}

if (!read_buffer.eof())
{
Expand Down Expand Up @@ -4177,15 +4196,21 @@ class FunctionCast final : public FunctionCastBase
{
if constexpr (std::is_same_v<ToDataType, DataTypeIPv4>)
{
ret = [cast_ipv4_ipv6_default_on_conversion_error_value, input_format_ipv4_default_on_conversion_error_value, requested_result_is_nullable](
ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, const ColumnNullable * column_nullable, size_t)
-> ColumnPtr
ret = [cast_ipv4_ipv6_default_on_conversion_error_value,
input_format_ipv4_default_on_conversion_error_value,
requested_result_is_nullable](
ColumnsWithTypeAndName & arguments,
const DataTypePtr & result_type,
const ColumnNullable * column_nullable,
size_t) -> ColumnPtr
{
if (!WhichDataType(result_type).isIPv4())
throw Exception(ErrorCodes::TYPE_MISMATCH, "Wrong result type {}. Expected IPv4", result_type->getName());

const auto * null_map = column_nullable ? &column_nullable->getNullMapData() : nullptr;
if (cast_ipv4_ipv6_default_on_conversion_error_value || input_format_ipv4_default_on_conversion_error_value || requested_result_is_nullable)
if (requested_result_is_nullable)
return convertToIPv4<IPStringToNumExceptionMode::Null>(arguments[0].column, null_map);
else if (cast_ipv4_ipv6_default_on_conversion_error_value || input_format_ipv4_default_on_conversion_error_value)
return convertToIPv4<IPStringToNumExceptionMode::Default>(arguments[0].column, null_map);
else
return convertToIPv4<IPStringToNumExceptionMode::Throw>(arguments[0].column, null_map);
Expand All @@ -4196,16 +4221,22 @@ class FunctionCast final : public FunctionCastBase

if constexpr (std::is_same_v<ToDataType, DataTypeIPv6>)
{
ret = [cast_ipv4_ipv6_default_on_conversion_error_value, input_format_ipv6_default_on_conversion_error_value, requested_result_is_nullable](
ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, const ColumnNullable * column_nullable, size_t)
-> ColumnPtr
ret = [cast_ipv4_ipv6_default_on_conversion_error_value,
input_format_ipv6_default_on_conversion_error_value,
requested_result_is_nullable](
ColumnsWithTypeAndName & arguments,
const DataTypePtr & result_type,
const ColumnNullable * column_nullable,
size_t) -> ColumnPtr
{
if (!WhichDataType(result_type).isIPv6())
throw Exception(
ErrorCodes::TYPE_MISMATCH, "Wrong result type {}. Expected IPv6", result_type->getName());

const auto * null_map = column_nullable ? &column_nullable->getNullMapData() : nullptr;
if (cast_ipv4_ipv6_default_on_conversion_error_value || input_format_ipv6_default_on_conversion_error_value || requested_result_is_nullable)
if (requested_result_is_nullable)
return convertToIPv6<IPStringToNumExceptionMode::Null>(arguments[0].column, null_map);
else if (cast_ipv4_ipv6_default_on_conversion_error_value || input_format_ipv6_default_on_conversion_error_value)
return convertToIPv6<IPStringToNumExceptionMode::Default>(arguments[0].column, null_map);
else
return convertToIPv6<IPStringToNumExceptionMode::Throw>(arguments[0].column, null_map);
Expand All @@ -4216,7 +4247,18 @@ class FunctionCast final : public FunctionCastBase

if (to_type->getCustomSerialization() && to_type->getCustomName())
{
ret = &ConvertImplGenericFromString<typename FromDataType::ColumnType>::execute;
ret = [requested_result_is_nullable](
ColumnsWithTypeAndName & arguments,
const DataTypePtr & result_type,
const ColumnNullable * column_nullable,
size_t input_rows_count) -> ColumnPtr
{
auto wrapped_result_type = result_type;
if (requested_result_is_nullable)
wrapped_result_type = makeNullable(result_type);
return ConvertImplGenericFromString<typename FromDataType::ColumnType>::execute(
arguments, wrapped_result_type, column_nullable, input_rows_count);
};
return true;
}
}
Expand All @@ -4231,7 +4273,9 @@ class FunctionCast final : public FunctionCastBase
ErrorCodes::TYPE_MISMATCH, "Wrong result type {}. Expected IPv4", result_type->getName());

const auto * null_map = column_nullable ? &column_nullable->getNullMapData() : nullptr;
if (cast_ipv4_ipv6_default_on_conversion_error_value || requested_result_is_nullable)
if (requested_result_is_nullable)
return convertIPv6ToIPv4<IPStringToNumExceptionMode::Null>(arguments[0].column, null_map);
else if (cast_ipv4_ipv6_default_on_conversion_error_value)
return convertIPv6ToIPv4<IPStringToNumExceptionMode::Default>(arguments[0].column, null_map);
else
return convertIPv6ToIPv4<IPStringToNumExceptionMode::Throw>(arguments[0].column, null_map);
Expand Down
18 changes: 18 additions & 0 deletions tests/queries/0_stateless/01556_accurate_cast_or_null.reference
Expand Up @@ -42,3 +42,21 @@
2023-05-30
2149-06-06
1970-01-20
\N
\N
\N
true
false
true
false
true
false
\N
\N
\N
192.0.2.1
\N
\N
::ffff:192.0.2.1
2001:db8::1
\N
21 changes: 21 additions & 0 deletions tests/queries/0_stateless/01556_accurate_cast_or_null.sql
Expand Up @@ -49,3 +49,24 @@ SELECT accurateCastOrNull('1xxx', 'Date');
SELECT accurateCastOrNull('2023-05-30', 'Date');
SELECT accurateCastOrNull('2180-01-01', 'Date');
SELECT accurateCastOrNull(19, 'Date');

select accurateCastOrNull('test', 'Bool');
select accurateCastOrNull('truex', 'Bool');
select accurateCastOrNull('xfalse', 'Bool');
select accurateCastOrNull('true', 'Bool');
select accurateCastOrNull('false', 'Bool');
select accurateCastOrNull('1', 'Bool');
select accurateCastOrNull('0', 'Bool');
select accurateCastOrNull(1, 'Bool');
select accurateCastOrNull(0, 'Bool');

select accurateCastOrNull('test', 'IPv4');
select accurateCastOrNull('2001:db8::1', 'IPv4');
select accurateCastOrNull('::ffff:192.0.2.1', 'IPv4');
select accurateCastOrNull('192.0.2.1', 'IPv4');
select accurateCastOrNull('192.0.2.1x', 'IPv4');

select accurateCastOrNull('test', 'IPv6');
select accurateCastOrNull('192.0.2.1', 'IPv6');
select accurateCastOrNull('2001:db8::1', 'IPv6');
select accurateCastOrNull('2001:db8::1x', 'IPv6');
12 changes: 12 additions & 0 deletions tests/queries/0_stateless/01601_accurate_cast.reference
Expand Up @@ -10,3 +10,15 @@
1970-01-01 00:00:19
2023-05-30
1970-01-20
\N
true
false
true
false
true
false
\N
192.0.2.1
\N
::ffff:192.0.2.1
2001:db8::1
24 changes: 24 additions & 0 deletions tests/queries/0_stateless/01601_accurate_cast.sql
Expand Up @@ -34,3 +34,27 @@ SELECT accurateCast(0xFFFFFFFF + 1, 'Date'); -- { serverError CANNOT_CONVERT_T
SELECT accurateCast('1xxx', 'Date'); -- { serverError CANNOT_PARSE_DATE }
SELECT accurateCast('2023-05-30', 'Date');
SELECT accurateCast(19, 'Date');

select accurateCast('test', 'Nullable(Bool)');
select accurateCast('test', 'Bool'); -- { serverError CANNOT_PARSE_BOOL }
select accurateCast('truex', 'Bool'); -- { serverError CANNOT_PARSE_BOOL }
select accurateCast('xfalse', 'Bool'); -- { serverError CANNOT_PARSE_BOOL }
select accurateCast('true', 'Bool');
select accurateCast('false', 'Bool');
select accurateCast('1', 'Bool');
select accurateCast('0', 'Bool');
select accurateCast(1, 'Bool');
select accurateCast(0, 'Bool');

select accurateCast('test', 'Nullable(IPv4)');
select accurateCast('test', 'IPv4'); -- { serverError CANNOT_PARSE_IPV4 }
select accurateCast('2001:db8::1', 'IPv4'); -- { serverError CANNOT_PARSE_IPV4 }
select accurateCast('::ffff:192.0.2.1', 'IPv4'); -- { serverError CANNOT_PARSE_IPV4 }
select accurateCast('192.0.2.1', 'IPv4');
select accurateCast('192.0.2.1x', 'IPv4'); -- { serverError CANNOT_PARSE_IPV4 }

select accurateCast('test', 'Nullable(IPv6)');
select accurateCast('test', 'IPv6'); -- { serverError CANNOT_PARSE_IPV6 }
select accurateCast('192.0.2.1', 'IPv6');
select accurateCast('2001:db8::1', 'IPv6');
select accurateCast('2001:db8::1x', 'IPv6'); -- { serverError CANNOT_PARSE_IPV6 }
21 changes: 21 additions & 0 deletions tests/queries/0_stateless/02026_accurate_cast_or_default.reference
Expand Up @@ -30,3 +30,24 @@
0 5
127 127
0 5
\N
false
false
false
true
false
true
false
true
false
\N
0.0.0.0
0.0.0.0
0.0.0.0
192.0.2.1
0.0.0.0
\N
::
::ffff:192.0.2.1
2001:db8::1
::
24 changes: 24 additions & 0 deletions tests/queries/0_stateless/02026_accurate_cast_or_default.sql
Expand Up @@ -34,3 +34,27 @@ SELECT accurateCastOrDefault(nan, 'UInt64'), accurateCastOrDefault(nan, 'UInt64'
SELECT accurateCastOrDefault(nan, 'UInt256'), accurateCastOrDefault(nan, 'UInt256', toUInt256(5));

SELECT accurateCastOrDefault(number + 127, 'Int8') AS x, accurateCastOrDefault(number + 127, 'Int8', toInt8(5)) AS x_with_default FROM numbers (2) ORDER BY number;

select accurateCastOrDefault('test', 'Nullable(Bool)');
select accurateCastOrDefault('test', 'Bool');
select accurateCastOrDefault('truex', 'Bool');
select accurateCastOrDefault('xfalse', 'Bool');
select accurateCastOrDefault('true', 'Bool');
select accurateCastOrDefault('false', 'Bool');
select accurateCastOrDefault('1', 'Bool');
select accurateCastOrDefault('0', 'Bool');
select accurateCastOrDefault(1, 'Bool');
select accurateCastOrDefault(0, 'Bool');

select accurateCastOrDefault('test', 'Nullable(IPv4)');
select accurateCastOrDefault('test', 'IPv4');
select accurateCastOrDefault('2001:db8::1', 'IPv4');
select accurateCastOrDefault('::ffff:192.0.2.1', 'IPv4');
select accurateCastOrDefault('192.0.2.1', 'IPv4');
select accurateCastOrDefault('192.0.2.1x', 'IPv4');

select accurateCastOrDefault('test', 'Nullable(IPv6)');
select accurateCastOrDefault('test', 'IPv6');
select accurateCastOrDefault('192.0.2.1', 'IPv6');
select accurateCastOrDefault('2001:db8::1', 'IPv6');
select accurateCastOrDefault('2001:db8::1x', 'IPv6');
Expand Up @@ -17,16 +17,29 @@ true
\N
0.0.0.0
\N
0.0.0.0
\N
\N
\N
\N
0
\N
::
\N
::
\N
\N
\N
\N
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
fuzzer issue
\N
\N
\N
\N
\N
\N
\N
\N
\N
\N
\N
\N
Expand Up @@ -22,3 +22,9 @@ select toIPv6(number % 2 ? '0000:0000:0000:0000:0000:0000:0000:0000' : NULL) fro
select toIPv6OrDefault(number % 2 ? '' : NULL) from numbers(2);
select toIPv6OrNull(number % 2 ? '' : NULL) from numbers(2);
select IPv6StringToNum(number % 2 ? '0000:0000:0000:0000:0000:0000:0000:0000' : NULL) from numbers(2);

select 'fuzzer issue';
SELECT CAST(if(number % 2, 'truetrue', NULL), 'Nullable(Bool)') FROM numbers(2);
SELECT CAST(if(number % 2, 'falsefalse', NULL), 'Nullable(Bool)') FROM numbers(2);
SELECT accurateCastOrNull(if(number % 2, NULL, 'truex'), 'Bool') FROM numbers(4);
SELECT accurateCastOrNull(if(number % 2, 'truex', NULL), 'Bool') FROM numbers(4);

0 comments on commit 975f954

Please sign in to comment.