diff --git a/dbms/src/DataTypes/DataTypesDecimal.h b/dbms/src/DataTypes/DataTypesDecimal.h index 6fff08ca4d9..454b069fe40 100644 --- a/dbms/src/DataTypes/DataTypesDecimal.h +++ b/dbms/src/DataTypes/DataTypesDecimal.h @@ -260,13 +260,13 @@ inline UInt32 getDecimalScale(const IDataType & data_type) /// -template constexpr bool IsDecimal = false; -template <> constexpr bool IsDecimal> = true; -template <> constexpr bool IsDecimal> = true; -template <> constexpr bool IsDecimal> = true; +template constexpr bool IsDataTypeDecimal = false; +template <> constexpr bool IsDataTypeDecimal> = true; +template <> constexpr bool IsDataTypeDecimal> = true; +template <> constexpr bool IsDataTypeDecimal> = true; template -inline std::enable_if_t && IsDecimal, typename ToDataType::FieldType> +inline std::enable_if_t && IsDataTypeDecimal, typename ToDataType::FieldType> convertDecimals(const typename FromDataType::FieldType & value, UInt32 scale_from, UInt32 scale_to) { ToDataType type_to(ToDataType::maxPrecision(), scale_to); @@ -285,7 +285,7 @@ convertDecimals(const typename FromDataType::FieldType & value, UInt32 scale_fro } template -inline std::enable_if_t && !IsDecimal, typename ToDataType::FieldType> +inline std::enable_if_t && !IsDataTypeDecimal, typename ToDataType::FieldType> convertFromDecimal(const typename FromDataType::FieldType & value, UInt32 scale [[maybe_unused]]) { if (scale > FromDataType::maxPrecision()) @@ -298,7 +298,7 @@ convertFromDecimal(const typename FromDataType::FieldType & value, UInt32 scale } template -inline std::enable_if_t && IsDecimal, typename ToDataType::FieldType> +inline std::enable_if_t && IsDataTypeDecimal, typename ToDataType::FieldType> convertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale [[maybe_unused]]) { if (scale > ToDataType::maxPrecision()) diff --git a/dbms/src/DataTypes/DataTypesNumber.h b/dbms/src/DataTypes/DataTypesNumber.h index 9c6fcf02fbe..6ce1cbc0d24 100644 --- a/dbms/src/DataTypes/DataTypesNumber.h +++ b/dbms/src/DataTypes/DataTypesNumber.h @@ -30,4 +30,16 @@ using DataTypeInt64 = DataTypeNumber; using DataTypeFloat32 = DataTypeNumber; using DataTypeFloat64 = DataTypeNumber; +template constexpr bool IsDataTypeNumber = false; +template <> constexpr bool IsDataTypeNumber> = true; +template <> constexpr bool IsDataTypeNumber> = true; +template <> constexpr bool IsDataTypeNumber> = true; +template <> constexpr bool IsDataTypeNumber> = true; +template <> constexpr bool IsDataTypeNumber> = true; +template <> constexpr bool IsDataTypeNumber> = true; +template <> constexpr bool IsDataTypeNumber> = true; +template <> constexpr bool IsDataTypeNumber> = true; +template <> constexpr bool IsDataTypeNumber> = true; +template <> constexpr bool IsDataTypeNumber> = true; + } diff --git a/dbms/src/Functions/FunctionsArithmetic.h b/dbms/src/Functions/FunctionsArithmetic.h index d8d27e5ce23..7855b178f5a 100644 --- a/dbms/src/Functions/FunctionsArithmetic.h +++ b/dbms/src/Functions/FunctionsArithmetic.h @@ -1020,14 +1020,14 @@ public: /// DateTime, but if both operands are Dates, their type must be the same (e.g. Date - DateTime is invalid). using ResultDataType = Switch< /// Decimal cases - Case || IsDecimal), InvalidType>, - Case && IsDecimal && UseLeftDecimal, LeftDataType>, - Case && IsDecimal, RightDataType>, - Case && !IsDecimal && IsIntegral, LeftDataType>, - Case && IsDecimal && IsIntegral, RightDataType>, + Case || IsDataTypeDecimal), InvalidType>, + Case && IsDataTypeDecimal && UseLeftDecimal, LeftDataType>, + Case && IsDataTypeDecimal, RightDataType>, + Case && !IsDataTypeDecimal && IsIntegral, LeftDataType>, + Case && IsDataTypeDecimal && IsIntegral, RightDataType>, /// Decimal Real is not supported (traditional DBs convert Decimal Real to Real) - Case && !IsDecimal && !IsIntegral, InvalidType>, - Case && IsDecimal && !IsIntegral, InvalidType>, + Case && !IsDataTypeDecimal && !IsIntegral, InvalidType>, + Case && IsDataTypeDecimal && !IsIntegral, InvalidType>, /// number number -> see corresponding impl Case && !IsDateOrDateTime, DataTypeFromFieldType>, @@ -1311,16 +1311,16 @@ public: using ResultDataType = typename BinaryOperationTraits::ResultDataType; if constexpr (!std::is_same_v) { - if constexpr (IsDecimal && IsDecimal) + if constexpr (IsDataTypeDecimal && IsDataTypeDecimal) { constexpr bool is_multiply = std::is_same_v, MultiplyImpl>; constexpr bool is_division = std::is_same_v, DivideFloatingImpl>; ResultDataType result_type = decimalResultType(left, right, is_multiply, is_division); type_res = std::make_shared(result_type.getPrecision(), result_type.getScale()); } - else if constexpr (IsDecimal) + else if constexpr (IsDataTypeDecimal) type_res = std::make_shared(left.getPrecision(), left.getScale()); - else if constexpr (IsDecimal) + else if constexpr (IsDataTypeDecimal) type_res = std::make_shared(right.getPrecision(), right.getScale()); else type_res = std::make_shared(); @@ -1366,7 +1366,7 @@ public: using ResultDataType = typename BinaryOperationTraits::ResultDataType; if constexpr (!std::is_same_v) { - constexpr bool result_is_decimal = IsDecimal || IsDecimal; + constexpr bool result_is_decimal = IsDataTypeDecimal || IsDataTypeDecimal; constexpr bool is_multiply = std::is_same_v, MultiplyImpl>; constexpr bool is_division = std::is_same_v, DivideFloatingImpl>; @@ -1378,7 +1378,7 @@ public: using ColVecResult = std::conditional_t, ColumnDecimal, ColumnVector>; /// Decimal operations need scale. Operations are on result type. - using OpImpl = std::conditional_t, + using OpImpl = std::conditional_t, DecimalBinaryOperation, BinaryOperationImpl, ResultType>>; @@ -1394,7 +1394,7 @@ public: ResultDataType type = decimalResultType(left, right, is_multiply, is_division); typename ResultDataType::FieldType scale_a = type.scaleFactorFor(left, is_multiply); typename ResultDataType::FieldType scale_b = type.scaleFactorFor(right, is_multiply || is_division); - if constexpr (IsDecimal && is_division) + if constexpr (IsDataTypeDecimal && is_division) scale_a = right.getScaleMultiplier(); auto res = OpImpl::constant_constant(col_left->template getValue(), col_right->template getValue(), @@ -1435,7 +1435,7 @@ public: typename ResultDataType::FieldType scale_a = type.scaleFactorFor(left, is_multiply); typename ResultDataType::FieldType scale_b = type.scaleFactorFor(right, is_multiply || is_division); - if constexpr (IsDecimal && is_division) + if constexpr (IsDataTypeDecimal && is_division) scale_a = right.getScaleMultiplier(); OpImpl::constant_vector(col_left_const->template getValue(), col_right->getData(), vec_res, @@ -1455,7 +1455,7 @@ public: typename ResultDataType::FieldType scale_a = type.scaleFactorFor(left, is_multiply); typename ResultDataType::FieldType scale_b = type.scaleFactorFor(right, is_multiply || is_division); - if constexpr (IsDecimal && is_division) + if constexpr (IsDataTypeDecimal && is_division) scale_a = right.getScaleMultiplier(); if (auto col_right = checkAndGetColumn(col_right_raw)) { @@ -1501,7 +1501,7 @@ public: using RightDataType = std::decay_t; using ResultDataType = typename BinaryOperationTraits::ResultDataType; using OpSpec = Op; - return !std::is_same_v && !IsDecimal && OpSpec::compilable; + return !std::is_same_v && !IsDataTypeDecimal && OpSpec::compilable; }); } @@ -1514,7 +1514,7 @@ public: using RightDataType = std::decay_t; using ResultDataType = typename BinaryOperationTraits::ResultDataType; using OpSpec = Op; - if constexpr (!std::is_same_v && !IsDecimal && OpSpec::compilable) + if constexpr (!std::is_same_v && !IsDataTypeDecimal && OpSpec::compilable) { auto & b = static_cast &>(builder); auto type = std::make_shared(); @@ -1584,7 +1584,7 @@ public: using DataType = std::decay_t; using T0 = typename DataType::FieldType; - if constexpr (IsDecimal) + if constexpr (IsDataTypeDecimal) { if constexpr (!allow_decimal) return false; @@ -1607,7 +1607,7 @@ public: using DataType = std::decay_t; using T0 = typename DataType::FieldType; - if constexpr (IsDecimal) + if constexpr (IsDataTypeDecimal) { if constexpr (allow_decimal) { @@ -1647,7 +1647,7 @@ public: return castType(arguments[0].get(), [&](const auto & type) { using DataType = std::decay_t; - return !IsDecimal && Op::compilable; + return !IsDataTypeDecimal && Op::compilable; }); } @@ -1659,7 +1659,7 @@ public: using DataType = std::decay_t; using T0 = typename DataType::FieldType; using T1 = typename Op::ResultType; - if constexpr (!std::is_same_v && !IsDecimal && Op::compilable) + if constexpr (!std::is_same_v && !IsDecimalDataType && Op::compilable) { auto & b = static_cast &>(builder); auto * v = nativeCast(b, types[0], values[0](), std::make_shared>()); diff --git a/dbms/src/Functions/FunctionsConversion.h b/dbms/src/Functions/FunctionsConversion.h index a8dd3b6d033..a568fc2204a 100644 --- a/dbms/src/Functions/FunctionsConversion.h +++ b/dbms/src/Functions/FunctionsConversion.h @@ -110,7 +110,7 @@ struct ConvertImpl if (const ColVecFrom * col_from = checkAndGetColumn(named_from.column.get())) { typename ColVecTo::MutablePtr col_to = nullptr; - if constexpr (IsDecimal) + if constexpr (IsDataTypeDecimal) { UInt32 scale = additions; col_to = ColVecTo::create(0, scale); @@ -125,11 +125,11 @@ struct ConvertImpl for (size_t i = 0; i < size; ++i) { - if constexpr (IsDecimal && IsDecimal) + if constexpr (IsDataTypeDecimal && IsDataTypeDecimal) vec_to[i] = convertDecimals(vec_from[i], vec_from.getScale(), vec_to.getScale()); - else if constexpr (IsDecimal) + else if constexpr (IsDataTypeDecimal) vec_to[i] = convertFromDecimal(vec_from[i], vec_from.getScale()); - else if constexpr (IsDecimal) + else if constexpr (IsDataTypeDecimal) vec_to[i] = convertToDecimal(vec_from[i], vec_to.getScale()); else vec_to[i] = static_cast(vec_from[i]); @@ -490,7 +490,7 @@ struct ConvertThroughParsing size_t size = input_rows_count; typename ColVecTo::MutablePtr col_to = nullptr; - if constexpr (IsDecimal) + if constexpr (IsDataTypeDecimal) { UInt32 scale = additions; ToDataType check_bounds_in_ctor(ToDataType::maxPrecision(), scale); @@ -533,7 +533,7 @@ struct ConvertThroughParsing ReadBufferFromMemory read_buffer(&(*chars)[current_offset], string_size); - if constexpr (IsDecimal) + if constexpr (IsDataTypeDecimal) { ToDataType::readText(vec_to[i], read_buffer, ToDataType::maxPrecision(), vec_to.getScale()); } @@ -880,7 +880,7 @@ private: using LeftDataType = typename Types::LeftType; using RightDataType = typename Types::RightType; - if constexpr (IsDecimal) + if constexpr (IsDataTypeDecimal) { if (arguments.size() != 2) throw Exception{"Function " + getName() + " expects 2 arguments for Decimal.", diff --git a/dbms/src/Functions/FunctionsRound.h b/dbms/src/Functions/FunctionsRound.h index db724939977..61486414df6 100644 --- a/dbms/src/Functions/FunctionsRound.h +++ b/dbms/src/Functions/FunctionsRound.h @@ -425,7 +425,6 @@ struct IntegerRoundingImpl { private: using Op = IntegerRoundingComputation; - using Data = T; public: template @@ -476,70 +475,103 @@ public: } }; -template -using FunctionRoundingImpl = std::conditional_t, - FloatRoundingImpl, - IntegerRoundingImpl>; + +template +class DecimalRounding +{ + using NativeType= typename T::NativeType; + using Op = IntegerRoundingComputation; + using Container = typename ColumnDecimal::Container; + +public: + static NO_INLINE void apply(const Container & in, Container & out, Int64 scale_arg) + { + scale_arg = in.getScale() - scale_arg; + if (scale_arg > 0) + { + size_t scale = pow(10, scale_arg); + + const NativeType * __restrict p_in = reinterpret_cast(in.data()); + const NativeType * end_in = reinterpret_cast(in.data()) + in.size(); + NativeType * __restrict p_out = reinterpret_cast(out.data()); + + while (p_in < end_in) + { + Op::compute(p_in, scale, p_out); + ++p_in; + ++p_out; + } + } + else + memcpy(out.data(), in.data(), in.size() * sizeof(T)); + } +}; /** Select the appropriate processing algorithm depending on the scale. */ template -struct Dispatcher +class Dispatcher { - static void apply(Block & block, const ColumnVector * col, const ColumnNumbers & arguments, size_t result) + template + using FunctionRoundingImpl = std::conditional_t, + FloatRoundingImpl, + IntegerRoundingImpl>; + + static void apply(Block & block, const ColumnVector * col, Int64 scale_arg, size_t result) { - size_t scale = 1; - Int64 scale_arg = 0; - - if (arguments.size() == 2) - { - const IColumn & scale_column = *block.getByPosition(arguments[1]).column; - if (!scale_column.isColumnConst()) - throw Exception("Scale argument for rounding functions must be constant.", ErrorCodes::ILLEGAL_COLUMN); - - Field scale_field = static_cast(scale_column).getField(); - if (scale_field.getType() != Field::Types::UInt64 - && scale_field.getType() != Field::Types::Int64) - throw Exception("Scale argument for rounding functions must have integer type.", ErrorCodes::ILLEGAL_COLUMN); - - scale_arg = scale_field.get(); - } - auto col_res = ColumnVector::create(); typename ColumnVector::Container & vec_res = col_res->getData(); vec_res.resize(col->getData().size()); - if (vec_res.empty()) + if (!vec_res.empty()) { - block.getByPosition(result).column = std::move(col_res); - return; - } - - if (scale_arg == 0) - { - scale = 1; - FunctionRoundingImpl::apply(col->getData(), scale, vec_res); - } - else if (scale_arg > 0) - { - scale = pow(10, scale_arg); - FunctionRoundingImpl::apply(col->getData(), scale, vec_res); - } - else - { - scale = pow(10, -scale_arg); - FunctionRoundingImpl::apply(col->getData(), scale, vec_res); + if (scale_arg == 0) + { + size_t scale = 1; + FunctionRoundingImpl::apply(col->getData(), scale, vec_res); + } + else if (scale_arg > 0) + { + size_t scale = pow(10, scale_arg); + FunctionRoundingImpl::apply(col->getData(), scale, vec_res); + } + else + { + size_t scale = pow(10, -scale_arg); + FunctionRoundingImpl::apply(col->getData(), scale, vec_res); + } } block.getByPosition(result).column = std::move(col_res); } + + static void apply(Block & block, const ColumnDecimal * col, Int64 scale_arg, size_t result) + { + const typename ColumnDecimal::Container & vec_src = col->getData(); + + auto col_res = ColumnDecimal::create(vec_src.size(), vec_src.getScale()); + auto & vec_res = col_res->getData(); + + if (!vec_res.empty()) + DecimalRounding::apply(col->getData(), vec_res, scale_arg); + + block.getByPosition(result).column = std::move(col_res); + } + +public: + static void apply(Block & block, const IColumn * column, Int64 scale_arg, size_t result) + { + if constexpr (IsNumber) + apply(block, checkAndGetColumn>(column), scale_arg, result); + else if constexpr (IsDecimalNumber) + apply(block, checkAndGetColumn>(column), scale_arg, result); + } }; /** A template for functions that round the value of an input parameter of type - * (U)Int8/16/32/64 or Float32/64, and accept an additional optional - * parameter (default is 0). + * (U)Int8/16/32/64, Float32/64 or Decimal32/64/128, and accept an additional optional parameter (default is 0). */ template class FunctionRounding : public IFunction @@ -548,18 +580,6 @@ public: static constexpr auto name = Name::name; static FunctionPtr create(const Context &) { return std::make_shared(); } -private: - template - bool executeForType(Block & block, const ColumnNumbers & arguments, size_t result) - { - if (auto col = checkAndGetColumn>(block.getByPosition(arguments[0]).column.get())) - { - Dispatcher::apply(block, col, arguments, result); - return true; - } - return false; - } - public: String getName() const override { @@ -578,31 +598,56 @@ public: ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); for (const auto & type : arguments) - if (!isNumber(type)) + if (!isNumber(type) && !isDecimal(type)) throw Exception("Illegal type " + arguments[0]->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); return arguments[0]; } + static Int64 getScaleArg(Block & block, const ColumnNumbers & arguments) + { + if (arguments.size() == 2) + { + const IColumn & scale_column = *block.getByPosition(arguments[1]).column; + if (!scale_column.isColumnConst()) + throw Exception("Scale argument for rounding functions must be constant.", ErrorCodes::ILLEGAL_COLUMN); + + Field scale_field = static_cast(scale_column).getField(); + if (scale_field.getType() != Field::Types::UInt64 + && scale_field.getType() != Field::Types::Int64) + throw Exception("Scale argument for rounding functions must have integer type.", ErrorCodes::ILLEGAL_COLUMN); + + return scale_field.get(); + } + return 0; + } + bool useDefaultImplementationForConstants() const override { return true; } ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; } void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override { - if (!( executeForType(block, arguments, result) - || executeForType(block, arguments, result) - || executeForType(block, arguments, result) - || executeForType(block, arguments, result) - || executeForType(block, arguments, result) - || executeForType(block, arguments, result) - || executeForType(block, arguments, result) - || executeForType(block, arguments, result) - || executeForType(block, arguments, result) - || executeForType(block, arguments, result))) + const ColumnWithTypeAndName & column = block.getByPosition(arguments[0]); + Int64 scale_arg = getScaleArg(block, arguments); + + auto call = [&](const auto & types) -> bool { - throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName() - + " of argument of function " + getName(), + using Types = std::decay_t; + using DataType = typename Types::LeftType; + + if constexpr (IsDataTypeNumber || IsDataTypeDecimal) + { + using FieldType = typename DataType::FieldType; + Dispatcher::apply(block, column.column.get(), scale_arg, result); + return true; + } + return false; + }; + + if (!callOnIndexAndDataType(column.type->getTypeId(), call)) + { + throw Exception("Illegal column " + column.name + " of argument of function " + getName(), ErrorCodes::ILLEGAL_COLUMN); } } diff --git a/dbms/tests/queries/0_stateless/00700_decimal_round.reference b/dbms/tests/queries/0_stateless/00700_decimal_round.reference new file mode 100644 index 00000000000..fc1c48aeed7 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00700_decimal_round.reference @@ -0,0 +1,60 @@ +12345.6789 12346.0000 12345.7000 12345.6800 12345.6790 12345.6789 12345.6789 +12345.6789 12346.0000 12345.7000 12345.6800 12345.6790 12345.6789 12345.6789 +12345.6789 12345.0000 12345.6000 12345.6700 12345.6780 12345.6789 12345.6789 +12345.6789 12345.0000 12345.6000 12345.6700 12345.6780 12345.6789 12345.6789 +-12345.6789 -12346.0000 -12345.7000 -12345.6800 -12345.6790 -12345.6789 -12345.6789 +-12345.6789 -12345.0000 -12345.6000 -12345.6700 -12345.6780 -12345.6789 -12345.6789 +-12345.6789 -12346.0000 -12345.7000 -12345.6800 -12345.6790 -12345.6789 -12345.6789 +-12345.6789 -12345.0000 -12345.6000 -12345.6700 -12345.6780 -12345.6789 -12345.6789 +12345.6789 12350.0000 12300.0000 12000.0000 10000.0000 0.0000 +12345.6789 12350.0000 12400.0000 13000.0000 20000.0000 100000.0000 +12345.6789 12340.0000 12300.0000 12000.0000 10000.0000 0.0000 +12345.6789 12340.0000 12300.0000 12000.0000 10000.0000 0.0000 +-12345.6789 -12350.0000 -12300.0000 -12000.0000 -10000.0000 0.0000 +-12345.6789 -12340.0000 -12300.0000 -12000.0000 -10000.0000 0.0000 +-12345.6789 -12350.0000 -12400.0000 -13000.0000 -20000.0000 -100000.0000 +-12345.6789 -12340.0000 -12300.0000 -12000.0000 -10000.0000 0.0000 +12345.6789 12346.0000 12345.7000 12345.6800 12345.6790 12345.6789 12345.6789 +12345.6789 12346.0000 12345.7000 12345.6800 12345.6790 12345.6789 12345.6789 +12345.6789 12345.0000 12345.6000 12345.6700 12345.6780 12345.6789 12345.6789 +12345.6789 12345.0000 12345.6000 12345.6700 12345.6780 12345.6789 12345.6789 +-12345.6789 -12346.0000 -12345.7000 -12345.6800 -12345.6790 -12345.6789 -12345.6789 +-12345.6789 -12345.0000 -12345.6000 -12345.6700 -12345.6780 -12345.6789 -12345.6789 +-12345.6789 -12346.0000 -12345.7000 -12345.6800 -12345.6790 -12345.6789 -12345.6789 +-12345.6789 -12345.0000 -12345.6000 -12345.6700 -12345.6780 -12345.6789 -12345.6789 +12345.6789 12350.0000 12300.0000 12000.0000 10000.0000 0.0000 +12345.6789 12350.0000 12400.0000 13000.0000 20000.0000 100000.0000 +12345.6789 12340.0000 12300.0000 12000.0000 10000.0000 0.0000 +12345.6789 12340.0000 12300.0000 12000.0000 10000.0000 0.0000 +-12345.6789 -12350.0000 -12300.0000 -12000.0000 -10000.0000 0.0000 +-12345.6789 -12340.0000 -12300.0000 -12000.0000 -10000.0000 0.0000 +-12345.6789 -12350.0000 -12400.0000 -13000.0000 -20000.0000 -100000.0000 +-12345.6789 -12340.0000 -12300.0000 -12000.0000 -10000.0000 0.0000 +12345.6789 12346.0000 12345.7000 12345.6800 12345.6790 12345.6789 12345.6789 +12345.6789 12346.0000 12345.7000 12345.6800 12345.6790 12345.6789 12345.6789 +12345.6789 12345.0000 12345.6000 12345.6700 12345.6780 12345.6789 12345.6789 +12345.6789 12345.0000 12345.6000 12345.6700 12345.6780 12345.6789 12345.6789 +-12345.6789 -12346.0000 -12345.7000 -12345.6800 -12345.6790 -12345.6789 -12345.6789 +-12345.6789 -12345.0000 -12345.6000 -12345.6700 -12345.6780 -12345.6789 -12345.6789 +-12345.6789 -12346.0000 -12345.7000 -12345.6800 -12345.6790 -12345.6789 -12345.6789 +-12345.6789 -12345.0000 -12345.6000 -12345.6700 -12345.6780 -12345.6789 -12345.6789 +12345.6789 12350.0000 12300.0000 12000.0000 10000.0000 0.0000 +12345.6789 12350.0000 12400.0000 13000.0000 20000.0000 100000.0000 +12345.6789 12340.0000 12300.0000 12000.0000 10000.0000 0.0000 +12345.6789 12340.0000 12300.0000 12000.0000 10000.0000 0.0000 +-12345.6789 -12350.0000 -12300.0000 -12000.0000 -10000.0000 0.0000 +-12345.6789 -12340.0000 -12300.0000 -12000.0000 -10000.0000 0.0000 +-12345.6789 -12350.0000 -12400.0000 -13000.0000 -20000.0000 -100000.0000 +-12345.6789 -12340.0000 -12300.0000 -12000.0000 -10000.0000 0.0000 +123456789.123456784 -123456789.123456784 123456789.000000000 -123456789.000000000 123456789.123460000 -123456789.123460000 123500000.000000000 -123500000.000000000 +123456789.123456784 -123456789.123456784 123456790.000000000 -123456789.000000000 123456789.123460000 -123456789.123450000 123500000.000000000 -123400000.000000000 +123456789.123456784 -123456789.123456784 123456789.000000000 -123456790.000000000 123456789.123450000 -123456789.123460000 123400000.000000000 -123500000.000000000 +123456789.123456784 -123456789.123456784 123456789.000000000 -123456789.000000000 123456789.123450000 -123456789.123450000 123400000.000000000 -123400000.000000000 +12345678901234567525491324606.797053952 -12345678901234567525491324606.797053952 12345678901234567525491324607.000000000 -12345678901234567525491324607.000000000 12345678901234567525491324606.797000000 -12345678901234567525491324606.797000000 +12345678901234567525491324606.797053952 -12345678901234567525491324606.797053952 12345678901234567525491324607.000000000 -12345678901234567525491324606.000000000 12345678901234567525491324606.798000000 -12345678901234567525491324606.797000000 +12345678901234567525491324606.797053952 -12345678901234567525491324606.797053952 12345678901234567525491324606.000000000 -12345678901234567525491324607.000000000 12345678901234567525491324606.797000000 -12345678901234567525491324606.798000000 +12345678901234567525491324606.797053952 -12345678901234567525491324606.797053952 12345678901234567525491324606.000000000 -12345678901234567525491324606.000000000 12345678901234567525491324606.797000000 -12345678901234567525491324606.797000000 +12345678901234567525491324606.797053952 -12345678901234567525491324606.797053952 12345678901234567525491324607.000000000 -12345678901234567525491324607.000000000 12345678901234567525491325000.000000000 -12345678901234567525491325000.000000000 +12345678901234567525491324606.797053952 -12345678901234567525491324606.797053952 12345678901234567525491324607.000000000 -12345678901234567525491324606.000000000 12345678901234567525491325000.000000000 -12345678901234567525491324000.000000000 +12345678901234567525491324606.797053952 -12345678901234567525491324606.797053952 12345678901234567525491324606.000000000 -12345678901234567525491324607.000000000 12345678901234567525491324000.000000000 -12345678901234567525491325000.000000000 +12345678901234567525491324606.797053952 -12345678901234567525491324606.797053952 12345678901234567525491324606.000000000 -12345678901234567525491324606.000000000 12345678901234567525491324000.000000000 -12345678901234567525491324000.000000000 diff --git a/dbms/tests/queries/0_stateless/00700_decimal_round.sql b/dbms/tests/queries/0_stateless/00700_decimal_round.sql new file mode 100644 index 00000000000..9deba592dfc --- /dev/null +++ b/dbms/tests/queries/0_stateless/00700_decimal_round.sql @@ -0,0 +1,65 @@ +SELECT toDecimal32(12345.6789, 4) AS x, round(x), round(x, 1), round(x, 2), round(x, 3), round(x, 4), round(x, 5); +SELECT toDecimal32(12345.6789, 4) AS x, ceil(x), ceil(x, 1), ceil(x, 2), ceil(x, 3), ceil(x, 4), ceil(x, 5); +SELECT toDecimal32(12345.6789, 4) AS x, floor(x), floor(x, 1), floor(x, 2), floor(x, 3), floor(x, 4), floor(x, 5); +SELECT toDecimal32(12345.6789, 4) AS x, trunc(x), trunc(x, 1), trunc(x, 2), trunc(x, 3), trunc(x, 4), trunc(x, 5); +SELECT toDecimal32(-12345.6789, 4) AS x, round(x), round(x, 1), round(x, 2), round(x, 3), round(x, 4), round(x, 5); +SELECT toDecimal32(-12345.6789, 4) AS x, ceil(x), ceil(x, 1), ceil(x, 2), ceil(x, 3), ceil(x, 4), ceil(x, 5); +SELECT toDecimal32(-12345.6789, 4) AS x, floor(x), floor(x, 1), floor(x, 2), floor(x, 3), floor(x, 4), floor(x, 5); +SELECT toDecimal32(-12345.6789, 4) AS x, trunc(x), trunc(x, 1), trunc(x, 2), trunc(x, 3), trunc(x, 4), trunc(x, 5); +SELECT toDecimal32(12345.6789, 4) AS x, round(x, -1), round(x, -2), round(x, -3), round(x, -4), round(x, -5); +SELECT toDecimal32(12345.6789, 4) AS x, ceil(x, -1), ceil(x, -2), ceil(x, -3), ceil(x, -4), ceil(x, -5); +SELECT toDecimal32(12345.6789, 4) AS x, floor(x, -1), floor(x, -2), floor(x, -3), floor(x, -4), floor(x, -5); +SELECT toDecimal32(12345.6789, 4) AS x, trunc(x, -1), trunc(x, -2), trunc(x, -3), trunc(x, -4), trunc(x, -5); +SELECT toDecimal32(-12345.6789, 4) AS x, round(x, -1), round(x, -2), round(x, -3), round(x, -4), round(x, -5); +SELECT toDecimal32(-12345.6789, 4) AS x, ceil(x, -1), ceil(x, -2), ceil(x, -3), ceil(x, -4), ceil(x, -5); +SELECT toDecimal32(-12345.6789, 4) AS x, floor(x, -1), floor(x, -2), floor(x, -3), floor(x, -4), floor(x, -5); +SELECT toDecimal32(-12345.6789, 4) AS x, trunc(x, -1), trunc(x, -2), trunc(x, -3), trunc(x, -4), trunc(x, -5); + +SELECT toDecimal64(12345.6789, 4) AS x, round(x), round(x, 1), round(x, 2), round(x, 3), round(x, 4), round(x, 5); +SELECT toDecimal64(12345.6789, 4) AS x, ceil(x), ceil(x, 1), ceil(x, 2), ceil(x, 3), ceil(x, 4), ceil(x, 5); +SELECT toDecimal64(12345.6789, 4) AS x, floor(x), floor(x, 1), floor(x, 2), floor(x, 3), floor(x, 4), floor(x, 5); +SELECT toDecimal64(12345.6789, 4) AS x, trunc(x), trunc(x, 1), trunc(x, 2), trunc(x, 3), trunc(x, 4), trunc(x, 5); +SELECT toDecimal64(-12345.6789, 4) AS x, round(x), round(x, 1), round(x, 2), round(x, 3), round(x, 4), round(x, 5); +SELECT toDecimal64(-12345.6789, 4) AS x, ceil(x), ceil(x, 1), ceil(x, 2), ceil(x, 3), ceil(x, 4), ceil(x, 5); +SELECT toDecimal64(-12345.6789, 4) AS x, floor(x), floor(x, 1), floor(x, 2), floor(x, 3), floor(x, 4), floor(x, 5); +SELECT toDecimal64(-12345.6789, 4) AS x, trunc(x), trunc(x, 1), trunc(x, 2), trunc(x, 3), trunc(x, 4), trunc(x, 5); +SELECT toDecimal64(12345.6789, 4) AS x, round(x, -1), round(x, -2), round(x, -3), round(x, -4), round(x, -5); +SELECT toDecimal64(12345.6789, 4) AS x, ceil(x, -1), ceil(x, -2), ceil(x, -3), ceil(x, -4), ceil(x, -5); +SELECT toDecimal64(12345.6789, 4) AS x, floor(x, -1), floor(x, -2), floor(x, -3), floor(x, -4), floor(x, -5); +SELECT toDecimal64(12345.6789, 4) AS x, trunc(x, -1), trunc(x, -2), trunc(x, -3), trunc(x, -4), trunc(x, -5); +SELECT toDecimal64(-12345.6789, 4) AS x, round(x, -1), round(x, -2), round(x, -3), round(x, -4), round(x, -5); +SELECT toDecimal64(-12345.6789, 4) AS x, ceil(x, -1), ceil(x, -2), ceil(x, -3), ceil(x, -4), ceil(x, -5); +SELECT toDecimal64(-12345.6789, 4) AS x, floor(x, -1), floor(x, -2), floor(x, -3), floor(x, -4), floor(x, -5); +SELECT toDecimal64(-12345.6789, 4) AS x, trunc(x, -1), trunc(x, -2), trunc(x, -3), trunc(x, -4), trunc(x, -5); + +SELECT toDecimal128(12345.6789, 4) AS x, round(x), round(x, 1), round(x, 2), round(x, 3), round(x, 4), round(x, 5); +SELECT toDecimal128(12345.6789, 4) AS x, ceil(x), ceil(x, 1), ceil(x, 2), ceil(x, 3), ceil(x, 4), ceil(x, 5); +SELECT toDecimal128(12345.6789, 4) AS x, floor(x), floor(x, 1), floor(x, 2), floor(x, 3), floor(x, 4), floor(x, 5); +SELECT toDecimal128(12345.6789, 4) AS x, trunc(x), trunc(x, 1), trunc(x, 2), trunc(x, 3), trunc(x, 4), trunc(x, 5); +SELECT toDecimal128(-12345.6789, 4) AS x, round(x), round(x, 1), round(x, 2), round(x, 3), round(x, 4), round(x, 5); +SELECT toDecimal128(-12345.6789, 4) AS x, ceil(x), ceil(x, 1), ceil(x, 2), ceil(x, 3), ceil(x, 4), ceil(x, 5); +SELECT toDecimal128(-12345.6789, 4) AS x, floor(x), floor(x, 1), floor(x, 2), floor(x, 3), floor(x, 4), floor(x, 5); +SELECT toDecimal128(-12345.6789, 4) AS x, trunc(x), trunc(x, 1), trunc(x, 2), trunc(x, 3), trunc(x, 4), trunc(x, 5); +SELECT toDecimal128(12345.6789, 4) AS x, round(x, -1), round(x, -2), round(x, -3), round(x, -4), round(x, -5); +SELECT toDecimal128(12345.6789, 4) AS x, ceil(x, -1), ceil(x, -2), ceil(x, -3), ceil(x, -4), ceil(x, -5); +SELECT toDecimal128(12345.6789, 4) AS x, floor(x, -1), floor(x, -2), floor(x, -3), floor(x, -4), floor(x, -5); +SELECT toDecimal128(12345.6789, 4) AS x, trunc(x, -1), trunc(x, -2), trunc(x, -3), trunc(x, -4), trunc(x, -5); +SELECT toDecimal128(-12345.6789, 4) AS x, round(x, -1), round(x, -2), round(x, -3), round(x, -4), round(x, -5); +SELECT toDecimal128(-12345.6789, 4) AS x, ceil(x, -1), ceil(x, -2), ceil(x, -3), ceil(x, -4), ceil(x, -5); +SELECT toDecimal128(-12345.6789, 4) AS x, floor(x, -1), floor(x, -2), floor(x, -3), floor(x, -4), floor(x, -5); +SELECT toDecimal128(-12345.6789, 4) AS x, trunc(x, -1), trunc(x, -2), trunc(x, -3), trunc(x, -4), trunc(x, -5); + +SELECT toDecimal64(123456789.123456789, 9) AS x, -x AS y, round(x), round(y), round(x, 5), round(y, 5), round(x, -5), round(y, -5); +SELECT toDecimal64(123456789.123456789, 9) AS x, -x AS y, ceil(x), ceil(y), ceil(x, 5), ceil(y, 5), ceil(x, -5), ceil(y, -5); +SELECT toDecimal64(123456789.123456789, 9) AS x, -x AS y, floor(x), floor(y), floor(x, 5), floor(y, 5), floor(x, -5), floor(y, -5); +SELECT toDecimal64(123456789.123456789, 9) AS x, -x AS y, trunc(x), trunc(y), trunc(x, 5), trunc(y, 5), trunc(x, -5), trunc(y, -5); + +SELECT toDecimal128(12345678901234567890123456789.123456789, 9) AS x, -x AS y, round(x), round(y), round(x, 3), round(y, 3); +SELECT toDecimal128(12345678901234567890123456789.123456789, 9) AS x, -x AS y, ceil(x), ceil(y), ceil(x, 3), ceil(y, 3); +SELECT toDecimal128(12345678901234567890123456789.123456789, 9) AS x, -x AS y, floor(x), floor(y), floor(x, 3), floor(y, 3); +SELECT toDecimal128(12345678901234567890123456789.123456789, 9) AS x, -x AS y, trunc(x), trunc(y), trunc(x, 3), trunc(y, 3); + +SELECT toDecimal128(12345678901234567890123456789.123456789, 9) AS x, -x AS y, round(x), round(y), round(x, -3), round(y, -3); +SELECT toDecimal128(12345678901234567890123456789.123456789, 9) AS x, -x AS y, ceil(x), ceil(y), ceil(x, -3), ceil(y, -3); +SELECT toDecimal128(12345678901234567890123456789.123456789, 9) AS x, -x AS y, floor(x), floor(y), floor(x, -3), floor(y, -3); +SELECT toDecimal128(12345678901234567890123456789.123456789, 9) AS x, -x AS y, trunc(x), trunc(y), trunc(x, -3), trunc(y, -3);