diff --git a/dbms/src/Core/Types.h b/dbms/src/Core/Types.h index 9eb34ca1575..8c8ff9c0fa1 100644 --- a/dbms/src/Core/Types.h +++ b/dbms/src/Core/Types.h @@ -191,10 +191,4 @@ namespace DB template <> constexpr bool decTrait() { return true; } template <> constexpr bool decTrait() { return true; } template <> constexpr bool decTrait() { return true; } - - template - inline constexpr bool decBaseTrait() { return false; } - template <> constexpr bool decBaseTrait() { return true; } - template <> constexpr bool decBaseTrait() { return true; } - template <> constexpr bool decBaseTrait() { return true; } } diff --git a/dbms/src/DataTypes/DataTypesDecimal.cpp b/dbms/src/DataTypes/DataTypesDecimal.cpp index f0e2c58490d..822c2679579 100644 --- a/dbms/src/DataTypes/DataTypesDecimal.cpp +++ b/dbms/src/DataTypes/DataTypesDecimal.cpp @@ -39,9 +39,8 @@ bool DataTypeDecimal::equals(const IDataType & rhs) const } template -void DataTypeDecimal::serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const +void DataTypeDecimal::writeText(T value, WriteBuffer & ostr) const { - T value = static_cast(column).getData()[row_num]; if (value < T(0)) { value *= T(-1); @@ -59,14 +58,26 @@ void DataTypeDecimal::serializeText(const IColumn & column, size_t row_num, W } } +template +void DataTypeDecimal::serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const +{ + T value = static_cast(column).getData()[row_num]; + writeText(value, ostr); +} + +template +void DataTypeDecimal::readText(T & x, ReadBuffer & istr, UInt32 precision, UInt32 scale) +{ + UInt32 unread_scale = scale; + readDecimalText(istr, x, precision, unread_scale); + x *= getScaleMultiplier(unread_scale); +} template void DataTypeDecimal::deserializeText(IColumn & column, ReadBuffer & istr, const FormatSettings &) const { T x; - UInt32 unread_scale = scale; - readDecimalText(istr, x, precision, unread_scale); - x *= getScaleMultiplier(unread_scale); + readText(x, istr); static_cast(column).getData().push_back(x); } @@ -156,6 +167,21 @@ MutableColumnPtr DataTypeDecimal::createColumn() const // +DataTypePtr createDecimal(UInt64 precision_value, UInt64 scale_value) +{ + if (precision_value < minDecimalPrecision() || precision_value > maxDecimalPrecision()) + throw Exception("Wrong precision", ErrorCodes::ARGUMENT_OUT_OF_BOUND); + + if (static_cast(scale_value) > precision_value) + throw Exception("Negative scales and scales larger than presicion are not supported", ErrorCodes::ARGUMENT_OUT_OF_BOUND); + + if (precision_value <= maxDecimalPrecision()) + return std::make_shared>(precision_value, scale_value); + else if (precision_value <= maxDecimalPrecision()) + return std::make_shared>(precision_value, scale_value); + return std::make_shared>(precision_value, scale_value); +} + static DataTypePtr create(const ASTPtr & arguments) { if (!arguments || arguments->children.size() != 2) @@ -170,19 +196,9 @@ static DataTypePtr create(const ASTPtr & arguments) throw Exception("Decimal data type family must have a two numbers as its arguments", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); UInt64 precision_value = precision->value.get(); - Int64 scale_value = scale->value.get(); + UInt64 scale_value = scale->value.get(); - if (precision_value < minDecimalPrecision() || precision_value > maxDecimalPrecision()) - throw Exception("Wrong precision", ErrorCodes::ARGUMENT_OUT_OF_BOUND); - - if (scale_value < 0 || static_cast(scale_value) > precision_value) - throw Exception("Negative scales and scales larger than presicion are not supported", ErrorCodes::ARGUMENT_OUT_OF_BOUND); - - if (precision_value <= maxDecimalPrecision()) - return std::make_shared>(precision_value, scale_value); - else if (precision_value <= maxDecimalPrecision()) - return std::make_shared>(precision_value, scale_value); - return std::make_shared>(precision_value, scale_value); + return createDecimal(precision_value, scale_value); } diff --git a/dbms/src/DataTypes/DataTypesDecimal.h b/dbms/src/DataTypes/DataTypesDecimal.h index 43b958e28db..0da102aa936 100644 --- a/dbms/src/DataTypes/DataTypesDecimal.h +++ b/dbms/src/DataTypes/DataTypesDecimal.h @@ -13,6 +13,7 @@ namespace ErrorCodes { extern const int LOGICAL_ERROR; extern const int ARGUMENT_OUT_OF_BOUND; + extern const int CANNOT_CONVERT_TYPE; } /// @@ -69,6 +70,9 @@ template <> constexpr size_t maxDecimalPrecision() { return 18; } template <> constexpr size_t maxDecimalPrecision() { return 38; } +DataTypePtr createDecimal(UInt64 precision, UInt64 scale); + + /// Implements Decimal(P, S), where P is precision, S is scale. /// Maximum precisions for underlying types are: /// Int32 9 @@ -88,13 +92,15 @@ public: static constexpr bool is_parametric = true; + static constexpr size_t maxPrecision() { return maxDecimalPrecision(); } + DataTypeDecimal(UInt32 precision_, UInt32 scale_) : precision(precision_), scale(scale_) { - if (unlikely(precision < 1 || precision > maxDecimalPrecision())) + if (unlikely(precision < 1 || precision > maxPrecision())) throw Exception("Precision is out of bounds", ErrorCodes::ARGUMENT_OUT_OF_BOUND); - if (unlikely(scale < 0 || static_cast(scale) > maxDecimalPrecision())) + if (unlikely(scale < 0 || static_cast(scale) > maxPrecision())) throw Exception("Scale is out of bounds", ErrorCodes::ARGUMENT_OUT_OF_BOUND); } @@ -161,7 +167,7 @@ public: return x % getScaleMultiplier(); } - T maxWholeValue() const { return getScaleMultiplier(maxDecimalPrecision() - scale) - T(1); } + T maxWholeValue() const { return getScaleMultiplier(maxPrecision() - scale) - T(1); } bool canStoreWhole(T x) const { @@ -191,6 +197,10 @@ public: T parseFromString(const String & str) const; + void readText(T & x, ReadBuffer & istr) const { readText(x, istr, precision, scale); } + void writeText(T value, WriteBuffer & ostr) const; + + static void readText(T & x, ReadBuffer & istr, UInt32 precision, UInt32 scale); static T getScaleMultiplier(UInt32 scale); private: @@ -253,6 +263,17 @@ inline bool isDecimal(const IDataType & data_type) return false; } +inline UInt32 getDecimalScale(const IDataType & data_type) +{ + if (auto * decimal_type = checkDecimal(data_type)) + return decimal_type->getScale(); + if (auto * decimal_type = checkDecimal(data_type)) + return decimal_type->getScale(); + if (auto * decimal_type = checkDecimal(data_type)) + return decimal_type->getScale(); + return std::numeric_limits::max(); +} + /// inline bool notDecimalButComparableToDecimal(const IDataType & data_type) { @@ -269,4 +290,54 @@ inline bool comparableToDecimal(const IDataType & data_type) return isDecimal(data_type); } +template constexpr bool IsDecimal = false; +template <> constexpr bool IsDecimal> = true; +template <> constexpr bool IsDecimal> = true; +template <> constexpr bool IsDecimal> = true; + +template +inline std::enable_if_t && IsDecimal, typename ToDataType::FieldType> +convertDecimals(const typename FromDataType::FieldType & value, UInt32 scale_from, UInt32 scale_to) +{ + ToDataType type_to(ToDataType::maxPrecision(), scale_to); + FromDataType type_from(FromDataType::maxPrecision(), scale_from); + + if (scale_from > scale_to) + { + typename FromDataType::FieldType factor = type_from.scaleFactorFor(type_to, false); + return value / factor; + } + else + { + typename ToDataType::FieldType factor = type_to.scaleFactorFor(type_from, false); + return value * factor; + } +} + +template +inline std::enable_if_t && !IsDecimal, typename ToDataType::FieldType> +convertFromDecimal(const typename FromDataType::FieldType & value, UInt32 scale [[maybe_unused]]) +{ + if (scale > FromDataType::maxPrecision()) + throw Exception("Wrong decimal scale", ErrorCodes::LOGICAL_ERROR); + + if constexpr (!std::is_same_v>) + throw Exception("Illegal convertion from decimal", ErrorCodes::CANNOT_CONVERT_TYPE); + else + return static_cast(value) / FromDataType::getScaleMultiplier(scale); +} + +template +inline std::enable_if_t && IsDecimal, typename ToDataType::FieldType> +convertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale [[maybe_unused]]) +{ + if (scale > ToDataType::maxPrecision()) + throw Exception("Wrong decimal scale", ErrorCodes::LOGICAL_ERROR); + + if constexpr (!std::is_same_v>) + throw Exception("Illegal convertion to decimal", ErrorCodes::CANNOT_CONVERT_TYPE); + else + return value * ToDataType::getScaleMultiplier(scale); +} + } diff --git a/dbms/src/Functions/FunctionHelpers.h b/dbms/src/Functions/FunctionHelpers.h index 81477836fe0..44184d893f5 100644 --- a/dbms/src/Functions/FunctionHelpers.h +++ b/dbms/src/Functions/FunctionHelpers.h @@ -305,6 +305,7 @@ class DataTypeFixedString; class DataTypeUUID; template class DataTypeEnum; template class DataTypeNumber; +template class DataTypeDecimal; template bool callOnDataTypeAndIndex(TypeIndex number, F && f) @@ -324,6 +325,10 @@ bool callOnDataTypeAndIndex(TypeIndex number, F && f) case TypeIndex::Float32: return f(TypePair>()); case TypeIndex::Float64: return f(TypePair>()); + case TypeIndex::Dec32: return f(TypePair>()); + case TypeIndex::Dec64: return f(TypePair>()); + case TypeIndex::Dec128: return f(TypePair>()); + case TypeIndex::Date: return f(TypePair()); case TypeIndex::DateTime: return f(TypePair()); @@ -360,6 +365,10 @@ bool callOnIndexAndDataType(TypeIndex number, F && f) case TypeIndex::Float32: return f(TypePair, T>()); case TypeIndex::Float64: return f(TypePair, T>()); + case TypeIndex::Dec32: return f(TypePair, T>()); + case TypeIndex::Dec64: return f(TypePair, T>()); + case TypeIndex::Dec128: return f(TypePair, T>()); + case TypeIndex::Date: return f(TypePair()); case TypeIndex::DateTime: return f(TypePair()); diff --git a/dbms/src/Functions/FunctionsArithmetic.h b/dbms/src/Functions/FunctionsArithmetic.h index a68bb657944..3ab71f6d4ad 100644 --- a/dbms/src/Functions/FunctionsArithmetic.h +++ b/dbms/src/Functions/FunctionsArithmetic.h @@ -930,11 +930,6 @@ template constexpr bool IsDateOrDateTime = false; template <> constexpr bool IsDateOrDateTime = true; template <> constexpr bool IsDateOrDateTime = true; -template constexpr bool IsDecimal = false; -template <> constexpr bool IsDecimal> = true; -template <> constexpr bool IsDecimal> = true; -template <> constexpr bool IsDecimal> = true; - template constexpr bool UseLeftDecimal = false; template <> constexpr bool UseLeftDecimal, DataTypeDecimal> = true; template <> constexpr bool UseLeftDecimal, DataTypeDecimal> = true; diff --git a/dbms/src/Functions/FunctionsConversion.cpp b/dbms/src/Functions/FunctionsConversion.cpp index 596c86f07e2..a8ce9cccc5e 100644 --- a/dbms/src/Functions/FunctionsConversion.cpp +++ b/dbms/src/Functions/FunctionsConversion.cpp @@ -40,6 +40,10 @@ void registerFunctionsConversion(FunctionFactory & factory) factory.registerFunction(); factory.registerFunction(); + factory.registerFunction(); + factory.registerFunction(); + //factory.registerFunction(); /// TODO + factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); diff --git a/dbms/src/Functions/FunctionsConversion.h b/dbms/src/Functions/FunctionsConversion.h index 4ca93f26807..5e94bbbf762 100644 --- a/dbms/src/Functions/FunctionsConversion.h +++ b/dbms/src/Functions/FunctionsConversion.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +73,21 @@ namespace ErrorCodes * toType - conversion in "natural way"; */ +inline UInt32 extractToDecimalScale(const ColumnWithTypeAndName & named_column) +{ + const auto * arg_type = named_column.type.get(); + bool ok = checkAndGetDataType(arg_type) + || checkAndGetDataType(arg_type) + || checkAndGetDataType(arg_type) + || checkAndGetDataType(arg_type); + if (!ok) + throw Exception("Illegal type of toDecimal() scale " + named_column.type->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + Field field; + named_column.column->get(0, field); + return field.get(); +} + /** Conversion of number types to each other, enums to numbers, dates and datetimes to numbers and back: done by straight assignment. * (Date is represented internally as number of days from some day; DateTime - as unix timestamp) @@ -84,10 +100,17 @@ struct ConvertImpl static void execute(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) { - if (const ColumnVector * col_from - = checkAndGetColumn>(block.getByPosition(arguments[0]).column.get())) + const ColumnWithTypeAndName & named_from = block.getByPosition(arguments[0]); + + if (const ColumnVector * col_from = checkAndGetColumn>(named_from.column.get())) { auto col_to = ColumnVector::create(); + if constexpr (IsDecimal) + { + const ColumnWithTypeAndName & scale_column = block.getByPosition(arguments[1]); + UInt32 scale = extractToDecimalScale(scale_column); + col_to->getData().setScale(scale); + } const typename ColumnVector::Container & vec_from = col_from->getData(); typename ColumnVector::Container & vec_to = col_to->getData(); @@ -95,13 +118,21 @@ struct ConvertImpl vec_to.resize(size); for (size_t i = 0; i < size; ++i) - vec_to[i] = static_cast(vec_from[i]); + { + if constexpr (IsDecimal && IsDecimal) + vec_to[i] = convertDecimals(vec_from[i], vec_from.getScale(), vec_to.getScale()); + else if constexpr (IsDecimal) + vec_to[i] = convertFromDecimal(vec_from[i], vec_from.getScale()); + else if constexpr (IsDecimal) + vec_to[i] = convertToDecimal(vec_from[i], vec_to.getScale()); + else + vec_to[i] = static_cast(vec_from[i]); + } block.getByPosition(result).column = std::move(col_to); } else - throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName() - + " of first argument of function " + Name::name, + throw Exception("Illegal column " + named_from.column->getName() + " of first argument of function " + Name::name, ErrorCodes::ILLEGAL_COLUMN); } }; @@ -200,6 +231,15 @@ struct FormatImpl> } }; +template +struct FormatImpl> +{ + static void execute(const FieldType x, WriteBuffer & wb, const DataTypeDecimal * type, const DateLUTImpl *) + { + type->writeText(x, wb); + } +}; + /// DataTypeEnum to DataType free conversion template @@ -441,6 +481,14 @@ struct ConvertThroughParsing auto col_to = ColumnVector::create(size); typename ColumnVector::Container & vec_to = col_to->getData(); + if constexpr (IsDecimal) + { + const ColumnWithTypeAndName & scale_column = block.getByPosition(arguments[1]); + UInt32 scale = extractToDecimalScale(scale_column); + vec_to.setScale(scale); + ToDataType check_bounds_in_ctor(ToDataType::maxPrecision(), scale); + } + ColumnUInt8::MutablePtr col_null_map_to; ColumnUInt8::Container * vec_null_map_to [[maybe_unused]] = nullptr; if constexpr (exception_mode == ConvertFromStringExceptionMode::Null) @@ -473,7 +521,11 @@ struct ConvertThroughParsing ReadBufferFromMemory read_buffer(&(*chars)[current_offset], string_size); - if constexpr (exception_mode == ConvertFromStringExceptionMode::Throw) + if constexpr (IsDecimal) + { + ToDataType::readText(vec_to[i], read_buffer, ToDataType::maxPrecision(), vec_to.getScale()); + } + else if constexpr (exception_mode == ConvertFromStringExceptionMode::Throw) { if constexpr (parsing_mode == ConvertFromStringParsingMode::BestEffort) { @@ -530,7 +582,6 @@ template struct ConvertImpl, DataTypeFixedString>, ToDataType, Name> : ConvertThroughParsing {}; - /// Generic conversion of any type from String. Used for complex types: Array and Tuple. struct ConvertImplGenericFromString { @@ -647,6 +698,9 @@ struct ConvertImpl struct NameToDate { static constexpr auto name = "toDate"; }; struct NameToDateTime { static constexpr auto name = "toDateTime"; }; struct NameToString { static constexpr auto name = "toString"; }; +struct NameToDecimal9 { static constexpr auto name = "toDecimal9"; }; +struct NameToDecimal18 { static constexpr auto name = "toDecimal18"; }; +struct NameToDecimal38 { static constexpr auto name = "toDecimal38"; }; #define DEFINE_NAME_TO_INTERVAL(INTERVAL_KIND) \ @@ -674,6 +728,9 @@ public: using Monotonic = MonotonicityImpl; static constexpr auto name = Name::name; + static constexpr bool to_decimal = + std::is_same_v || std::is_same_v || std::is_same_v; + static FunctionPtr create(const Context &) { return std::make_shared(); } String getName() const override @@ -687,7 +744,13 @@ public: DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override { - if (arguments.size() != 1 && arguments.size() != 2) + if (to_decimal && arguments.size() != 2) + { + throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " + + toString(arguments.size()) + ", should be 2.", + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + } + else if (arguments.size() != 1 && arguments.size() != 2) throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " + toString(arguments.size()) + ", should be 1 or 2. Second argument (time zone) is optional only make sense for DateTime.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); @@ -696,6 +759,19 @@ public: { return std::make_shared(DataTypeInterval::Kind(Name::kind)); } + else if constexpr (to_decimal) + { + UInt64 scale = extractToDecimalScale(arguments[1]); + + if constexpr (std::is_same_v) + return createDecimal(9, scale); + else if constexpr (std::is_same_v) + return createDecimal(18, scale); + else if constexpr ( std::is_same_v) + return createDecimal(38, scale); + + throw Exception("Someting wrong with toDecimalNN()", ErrorCodes::LOGICAL_ERROR); + } else { /** Optional second argument with time zone is supported: @@ -709,11 +785,12 @@ public: throw Exception("Illegal type " + arguments[1].type->getName() + " of 2nd argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); - if (!(std::is_same_v + static constexpr bool to_date_or_time = std::is_same_v || std::is_same_v - || std::is_same_v - || (std::is_same_v - && checkDataType(arguments[0].type.get())))) + || std::is_same_v; + + if (!(to_date_or_time + || (std::is_same_v && checkDataType(arguments[0].type.get())))) { throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " + toString(arguments.size()) + ", should be 1.", @@ -1128,6 +1205,9 @@ using FunctionToDateTime = FunctionConvert>; using FunctionToString = FunctionConvert; using FunctionToUnixTimestamp = FunctionConvert>; +using FunctionToDecimal9 = FunctionConvert, NameToDecimal9, ToIntMonotonicity>; +using FunctionToDecimal18 = FunctionConvert, NameToDecimal18, ToIntMonotonicity>; +using FunctionToDecimal38 = FunctionConvert, NameToDecimal38, ToIntMonotonicity>; template struct FunctionTo; @@ -1147,6 +1227,9 @@ template <> struct FunctionTo { using Type = FunctionToDateTim template <> struct FunctionTo { using Type = FunctionToUUID; }; template <> struct FunctionTo { using Type = FunctionToString; }; template <> struct FunctionTo { using Type = FunctionToFixedString; }; +template <> struct FunctionTo> { using Type = FunctionToDecimal9; }; +template <> struct FunctionTo> { using Type = FunctionToDecimal18; }; +template <> struct FunctionTo> { using Type = FunctionToDecimal38; }; template struct FunctionTo> : FunctionTo> diff --git a/dbms/tests/queries/0_stateless/00700_decimal_casts.reference b/dbms/tests/queries/0_stateless/00700_decimal_casts.reference new file mode 100644 index 00000000000..6a22cb44b58 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00700_decimal_casts.reference @@ -0,0 +1,89 @@ +1.1 1.10 1.10000000 +1 1.1 1.10 1.10000000 +9999999 9999999 -9999999 9999999 -9999999 +999999.9 999999.9 -999999.9 999999.9 -999999.9 +99999.99 99999.99 -99999.99 99999.99 -99999.99 +9999.999 9999.999 -9999.999 9999.999 -9999.999 +999.9999 999.9999 -999.9999 999.9999 -999.9999 +99.99999 99.99999 -99.99999 99.99999 -99.99999 +9.999999 9.999999 -9.999999 9.999999 -9.999999 +0.9999999 0.9999999 -0.9999999 0.9999999 -0.9999999 +999999999 999999999 -999999999 999999999 -999999999 +99999999.9 99999999.9 -99999999.9 99999999.9 -99999999.9 +9999999.99 9999999.99 -9999999.99 9999999.99 -9999999.99 +999999.999 999999.999 -999999.999 999999.999 -999999.999 +99999.9999 99999.9999 -99999.9999 99999.9999 -99999.9999 +9999.99999 9999.99999 -9999.99999 9999.99999 -9999.99999 +999.999999 999.999999 -999.999999 999.999999 -999.999999 +99.9999999 99.9999999 -99.9999999 99.9999999 -99.9999999 +9.99999999 9.99999998 -9.99999998 9.99999998 -9.99999998 +0.999999999 0.999999999 -0.999999999 0.999999999 -0.999999999 +0.0000 0.00 0.00000000 +1.0000 0.11 0.11000000 +2.0000 0.22 0.22000000 +3.0000 0.33 0.33000000 +4.0000 0.44 0.44000000 +5.0000 0.55 0.55000000 +6.0000 0.66 0.66000000 +7.0000 0.77 0.77000000 +8.0000 0.88 0.88000000 +9.0000 1.00 1.00000000 +0.0000 0.00000000 0.00 +1.0000 0.11110000 0.11 +2.0000 0.22220000 0.22 +3.0000 0.33330000 0.33 +4.0000 0.44440000 0.44 +5.0000 0.55550000 0.55 +6.0000 0.66660000 0.66 +7.0000 0.77770000 0.77 +8.0000 0.88880000 0.88 +9.0000 1.00000000 1.00 +0.00000000 0.0000 0.00 +1.00000000 0.1111 0.11 +2.00000000 0.2222 0.22 +3.00000000 0.3333 0.33 +4.00000000 0.4444 0.44 +5.00000000 0.5555 0.55 +6.00000000 0.6666 0.66 +7.00000000 0.7777 0.77 +8.00000000 0.8888 0.88 +9.00000000 1.0000 1.00 +0.0000 0.00 0.00000000 +1.0000 0.11 0.11000000 +2.0000 0.22 0.22000000 +3.0000 0.33 0.33000000 +4.0000 0.44 0.44000000 +5.0000 0.55 0.55000000 +6.0000 0.66 0.66000000 +7.0000 0.77 0.77000000 +8.0000 0.88 0.88000000 +9.0000 1.00 1.00000000 +0.0000 0.00000000 0.00 +1.0000 0.11110000 0.11 +2.0000 0.22220000 0.22 +3.0000 0.33330000 0.33 +4.0000 0.44440000 0.44 +5.0000 0.55550000 0.55 +6.0000 0.66660000 0.66 +7.0000 0.77770000 0.77 +8.0000 0.88880000 0.88 +9.0000 1.00000000 1.00 +0.00000000 0.0000 0.00 +1.00000000 0.1111 0.11 +2.00000000 0.2222 0.22 +3.00000000 0.3333 0.33 +4.00000000 0.4444 0.44 +5.00000000 0.5555 0.55 +6.00000000 0.6666 0.66 +7.00000000 0.7777 0.77 +8.00000000 0.8888 0.88 +9.00000000 1.0000 1.00 +99 99 -99 99 -99 +9999 9999 -9999 9999 -9999 +999999999 999999999 -999999999 999999999 -999999999 +999999999 999999999 -999999999 999999999 -999999999 +999999999999999999 999999999999999999 -999999999999999999 +99 99 99 +9999 9999 9999 +999999999 999999999 999999999 +999999999 999999999 999999999 diff --git a/dbms/tests/queries/0_stateless/00700_decimal_casts.sql b/dbms/tests/queries/0_stateless/00700_decimal_casts.sql new file mode 100644 index 00000000000..e161fe38168 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00700_decimal_casts.sql @@ -0,0 +1,49 @@ +SET allow_experimental_decimal_type = 1; + +SELECT toDecimal9('1.1', 1), toDecimal9('1.1', 2), toDecimal9('1.1', 8); +SELECT toDecimal9('1.1', 0); -- { serverError 69 } +SELECT toDecimal9(1.1, 0), toDecimal9(1.1, 1), toDecimal9(1.1, 2), toDecimal9(1.1, 8); + +SELECT toFloat32(9999999) as x, toDecimal9(x, 0), toDecimal9(-x, 0), toDecimal18(x, 0), toDecimal18(-x, 0); +SELECT toFloat32(999999.9) as x, toDecimal9(x, 1), toDecimal9(-x, 1), toDecimal18(x, 1), toDecimal18(-x, 1); +SELECT toFloat32(99999.99) as x, toDecimal9(x, 2), toDecimal9(-x, 2), toDecimal18(x, 2), toDecimal18(-x, 2); +SELECT toFloat32(9999.999) as x, toDecimal9(x, 3), toDecimal9(-x, 3), toDecimal18(x, 3), toDecimal18(-x, 3); +SELECT toFloat32(999.9999) as x, toDecimal9(x, 4), toDecimal9(-x, 4), toDecimal18(x, 4), toDecimal18(-x, 4); +SELECT toFloat32(99.99999) as x, toDecimal9(x, 5), toDecimal9(-x, 5), toDecimal18(x, 5), toDecimal18(-x, 5); +SELECT toFloat32(9.999999) as x, toDecimal9(x, 6), toDecimal9(-x, 6), toDecimal18(x, 6), toDecimal18(-x, 6); +SELECT toFloat32(0.9999999) as x, toDecimal9(x, 7), toDecimal9(-x, 7), toDecimal18(x, 7), toDecimal18(-x, 7); + +SELECT toFloat64(999999999) as x, toDecimal9(x, 0), toDecimal9(-x, 0), toDecimal18(x, 0), toDecimal18(-x, 0); +SELECT toFloat64(99999999.9) as x, toDecimal9(x, 1), toDecimal9(-x, 1), toDecimal18(x, 1), toDecimal18(-x, 1); +SELECT toFloat64(9999999.99) as x, toDecimal9(x, 2), toDecimal9(-x, 2), toDecimal18(x, 2), toDecimal18(-x, 2); +SELECT toFloat64(999999.999) as x, toDecimal9(x, 3), toDecimal9(-x, 3), toDecimal18(x, 3), toDecimal18(-x, 3); +SELECT toFloat64(99999.9999) as x, toDecimal9(x, 4), toDecimal9(-x, 4), toDecimal18(x, 4), toDecimal18(-x, 4); +SELECT toFloat64(9999.99999) as x, toDecimal9(x, 5), toDecimal9(-x, 5), toDecimal18(x, 5), toDecimal18(-x, 5); +SELECT toFloat64(999.999999) as x, toDecimal9(x, 6), toDecimal9(-x, 6), toDecimal18(x, 6), toDecimal18(-x, 6); +SELECT toFloat64(99.9999999) as x, toDecimal9(x, 7), toDecimal9(-x, 7), toDecimal18(x, 7), toDecimal18(-x, 7); +SELECT toFloat64(9.99999999) as x, toDecimal9(x, 8), toDecimal9(-x, 8), toDecimal18(x, 8), toDecimal18(-x, 8); +SELECT toFloat64(0.999999999) as x, toDecimal9(x, 9), toDecimal9(-x, 9), toDecimal18(x, 9), toDecimal18(-x, 9); + +SELECT toDecimal9(number, 4) as n1, toDecimal9(n1 / 9, 2) as n2, toDecimal9(n2, 8) FROM system.numbers LIMIT 10; +SELECT toDecimal9(number, 4) as n1, toDecimal9(n1 / 9, 8) as n2, toDecimal9(n2, 2) FROM system.numbers LIMIT 10; +SELECT toDecimal9(number, 8) as n1, toDecimal9(n1 / 9, 4) as n2, toDecimal9(n2, 2) FROM system.numbers LIMIT 10; + +SELECT toDecimal18(number, 4) as n1, toDecimal18(n1 / 9, 2) as n2, toDecimal18(n2, 8) FROM system.numbers LIMIT 10; +SELECT toDecimal18(number, 4) as n1, toDecimal18(n1 / 9, 8) as n2, toDecimal18(n2, 2) FROM system.numbers LIMIT 10; +SELECT toDecimal18(number, 8) as n1, toDecimal18(n1 / 9, 4) as n2, toDecimal18(n2, 2) FROM system.numbers LIMIT 10; + +SELECT toInt8(99) as x, toDecimal9(x, 0), toDecimal9(-x, 0), toDecimal18(x, 0), toDecimal18(-x, 0); +SELECT toInt16(9999) as x, toDecimal9(x, 0), toDecimal9(-x, 0), toDecimal18(x, 0), toDecimal18(-x, 0); +SELECT toInt32(999999999) as x, toDecimal9(x, 0), toDecimal9(-x, 0), toDecimal18(x, 0), toDecimal18(-x, 0); +SELECT toInt64(999999999) as x, toDecimal9(x, 0), toDecimal9(-x, 0), toDecimal18(x, 0), toDecimal18(-x, 0); +SELECT toInt64(999999999999999999) as x, toDecimal18(x, 0), toDecimal18(-x, 0); + +SELECT toUInt8(99) as x, toDecimal9(x, 0), toDecimal18(x, 0); +SELECT toUInt16(9999) as x, toDecimal9(x, 0), toDecimal18(x, 0); +SELECT toUInt32(999999999) as x, toDecimal9(x, 0), toDecimal18(x, 0); +SELECT toUInt64(999999999) as x, toDecimal9(x, 0), toDecimal18(x, 0); + +--SELECT CAST('1.1', 'Decimal(9,0)'), CAST('1.1', 'Decimal(9,1)'), CAST('1.1', 'Decimal(9,2)'); + +--SELECT * FROM test.decimal; +--DROP TABLE IF EXISTS test.decimal;