mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-24 08:32:02 +00:00
add two options to disable Decimal overflow checks CLICKHOUSE-3906
This commit is contained in:
parent
eac6dd1c99
commit
314dcc5e9e
@ -8,6 +8,7 @@
|
||||
#include <IO/readFloatText.h>
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Interpreters/Context.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -20,6 +21,10 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
bool decimalCheckComparisonOverflow(const Context & context) { return context.getSettingsRef().decimal_check_comparison_overflow; }
|
||||
bool decimalCheckArithmeticOverflow(const Context & context) { return context.getSettingsRef().decimal_check_arithmetic_overflow; }
|
||||
|
||||
|
||||
//
|
||||
|
||||
template <typename T>
|
||||
|
@ -63,6 +63,11 @@ class DataTypeSimpleSerialization : public IDataType
|
||||
};
|
||||
|
||||
|
||||
class Context;
|
||||
bool decimalCheckComparisonOverflow(const Context & context);
|
||||
bool decimalCheckArithmeticOverflow(const Context & context);
|
||||
|
||||
|
||||
static constexpr size_t minDecimalPrecision() { return 1; }
|
||||
template <typename T> static constexpr size_t maxDecimalPrecision() { return 0; }
|
||||
template <> constexpr size_t maxDecimalPrecision<Decimal32>() { return 9; }
|
||||
|
@ -725,7 +725,7 @@ template <> struct NativeType<Decimal128> { using Type = Int128; };
|
||||
/// +|- scale one of args (which scale factor is not 1). ScaleR = oneof(Scale1, Scale2);
|
||||
/// * no agrs scale. ScaleR = Scale1 + Scale2;
|
||||
/// / first arg scale. ScaleR = Scale1 (scale_a = DecimalType<B>::getScale()).
|
||||
template <typename A, typename B, template <typename, typename> typename Operation, typename ResultType_>
|
||||
template <typename A, typename B, template <typename, typename> typename Operation, typename ResultType_, bool _check_overflow = true>
|
||||
struct DecimalBinaryOperation
|
||||
{
|
||||
using ResultType = ResultType_;
|
||||
@ -734,6 +734,7 @@ struct DecimalBinaryOperation
|
||||
using ArrayA = typename ColumnVector<A>::Container;
|
||||
using ArrayB = typename ColumnVector<B>::Container;
|
||||
using ArrayC = typename ColumnVector<ResultType>::Container;
|
||||
using XOverflow = DecimalBinaryOperation<A, B, Operation, ResultType_, !_check_overflow>;
|
||||
|
||||
static constexpr bool is_plus_minus = std::is_same_v<Operation<Int32, Int32>, PlusImpl<Int32, Int32>> ||
|
||||
std::is_same_v<Operation<Int32, Int32>, MinusImpl<Int32, Int32>>;
|
||||
@ -855,7 +856,7 @@ private:
|
||||
/// there's implicit type convertion here
|
||||
static NativeResultType apply(NativeResultType a, NativeResultType b)
|
||||
{
|
||||
if constexpr (can_overflow)
|
||||
if constexpr (can_overflow && _check_overflow)
|
||||
{
|
||||
NativeResultType res;
|
||||
if (Op::template apply<NativeResultType>(a, b, res))
|
||||
@ -873,19 +874,30 @@ private:
|
||||
{
|
||||
NativeResultType res;
|
||||
|
||||
bool overflow = false;
|
||||
if constexpr (scale_left)
|
||||
overflow |= common::mulOverflow(a, scale, a);
|
||||
else
|
||||
overflow |= common::mulOverflow(b, scale, b);
|
||||
if constexpr (_check_overflow)
|
||||
{
|
||||
bool overflow = false;
|
||||
if constexpr (scale_left)
|
||||
overflow |= common::mulOverflow(a, scale, a);
|
||||
else
|
||||
overflow |= common::mulOverflow(b, scale, b);
|
||||
|
||||
if constexpr (can_overflow)
|
||||
overflow |= Op::template apply<NativeResultType>(a, b, res);
|
||||
if constexpr (can_overflow)
|
||||
overflow |= Op::template apply<NativeResultType>(a, b, res);
|
||||
else
|
||||
res = Op::template apply<NativeResultType>(a, b);
|
||||
|
||||
if (overflow)
|
||||
throw Exception("Decimal math overflow", ErrorCodes::DECIMAL_OVERFLOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (scale_left)
|
||||
a *= scale;
|
||||
else
|
||||
b *= scale;
|
||||
res = Op::template apply<NativeResultType>(a, b);
|
||||
|
||||
if (overflow)
|
||||
throw Exception("Decimal math overflow", ErrorCodes::DECIMAL_OVERFLOW);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -895,12 +907,21 @@ private:
|
||||
{
|
||||
if constexpr (is_division)
|
||||
{
|
||||
bool overflow = false;
|
||||
if constexpr (!IsDecimalNumber<A>)
|
||||
overflow |= common::mulOverflow(scale, scale, scale);
|
||||
overflow |= common::mulOverflow(a, scale, a);
|
||||
if (overflow)
|
||||
throw Exception("Decimal math overflow", ErrorCodes::DECIMAL_OVERFLOW);
|
||||
if constexpr (_check_overflow)
|
||||
{
|
||||
bool overflow = false;
|
||||
if constexpr (!IsDecimalNumber<A>)
|
||||
overflow |= common::mulOverflow(scale, scale, scale);
|
||||
overflow |= common::mulOverflow(a, scale, a);
|
||||
if (overflow)
|
||||
throw Exception("Decimal math overflow", ErrorCodes::DECIMAL_OVERFLOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (!IsDecimalNumber<A>)
|
||||
scale *= scale;
|
||||
a *= scale;
|
||||
}
|
||||
|
||||
return Op::template apply<NativeResultType>(a, b);
|
||||
}
|
||||
@ -1072,7 +1093,7 @@ public:
|
||||
static constexpr auto name = Name::name;
|
||||
static FunctionPtr create(const Context & context) { return std::make_shared<FunctionBinaryArithmetic>(context); }
|
||||
|
||||
FunctionBinaryArithmetic(const Context & context) : context(context) {}
|
||||
FunctionBinaryArithmetic(const Context & context_) : context(context_) {}
|
||||
|
||||
String getName() const override
|
||||
{
|
||||
@ -1197,10 +1218,20 @@ public:
|
||||
typename ResultDataType::FieldType scale_b = type.scaleFactorFor(right, is_multiply || is_division);
|
||||
if constexpr (IsDecimal<RightDataType> && is_division)
|
||||
scale_a = right.getScaleMultiplier();
|
||||
auto res = OpImpl::constant_constant(col_left->template getValue<T0>(), col_right->template getValue<T1>(),
|
||||
scale_a, scale_b);
|
||||
block.getByPosition(result).column =
|
||||
ResultDataType(type.getPrecision(), type.getScale()).createColumnConst(col_left->size(), toField(res));
|
||||
if (decimalCheckArithmeticOverflow(context))
|
||||
{
|
||||
auto res = OpImpl::constant_constant(
|
||||
col_left->template getValue<T0>(), col_right->template getValue<T1>(), scale_a, scale_b);
|
||||
block.getByPosition(result).column =
|
||||
ResultDataType(type.getPrecision(), type.getScale()).createColumnConst(col_left->size(), toField(res));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto res = OpImpl::XOverflow::constant_constant(
|
||||
col_left->template getValue<T0>(), col_right->template getValue<T1>(), scale_a, scale_b);
|
||||
block.getByPosition(result).column =
|
||||
ResultDataType(type.getPrecision(), type.getScale()).createColumnConst(col_left->size(), toField(res));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1227,7 +1258,11 @@ public:
|
||||
typename ResultDataType::FieldType scale_b = type.scaleFactorFor(right, is_multiply || is_division);
|
||||
if constexpr (IsDecimal<RightDataType> && is_division)
|
||||
scale_a = right.getScaleMultiplier();
|
||||
OpImpl::constant_vector(col_left->template getValue<T0>(), col_right->getData(), vec_res, scale_a, scale_b);
|
||||
if (decimalCheckArithmeticOverflow(context))
|
||||
OpImpl::constant_vector(col_left->template getValue<T0>(), col_right->getData(), vec_res, scale_a, scale_b);
|
||||
else
|
||||
OpImpl::XOverflow::constant_vector(
|
||||
col_left->template getValue<T0>(), col_right->getData(), vec_res, scale_a, scale_b);
|
||||
}
|
||||
else
|
||||
OpImpl::constant_vector(col_left->template getValue<T0>(), col_right->getData(), vec_res);
|
||||
@ -1247,9 +1282,20 @@ public:
|
||||
if constexpr (IsDecimal<RightDataType> && is_division)
|
||||
scale_a = right.getScaleMultiplier();
|
||||
if (auto col_right = checkAndGetColumn<ColVecT1>(col_right_raw))
|
||||
OpImpl::vector_vector(col_left->getData(), col_right->getData(), vec_res, scale_a, scale_b);
|
||||
{
|
||||
if (decimalCheckArithmeticOverflow(context))
|
||||
OpImpl::vector_vector(col_left->getData(), col_right->getData(), vec_res, scale_a, scale_b);
|
||||
else
|
||||
OpImpl::XOverflow::vector_vector(col_left->getData(), col_right->getData(), vec_res, scale_a, scale_b);
|
||||
}
|
||||
else if (auto col_right = checkAndGetColumnConst<ColVecT1>(col_right_raw))
|
||||
OpImpl::vector_constant(col_left->getData(), col_right->template getValue<T1>(), vec_res, scale_a, scale_b);
|
||||
{
|
||||
if (decimalCheckArithmeticOverflow(context))
|
||||
OpImpl::vector_constant(col_left->getData(), col_right->template getValue<T1>(), vec_res, scale_a, scale_b);
|
||||
else
|
||||
OpImpl::XOverflow::vector_constant(
|
||||
col_left->getData(), col_right->template getValue<T1>(), vec_res, scale_a, scale_b);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -221,7 +221,8 @@ struct DecCompareInt
|
||||
};
|
||||
|
||||
///
|
||||
template <typename A, typename B, template <typename, typename> typename Operation, bool _actual = IsDecimalNumber<A> || IsDecimalNumber<B>>
|
||||
template <typename A, typename B, template <typename, typename> typename Operation, bool _check_overflow = true,
|
||||
bool _actual = IsDecimalNumber<A> || IsDecimalNumber<B>>
|
||||
class DecimalComparison
|
||||
{
|
||||
public:
|
||||
@ -404,24 +405,35 @@ private:
|
||||
{
|
||||
CompareInt x = a;
|
||||
CompareInt y = b;
|
||||
bool overflow = false;
|
||||
|
||||
if constexpr (sizeof(A) > sizeof(CompareInt))
|
||||
overflow |= (A(x) != a);
|
||||
if constexpr (sizeof(B) > sizeof(CompareInt))
|
||||
overflow |= (B(y) != b);
|
||||
if constexpr (std::is_unsigned_v<A>)
|
||||
overflow |= (x < 0);
|
||||
if constexpr (std::is_unsigned_v<B>)
|
||||
overflow |= (y < 0);
|
||||
if constexpr (_check_overflow)
|
||||
{
|
||||
bool overflow = false;
|
||||
|
||||
if constexpr (scale_left)
|
||||
overflow |= common::mulOverflow(x, scale, x);
|
||||
if constexpr (scale_right)
|
||||
overflow |= common::mulOverflow(y, scale, y);
|
||||
if constexpr (sizeof(A) > sizeof(CompareInt))
|
||||
overflow |= (A(x) != a);
|
||||
if constexpr (sizeof(B) > sizeof(CompareInt))
|
||||
overflow |= (B(y) != b);
|
||||
if constexpr (std::is_unsigned_v<A>)
|
||||
overflow |= (x < 0);
|
||||
if constexpr (std::is_unsigned_v<B>)
|
||||
overflow |= (y < 0);
|
||||
|
||||
if (overflow)
|
||||
throw Exception("Can't compare", ErrorCodes::DECIMAL_OVERFLOW);
|
||||
if constexpr (scale_left)
|
||||
overflow |= common::mulOverflow(x, scale, x);
|
||||
if constexpr (scale_right)
|
||||
overflow |= common::mulOverflow(y, scale, y);
|
||||
|
||||
if (overflow)
|
||||
throw Exception("Can't compare", ErrorCodes::DECIMAL_OVERFLOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (scale_left)
|
||||
x *= scale;
|
||||
if constexpr (scale_right)
|
||||
y *= scale;
|
||||
}
|
||||
|
||||
return Op::apply(x, y);
|
||||
}
|
||||
@ -1030,7 +1042,10 @@ private:
|
||||
using LeftDataType = typename Types::LeftType;
|
||||
using RightDataType = typename Types::RightType;
|
||||
|
||||
DecimalComparison<LeftDataType, RightDataType, Op>(block, result, col_left, col_right);
|
||||
if (decimalCheckComparisonOverflow(context))
|
||||
DecimalComparison<LeftDataType, RightDataType, Op, true>(block, result, col_left, col_right);
|
||||
else
|
||||
DecimalComparison<LeftDataType, RightDataType, Op, false>(block, result, col_left, col_right);
|
||||
return true;
|
||||
};
|
||||
|
||||
|
@ -278,6 +278,8 @@ struct Settings
|
||||
M(SettingBool, low_cardinality_use_single_dictionary_for_part, false, "LowCardinality type serialization setting. If is true, than will use additional keys when global dictionary overflows. Otherwise, will create several shared dictionaries.") \
|
||||
M(SettingBool, allow_experimental_low_cardinality_type, false, "Allows to create table with LowCardinality types.") \
|
||||
M(SettingBool, allow_experimental_decimal_type, false, "Enables Decimal data type.") \
|
||||
M(SettingBool, decimal_check_comparison_overflow, true, "Check overflow of decimal comparison operations") \
|
||||
M(SettingBool, decimal_check_arithmetic_overflow, true, "Check overflow of decimal arithmetic operations") \
|
||||
\
|
||||
M(SettingBool, prefer_localhost_replica, 1, "1 - always send query to local replica, if it exists. 0 - choose replica to send query between local and remote ones according to load_balancing") \
|
||||
M(SettingUInt64, max_fetch_partition_retries_count, 5, "Amount of retries while fetching partition from another host.") \
|
||||
|
@ -2,6 +2,8 @@
|
||||
84 0 1764 1
|
||||
84 0 1764 1
|
||||
84.840 0.000 1799.456400 1.000
|
||||
84.840000000 0.000000000
|
||||
84.840000000000000000 0.000000000000000000
|
||||
84.84 0.00 1799.4564 1.00
|
||||
63 21 -42 882 -882 2 0
|
||||
63 21 -42 882 -882 2 0
|
||||
@ -23,3 +25,7 @@
|
||||
42 42 42 0.420000000 0.420000000000000000 0.42000000000000000000000000000000000000 42.420 42.420000000 42.42
|
||||
0 0 0 0.000000000 0.000000000000000000 0.00000000000000000000000000000000000000 0.000 0.000000000 0.00
|
||||
42 42 42 0.420000000 0.420000000000000000 0.42000000000000000000000000000000000000 42.420 42.420000000 42.42
|
||||
1 1
|
||||
1 1
|
||||
1 0 1 0
|
||||
1 0 1 0
|
||||
|
@ -29,7 +29,9 @@ SELECT e + e, e - e, e * e, e / e FROM test.decimal WHERE e > 0; -- { serverErro
|
||||
SELECT f + f, f - f, f * f, f / f FROM test.decimal WHERE f > 0; -- { serverError 69 }
|
||||
SELECT g + g, g - g, g * g, g / g FROM test.decimal WHERE g > 0;
|
||||
SELECT h + h, h - h, h * h, h / h FROM test.decimal WHERE h > 0; -- { serverError 407 }
|
||||
SELECT h + h, h - h FROM test.decimal WHERE h > 0;
|
||||
SELECT i + i, i - i, i * i, i / i FROM test.decimal WHERE i > 0; -- { serverError 407 }
|
||||
SELECT i + i, i - i FROM test.decimal WHERE i > 0;
|
||||
SELECT j + j, j - j, j * j, j / j FROM test.decimal WHERE j > 0;
|
||||
|
||||
SELECT a + 21, a - 21, a - 84, a * 21, a * -21, a / 21, a / 84 FROM test.decimal WHERE a = 42;
|
||||
@ -48,11 +50,20 @@ SELECT 21 + c, 21 - c, 84 - c, 21 * c, -21 * c, 21 / c, 84 / c FROM test.decimal
|
||||
SELECT 21 + e, 21 - e, 84 - e, 21 * e, -21 * e, 21 / e, 84 / e FROM test.decimal WHERE e > 0; -- { serverError 407 }
|
||||
SELECT 21 + f, 21 - f, 84 - f, 21 * f, -21 * f, 21 / f, 84 / f FROM test.decimal WHERE f > 0; -- { serverError 407 }
|
||||
SELECT 21 + g, 21 - g, 84 - g, 21 * g, -21 * g, 21 / g, 84 / g FROM test.decimal WHERE g > 0;
|
||||
SELECT 21 + h, 21 - h, 84 - h, 21 * h, -21 * h FROM test.decimal WHERE h > 0; --overflow 21 / h, 84 / h
|
||||
SELECT 21 + h, 21 - h, 84 - h, 21 * h, -21 * h, 21 / h, 84 / h FROM test.decimal WHERE h > 0; -- { serverError 407 }
|
||||
SELECT 21 + h, 21 - h, 84 - h, 21 * h, -21 * h FROM test.decimal WHERE h > 0;
|
||||
SELECT 21 + i, 21 - i, 84 - i, 21 * i, -21 * i, 21 / i, 84 / i FROM test.decimal WHERE i > 0;
|
||||
SELECT 21 + j, 21 - j, 84 - j, 21 * j, -21 * j, 21 / j, 84 / j FROM test.decimal WHERE j > 0;
|
||||
|
||||
SELECT a, -a, -b, -c, -d, -e, -f, -g, -h, -j from test.decimal ORDER BY a;
|
||||
SELECT abs(a), abs(b), abs(c), abs(d), abs(e), abs(f), abs(g), abs(h), abs(j) from test.decimal ORDER BY a;
|
||||
|
||||
SET decimal_check_arithmetic_overflow = 0;
|
||||
|
||||
SELECT (h * h) != 0, (h / h) != 1 FROM test.decimal WHERE h > 0;
|
||||
SELECT (i * i) != 0, (i / i) = 1 FROM test.decimal WHERE i > 0;
|
||||
|
||||
SELECT e + 1 > e, e + 10 > e, 1 + e > e, 10 + e > e FROM test.decimal WHERE e > 0;
|
||||
SELECT f + 1 > f, f + 10 > f, 1 + f > f, 10 + f > f FROM test.decimal WHERE f > 0;
|
||||
|
||||
DROP TABLE IF EXISTS test.decimal;
|
||||
|
Loading…
Reference in New Issue
Block a user