This commit is contained in:
yariks5s 2024-01-25 21:44:46 +00:00
parent a69a0aea0e
commit 36055bd008
4 changed files with 196 additions and 20 deletions

View File

@ -146,10 +146,24 @@ private: /// it's not correct for Decimal
public:
static constexpr bool allow_decimal = IsOperation<Operation>::allow_decimal;
static constexpr bool only_integer = IsOperation<Operation>::div_int || IsOperation<Operation>::div_int_or_zero;
/// Appropriate result type for binary operator on numeric types. "Date" can also mean
/// DateTime, but if both operands are Dates, their type must be the same (e.g. Date - DateTime is invalid).
using ResultDataType = Switch<
/// Result must be Integer
Case<
only_integer && IsDataTypeDecimal<LeftDataType> && IsDataTypeDecimal<RightDataType>,
Switch<
Case<std::is_same_v<LeftDataType, DataTypeDecimal256> || std::is_same_v<RightDataType, DataTypeDecimal256>, DataTypeInt256>,
Case<std::is_same_v<LeftDataType, DataTypeDecimal128> || std::is_same_v<RightDataType, DataTypeDecimal128>, DataTypeInt128>,
Case<std::is_same_v<LeftDataType, DataTypeDecimal64> || std::is_same_v<RightDataType, DataTypeDecimal64>, DataTypeInt64>,
Case<std::is_same_v<LeftDataType, DataTypeDecimal32> || std::is_same_v<RightDataType, DataTypeDecimal32>, DataTypeInt32>>>,
Case<
only_integer,
Switch<
Case<IsIntegral<LeftDataType>, LeftDataType>,
Case<IsIntegral<RightDataType>, RightDataType>>>,
/// Decimal cases
Case<!allow_decimal && (IsDataTypeDecimal<LeftDataType> || IsDataTypeDecimal<RightDataType>), InvalidType>,
Case<
@ -1667,31 +1681,77 @@ public:
{
if constexpr (IsDataTypeDecimal<LeftDataType> && IsDataTypeDecimal<RightDataType>)
{
if constexpr (is_division)
if constexpr (is_div_int || is_div_int_or_zero)
{
if (context->getSettingsRef().decimal_check_overflow)
{
/// Check overflow by using operands scale (based on big decimal division implementation details):
/// big decimal arithmetic is based on big integers, decimal operands are converted to big integers
/// i.e. int_operand = decimal_operand*10^scale
/// For division, left operand will be scaled by right operand scale also to do big integer division,
/// BigInt result = left*10^(left_scale + right_scale) / right * 10^right_scale
/// So, we can check upfront possible overflow just by checking max scale used for left operand
/// Note: it doesn't detect all possible overflow during big decimal division
if (left.getScale() + right.getScale() > ResultDataType::maxPrecision())
throw Exception(ErrorCodes::DECIMAL_OVERFLOW, "Overflow during decimal division");
}
if constexpr (std::is_same_v<LeftDataType, DataTypeDecimal256> || std::is_same_v<RightDataType, DataTypeDecimal256>)
type_res = std::make_shared<DataTypeInt256>();
else if constexpr (std::is_same_v<LeftDataType, DataTypeDecimal128> || std::is_same_v<RightDataType, DataTypeDecimal128>)
type_res = std::make_shared<DataTypeInt128>();
else if constexpr (std::is_same_v<LeftDataType, DataTypeDecimal64> || std::is_same_v<RightDataType, DataTypeDecimal64>)
type_res = std::make_shared<DataTypeInt64>();
else
type_res = std::make_shared<DataTypeInt32>();
}
else
{
if constexpr (is_division)
{
if (context->getSettingsRef().decimal_check_overflow)
{
/// Check overflow by using operands scale (based on big decimal division implementation details):
/// big decimal arithmetic is based on big integers, decimal operands are converted to big integers
/// i.e. int_operand = decimal_operand*10^scale
/// For division, left operand will be scaled by right operand scale also to do big integer division,
/// BigInt result = left*10^(left_scale + right_scale) / right * 10^right_scale
/// So, we can check upfront possible overflow just by checking max scale used for left operand
/// Note: it doesn't detect all possible overflow during big decimal division
if (left.getScale() + right.getScale() > ResultDataType::maxPrecision())
throw Exception(ErrorCodes::DECIMAL_OVERFLOW, "Overflow during decimal division");
}
}
ResultDataType result_type = decimalResultType<is_multiply, is_division>(left, right);
type_res = std::make_shared<ResultDataType>(result_type.getPrecision(), result_type.getScale());
}
ResultDataType result_type = decimalResultType<is_multiply, is_division>(left, right);
type_res = std::make_shared<ResultDataType>(result_type.getPrecision(), result_type.getScale());
}
else if constexpr ((IsDataTypeDecimal<LeftDataType> && IsFloatingPoint<RightDataType>) ||
(IsDataTypeDecimal<RightDataType> && IsFloatingPoint<LeftDataType>))
type_res = std::make_shared<DataTypeFloat64>();
else if constexpr (IsDataTypeDecimal<LeftDataType>)
type_res = std::make_shared<LeftDataType>(left.getPrecision(), left.getScale());
{
if constexpr ((is_div_int || is_div_int_or_zero) && IsIntegral<RightDataType>)
type_res = std::make_shared<RightDataType>();
else if constexpr (is_div_int || is_div_int_or_zero)
{
if constexpr (std::is_same_v<LeftDataType, DataTypeDecimal256>)
type_res = std::make_shared<DataTypeInt256>();
else if constexpr (std::is_same_v<LeftDataType, DataTypeDecimal128>)
type_res = std::make_shared<DataTypeInt128>();
else if constexpr (std::is_same_v<LeftDataType, DataTypeDecimal64>)
type_res = std::make_shared<DataTypeInt64>();
else
type_res = std::make_shared<DataTypeInt32>();
}
else
type_res = std::make_shared<LeftDataType>(left.getPrecision(), left.getScale());
}
else if constexpr (IsDataTypeDecimal<RightDataType>)
type_res = std::make_shared<RightDataType>(right.getPrecision(), right.getScale());
{
if constexpr ((is_div_int || is_div_int_or_zero) && IsIntegral<LeftDataType>)
type_res = std::make_shared<LeftDataType>();
else if constexpr (is_div_int || is_div_int_or_zero)
{
if constexpr (std::is_same_v<RightDataType, DataTypeDecimal256>)
type_res = std::make_shared<DataTypeInt256>();
else if constexpr (std::is_same_v<RightDataType, DataTypeDecimal128>)
type_res = std::make_shared<DataTypeInt128>();
else if constexpr (std::is_same_v<RightDataType, DataTypeDecimal64>)
type_res = std::make_shared<DataTypeInt64>();
else
type_res = std::make_shared<DataTypeInt32>();
}
else
type_res = std::make_shared<RightDataType>(right.getPrecision(), right.getScale());
}
else if constexpr (std::is_same_v<ResultDataType, DataTypeDateTime>)
{
// Special case for DateTime: binary OPS should reuse timezone
@ -2009,8 +2069,10 @@ ColumnPtr executeStringInteger(const ColumnsWithTypeAndName & arguments, const A
constexpr bool decimal_with_float = (IsDataTypeDecimal<LeftDataType> && IsFloatingPoint<RightDataType>)
|| (IsFloatingPoint<LeftDataType> && IsDataTypeDecimal<RightDataType>);
using T0 = std::conditional_t<decimal_with_float, Float64, typename LeftDataType::FieldType>;
using T1 = std::conditional_t<decimal_with_float, Float64, typename RightDataType::FieldType>;
constexpr bool is_div_int_with_decimal = (is_div_int || is_div_int_or_zero) && (IsDataTypeDecimal<LeftDataType> || IsDataTypeDecimal<RightDataType>);
using T0 = std::conditional_t<decimal_with_float, Float64, std::conditional_t<is_div_int_with_decimal, Int64, typename LeftDataType::FieldType>>;
using T1 = std::conditional_t<decimal_with_float, Float64, std::conditional_t<is_div_int_with_decimal, Int64, typename RightDataType::FieldType>>;
using ResultType = typename ResultDataType::FieldType;
using ColVecT0 = ColumnVectorOrDecimal<T0>;
using ColVecT1 = ColumnVectorOrDecimal<T1>;
@ -2026,6 +2088,12 @@ ColumnPtr executeStringInteger(const ColumnsWithTypeAndName & arguments, const A
left_col = castColumn(arguments[0], converted_type);
right_col = castColumn(arguments[1], converted_type);
}
else if constexpr (is_div_int_with_decimal)
{
const auto converted_type = std::make_shared<DataTypeInt64>();
left_col = castColumn(arguments[0], converted_type);
right_col = castColumn(arguments[1], converted_type);
}
else
{
left_col = arguments[0].column;

View File

@ -62,7 +62,9 @@ struct IsOperation
static constexpr bool division = div_floating || div_int || div_int_or_zero || modulo;
static constexpr bool allow_decimal = plus || minus || multiply || division || least || greatest;
static constexpr bool division_allow_decimal = div_floating || modulo;
static constexpr bool allow_decimal = plus || minus || multiply || division_allow_decimal || least || greatest;
};
}

View File

@ -0,0 +1,52 @@
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2

View File

@ -0,0 +1,54 @@
--intDiv--
SELECT intDiv(4,2);
SELECT intDiv(toDecimal32(4.4, 2), 2);
SELECT intDiv(4, toDecimal32(2.2, 2));
SELECT intDiv(toDecimal32(4.4, 2), 2);
SELECT intDiv(toDecimal32(4.4, 2), toDecimal32(2.2, 2));
SELECT intDiv(toDecimal64(4.4, 3), 2);
SELECT intDiv(toDecimal64(4.4, 3), toDecimal32(2.2, 2));
SELECT intDiv(toDecimal128(4.4, 4), 2);
SELECT intDiv(toDecimal128(4.4, 4), toDecimal32(2.2, 2));
SELECT intDiv(toDecimal256(4.4, 5), 2);
SELECT intDiv(toDecimal256(4.4, 5), toDecimal32(2.2, 2));
SELECT intDiv(4, toDecimal64(2.2, 2));
SELECT intDiv(toDecimal32(4.4, 2), toDecimal64(2.2, 2));
SELECT intDiv(4, toDecimal128(2.2, 3));
SELECT intDiv(toDecimal32(4.4, 2), toDecimal128(2.2, 3));
SELECT intDiv(4, toDecimal256(2.2, 4));
SELECT intDiv(toDecimal32(4.4, 2), toDecimal256(2.2, 4));
SELECT intDiv(toDecimal64(4.4, 2), toDecimal64(2.2, 2));
SELECT intDiv(toDecimal128(4.4, 2), toDecimal64(2.2, 2));
SELECT intDiv(toDecimal256(4.4, 2), toDecimal64(2.2, 2));
SELECT intDiv(toDecimal64(4.4, 2), toDecimal128(2.2, 2));
SELECT intDiv(toDecimal128(4.4, 2), toDecimal128(2.2, 2));
SELECT intDiv(toDecimal256(4.4, 2), toDecimal128(2.2, 2));
SELECT intDiv(toDecimal64(4.4, 2), toDecimal256(2.2, 2));
SELECT intDiv(toDecimal128(4.4, 2), toDecimal256(2.2, 2));
SELECT intDiv(toDecimal256(4.4, 2), toDecimal256(2.2, 2));
--intDivOrZero--
SELECT intDivOrZero(4,2);
SELECT intDivOrZero(toDecimal32(4.4, 2), 2);
SELECT intDivOrZero(4, toDecimal32(2.2, 2));
SELECT intDivOrZero(toDecimal32(4.4, 2), 2);
SELECT intDivOrZero(toDecimal32(4.4, 2), toDecimal32(2.2, 2));
SELECT intDivOrZero(toDecimal64(4.4, 3), 2);
SELECT intDivOrZero(toDecimal64(4.4, 3), toDecimal32(2.2, 2));
SELECT intDivOrZero(toDecimal128(4.4, 4), 2);
SELECT intDivOrZero(toDecimal128(4.4, 4), toDecimal32(2.2, 2));
SELECT intDivOrZero(toDecimal256(4.4, 5), 2);
SELECT intDivOrZero(toDecimal256(4.4, 5), toDecimal32(2.2, 2));
SELECT intDivOrZero(4, toDecimal64(2.2, 2));
SELECT intDivOrZero(toDecimal32(4.4, 2), toDecimal64(2.2, 2));
SELECT intDivOrZero(4, toDecimal128(2.2, 3));
SELECT intDivOrZero(toDecimal32(4.4, 2), toDecimal128(2.2, 3));
SELECT intDivOrZero(4, toDecimal256(2.2, 4));
SELECT intDivOrZero(toDecimal32(4.4, 2), toDecimal256(2.2, 4));
SELECT intDivOrZero(toDecimal64(4.4, 2), toDecimal64(2.2, 2));
SELECT intDivOrZero(toDecimal128(4.4, 2), toDecimal64(2.2, 2));
SELECT intDivOrZero(toDecimal256(4.4, 2), toDecimal64(2.2, 2));
SELECT intDivOrZero(toDecimal64(4.4, 2), toDecimal128(2.2, 2));
SELECT intDivOrZero(toDecimal128(4.4, 2), toDecimal128(2.2, 2));
SELECT intDivOrZero(toDecimal256(4.4, 2), toDecimal128(2.2, 2));
SELECT intDivOrZero(toDecimal64(4.4, 2), toDecimal256(2.2, 2));
SELECT intDivOrZero(toDecimal128(4.4, 2), toDecimal256(2.2, 2));
SELECT intDivOrZero(toDecimal256(4.4, 2), toDecimal256(2.2, 2));