From 5fc6a6973ac844af909e101de69a1e944a9e53b7 Mon Sep 17 00:00:00 2001 From: dmitry kuzmin Date: Thu, 13 Jun 2019 23:28:14 +0300 Subject: [PATCH] float to decimal overflow fix --- dbms/src/DataTypes/DataTypesDecimal.h | 21 ++++++++++--------- .../0_stateless/00700_decimal_casts.sql | 4 ++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/dbms/src/DataTypes/DataTypesDecimal.h b/dbms/src/DataTypes/DataTypesDecimal.h index 49f00aafa9c..ea0d777784d 100644 --- a/dbms/src/DataTypes/DataTypesDecimal.h +++ b/dbms/src/DataTypes/DataTypesDecimal.h @@ -324,22 +324,23 @@ convertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale) if constexpr (std::is_floating_point_v) { - ToNativeType min_value; - ToNativeType max_value; + if (!std::isfinite(value)) + throw Exception("Decimal convert overflow. Cannot convert infinity or NaN to decimal", ErrorCodes::DECIMAL_OVERFLOW); + + auto out = value * ToDataType::getScaleMultiplier(scale); if constexpr (std::is_same_v) { - min_value = __int128(0x8000000000000000ll) << 64; // min __int128 - max_value = (__int128(0x7fffffffffffffffll) << 64) + 0xffffffffffffffffll; // max __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 { - min_value = std::numeric_limits::min(); - max_value = std::numeric_limits::max(); + if (out < std::numeric_limits::min() || out > std::numeric_limits::max()) + throw Exception("Decimal convert overflow. Float is out of Decimal range", ErrorCodes::DECIMAL_OVERFLOW); } - ToNativeType converted_value = static_cast(value * ToDataType::getScaleMultiplier(scale)); - if (converted_value == min_value || converted_value == max_value) - throw Exception("Decimal convert overflow", ErrorCodes::DECIMAL_OVERFLOW); - return converted_value; + return out; } else { diff --git a/dbms/tests/queries/0_stateless/00700_decimal_casts.sql b/dbms/tests/queries/0_stateless/00700_decimal_casts.sql index 5c7de179624..bc32f5b19fc 100644 --- a/dbms/tests/queries/0_stateless/00700_decimal_casts.sql +++ b/dbms/tests/queries/0_stateless/00700_decimal_casts.sql @@ -254,3 +254,7 @@ 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 }