fix decimal overflow, extreme values

This commit is contained in:
dmitry kuzmin 2019-06-16 10:57:30 +03:00
parent febca43a89
commit c73ce602bf
2 changed files with 18 additions and 8 deletions

View File

@ -327,20 +327,22 @@ convertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale)
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);
auto out = value * ToDataType::getScaleMultiplier(scale); ToNativeType min_value;
ToNativeType max_value;
if constexpr (std::is_same_v<ToNativeType, Int128>) if constexpr (std::is_same_v<ToNativeType, Int128>)
{ {
static constexpr __int128 min_int128 = __int128(0x8000000000000000ll) << 64; min_value = __int128(0x8000000000000000ll) << 64; // min __int128
static constexpr __int128 max_int128 = (__int128(0x7fffffffffffffffll) << 64) + 0xffffffffffffffffll; max_value = (__int128(0x7fffffffffffffffll) << 64) + 0xffffffffffffffffll; // max __int128
if (out < min_int128 || out > max_int128)
throw Exception("Decimal convert overflow. Float is out of Decimal range", ErrorCodes::DECIMAL_OVERFLOW);
} }
else else
{ {
if (out < std::numeric_limits<ToNativeType>::min() || out > std::numeric_limits<ToNativeType>::max()) min_value = std::numeric_limits<ToNativeType>::min();
throw Exception("Decimal convert overflow. Float is out of Decimal range", ErrorCodes::DECIMAL_OVERFLOW); max_value = std::numeric_limits<ToNativeType>::max();
} }
return out; ToNativeType converted_value = static_cast<ToNativeType>(value * ToDataType::getScaleMultiplier(scale));
if (converted_value == min_value || converted_value == max_value)
throw Exception("Decimal convert overflow. Float is out of Decimal range", ErrorCodes::DECIMAL_OVERFLOW);
return converted_value;
} }
else else
{ {

View File

@ -258,3 +258,11 @@ select toDecimal128(1000000000000000000000.1, 18); -- { serverError 407 }
select toDecimal32(-10000.1, 6); -- { serverError 407 } select toDecimal32(-10000.1, 6); -- { serverError 407 }
select toDecimal64(-10000.1, 18); -- { serverError 407 } select toDecimal64(-10000.1, 18); -- { serverError 407 }
select toDecimal128(-1000000000000000000000.1, 18); -- { serverError 407 } select toDecimal128(-1000000000000000000000.1, 18); -- { serverError 407 }
select toDecimal32(2147483647.0 + 1.0, 0); -- { serverError 407 }
select toDecimal64(9223372036854775807.0, 0); -- { serverError 407 }
select toDecimal128(170141183460469231731687303715884105729.0, 0); -- { serverError 407 }
select toDecimal32(-2147483647.0 - 1.0, 0); -- { serverError 407 }
select toDecimal64(-9223372036854775807.0, 0); -- { serverError 407 }
select toDecimal128(-170141183460469231731687303715884105729.0, 0); -- { serverError 407 }