Merge pull request #5607 from coraxster/decimal-overflow

Fix float to decimal convert overflow
This commit is contained in:
alexey-milovidov 2019-06-14 09:20:39 +03:00 committed by GitHub
commit e90a7078f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 24 additions and 1 deletions

View File

@ -320,12 +320,27 @@ inline std::enable_if_t<IsDataTypeNumber<FromDataType> && IsDataTypeDecimal<ToDa
convertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale) convertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale)
{ {
using FromFieldType = typename FromDataType::FieldType; using FromFieldType = typename FromDataType::FieldType;
using ToNativeType = typename ToDataType::FieldType::NativeType;
if constexpr (std::is_floating_point_v<FromFieldType>) if constexpr (std::is_floating_point_v<FromFieldType>)
{ {
if (!std::isfinite(value)) if (!std::isfinite(value))
throw Exception("Decimal convert overflow. Cannot convert infinity or NaN to decimal", ErrorCodes::DECIMAL_OVERFLOW); throw Exception("Decimal convert overflow. Cannot convert infinity or NaN to decimal", ErrorCodes::DECIMAL_OVERFLOW);
return value * ToDataType::getScaleMultiplier(scale);
auto out = value * ToDataType::getScaleMultiplier(scale);
if constexpr (std::is_same_v<ToNativeType, Int128>)
{
static constexpr __int128 min_int128 = __int128(0x8000000000000000ll) << 64;
static constexpr __int128 max_int128 = (__int128(0x7fffffffffffffffll) << 64) + 0xffffffffffffffffll;
if (out < min_int128 || out > max_int128)
throw Exception("Decimal convert overflow. Float is out of Decimal range", ErrorCodes::DECIMAL_OVERFLOW);
}
else
{
if (out < std::numeric_limits<ToNativeType>::min() || out > std::numeric_limits<ToNativeType>::max())
throw Exception("Decimal convert overflow. Float is out of Decimal range", ErrorCodes::DECIMAL_OVERFLOW);
}
return out;
} }
else else
{ {

View File

@ -250,3 +250,11 @@ SELECT CAST(1/0, 'Decimal(38, 2)'); -- { serverError 407 }
SELECT CAST(0/0, 'Decimal(9, 3)'); -- { serverError 407 } SELECT CAST(0/0, 'Decimal(9, 3)'); -- { serverError 407 }
SELECT CAST(0/0, 'Decimal(18, 4)'); -- { serverError 407 } SELECT CAST(0/0, 'Decimal(18, 4)'); -- { serverError 407 }
SELECT CAST(0/0, 'Decimal(38, 5)'); -- { serverError 407 } SELECT CAST(0/0, 'Decimal(38, 5)'); -- { serverError 407 }
select toDecimal32(10000.1, 6); -- { serverError 407 }
select toDecimal64(10000.1, 18); -- { serverError 407 }
select toDecimal128(1000000000000000000000.1, 18); -- { serverError 407 }
select toDecimal32(-10000.1, 6); -- { serverError 407 }
select toDecimal64(-10000.1, 18); -- { serverError 407 }
select toDecimal128(-1000000000000000000000.1, 18); -- { serverError 407 }