mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-20 08:40:50 +00:00
Merge pull request #13228 from ClickHouse/decimal-too-large-negative-exponent
Fix assert when decimal has too large negative exponent
This commit is contained in:
commit
7786fd4119
@ -1,9 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <Common/intExp.h>
|
||||
|
||||
|
||||
/// This is only needed for non-official, "unbundled" build.
|
||||
/// https://stackoverflow.com/questions/41198673/uint128-t-not-working-with-clang-and-libstdc
|
||||
#if !defined(_LIBCPP_LIMITS) && !defined(__GLIBCXX_BITSIZE_INT_N_0) && defined(__SIZEOF_INT128__)
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct numeric_limits<__int128_t>
|
||||
{
|
||||
static constexpr bool is_specialized = true;
|
||||
static constexpr bool is_signed = true;
|
||||
static constexpr bool is_integer = true;
|
||||
static constexpr int radix = 2;
|
||||
static constexpr int digits = 127;
|
||||
static constexpr int digits10 = 38;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
@ -160,12 +180,24 @@ inline void readDecimalText(ReadBuffer & buf, T & x, uint32_t precision, uint32_
|
||||
|
||||
if (static_cast<int32_t>(scale) + exponent < 0)
|
||||
{
|
||||
/// Too many digits after point. Just cut off excessive digits.
|
||||
auto divisor = intExp10OfSize<T>(-exponent - static_cast<int32_t>(scale));
|
||||
assert(divisor > 0); /// This is for Clang Static Analyzer. It is not smart enough to infer it automatically.
|
||||
x.value /= divisor;
|
||||
scale = 0;
|
||||
return;
|
||||
auto divisor_exp = -exponent - static_cast<int32_t>(scale);
|
||||
|
||||
if (divisor_exp >= std::numeric_limits<typename T::NativeType>::digits10)
|
||||
{
|
||||
/// Too big negative exponent
|
||||
x.value = 0;
|
||||
scale = 0;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Too many digits after point. Just cut off excessive digits.
|
||||
auto divisor = intExp10OfSize<T>(divisor_exp);
|
||||
assert(divisor > 0); /// This is for Clang Static Analyzer. It is not smart enough to infer it automatically.
|
||||
x.value /= divisor;
|
||||
scale = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
scale += exponent;
|
||||
|
@ -34,6 +34,7 @@ namespace std
|
||||
static constexpr bool is_integer = true;
|
||||
static constexpr int radix = 2;
|
||||
static constexpr int digits = 128;
|
||||
static constexpr int digits10 = 38;
|
||||
static constexpr __uint128_t min () { return 0; } // used in boost 1.65.1+
|
||||
static constexpr __uint128_t max () { return __uint128_t(0) - 1; } // used in boost 1.68.0+
|
||||
};
|
||||
|
@ -0,0 +1,6 @@
|
||||
1E-9 0
|
||||
1E-8 0
|
||||
1E-7 0
|
||||
1e-7 0
|
||||
1E-9 0.000000001
|
||||
1E-10 0.000000000
|
@ -0,0 +1,10 @@
|
||||
SELECT '-1E9-1E9-1E9-1E9' AS x, toDecimal32(x, 0); -- { serverError 6 }
|
||||
SELECT '-1E9' AS x, toDecimal32(x, 0); -- { serverError 69 }
|
||||
SELECT '1E-9' AS x, toDecimal32(x, 0);
|
||||
SELECT '1E-8' AS x, toDecimal32(x, 0);
|
||||
SELECT '1E-7' AS x, toDecimal32(x, 0);
|
||||
SELECT '1e-7' AS x, toDecimal32(x, 0);
|
||||
SELECT '1E-9' AS x, toDecimal32(x, 9);
|
||||
SELECT '1E-9' AS x, toDecimal32(x, 10); -- { serverError 69 }
|
||||
SELECT '1E-10' AS x, toDecimal32(x, 10); -- { serverError 69 }
|
||||
SELECT '1E-10' AS x, toDecimal32(x, 9);
|
Loading…
Reference in New Issue
Block a user