#pragma once #include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int LOGICAL_ERROR; } /// Implements Decimal(P, S), where P is precision, S is scale. /// Maximum precisions for underlying types are: /// Int32 9 /// Int64 18 /// Int128 38 /// Int256 76 /// Operation between two decimals leads to Decimal(P, S), where /// P is one of (9, 18, 38, 76); equals to the maximum precision for the biggest underlying type of operands. /// S is maximum scale of operands. The allowed valuas are [0, precision] template class DataTypeDecimal final : public DataTypeDecimalBase { using Base = DataTypeDecimalBase; public: using typename Base::FieldType; using typename Base::ColumnType; using Base::Base; static constexpr auto family_name = "Decimal"; const char * getFamilyName() const override { return family_name; } std::string doGetName() const override; TypeIndex getTypeId() const override { return TypeToTypeIndex; } bool canBePromoted() const override { return true; } DataTypePtr promoteNumericType() const override; bool equals(const IDataType & rhs) const override; T parseFromString(const String & str) const; SerializationPtr doGetDefaultSerialization() const override; }; using DataTypeDecimal32 = DataTypeDecimal; using DataTypeDecimal64 = DataTypeDecimal; using DataTypeDecimal128 = DataTypeDecimal; using DataTypeDecimal256 = DataTypeDecimal; template inline const DataTypeDecimal * checkDecimal(const IDataType & data_type) { return typeid_cast *>(&data_type); } inline UInt32 getDecimalScale(const IDataType & data_type) { if (const auto * decimal_type = checkDecimal(data_type)) return decimal_type->getScale(); if (const auto * decimal_type = checkDecimal(data_type)) return decimal_type->getScale(); if (const auto * decimal_type = checkDecimal(data_type)) return decimal_type->getScale(); if (const auto * decimal_type = checkDecimal(data_type)) return decimal_type->getScale(); if (const auto * date_time_type = typeid_cast(&data_type)) return date_time_type->getScale(); throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot get decimal scale from type {}", data_type.getName()); } inline UInt32 getDecimalPrecision(const IDataType & data_type) { if (const auto * decimal_type = checkDecimal(data_type)) return decimal_type->getPrecision(); if (const auto * decimal_type = checkDecimal(data_type)) return decimal_type->getPrecision(); if (const auto * decimal_type = checkDecimal(data_type)) return decimal_type->getPrecision(); if (const auto * decimal_type = checkDecimal(data_type)) return decimal_type->getPrecision(); if (const auto * date_time_type = typeid_cast(&data_type)) return date_time_type->getPrecision(); throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot get decimal precision from type {}", data_type.getName()); } template inline UInt32 getDecimalScale(const DataTypeDecimal & data_type) { return data_type.getScale(); } #define FOR_EACH_DECIMAL_TYPE(M) \ M(DataTypeDecimal) \ M(DataTypeDateTime64) \ M(DataTypeDecimal32) \ M(DataTypeDecimal64) \ M(DataTypeDecimal128) \ M(DataTypeDecimal256) #define FOR_EACH_DECIMAL_TYPE_PASS(M, X) \ M(DataTypeDecimal, X) \ M(DataTypeDateTime64, X) \ M(DataTypeDecimal32, X) \ M(DataTypeDecimal64, X) \ M(DataTypeDecimal128, X) \ M(DataTypeDecimal256, X) template requires (IsDataTypeDecimal && IsDataTypeDecimal) ReturnType convertDecimalsImpl(const typename FromDataType::FieldType & value, UInt32 scale_from, UInt32 scale_to, typename ToDataType::FieldType & result); #define DISPATCH(FROM_DATA_TYPE, TO_DATA_TYPE) \ extern template void convertDecimalsImpl(const typename FROM_DATA_TYPE::FieldType & value, UInt32 scale_from, UInt32 scale_to, typename TO_DATA_TYPE::FieldType & result); \ extern template bool convertDecimalsImpl(const typename FROM_DATA_TYPE::FieldType & value, UInt32 scale_from, UInt32 scale_to, typename TO_DATA_TYPE::FieldType & result); #define INVOKE(X) FOR_EACH_DECIMAL_TYPE_PASS(DISPATCH, X) FOR_EACH_DECIMAL_TYPE(INVOKE); #undef INVOKE #undef DISPATCH template requires (IsDataTypeDecimal && IsDataTypeDecimal) typename ToDataType::FieldType convertDecimals(const typename FromDataType::FieldType & value, UInt32 scale_from, UInt32 scale_to); #define DISPATCH(FROM_DATA_TYPE, TO_DATA_TYPE) \ extern template typename TO_DATA_TYPE::FieldType convertDecimals(const typename FROM_DATA_TYPE::FieldType & value, UInt32 scale_from, UInt32 scale_to); #define INVOKE(X) FOR_EACH_DECIMAL_TYPE_PASS(DISPATCH, X) FOR_EACH_DECIMAL_TYPE(INVOKE); #undef INVOKE #undef DISPATCH template requires (IsDataTypeDecimal && IsDataTypeDecimal) bool tryConvertDecimals(const typename FromDataType::FieldType & value, UInt32 scale_from, UInt32 scale_to, typename ToDataType::FieldType & result); #define DISPATCH(FROM_DATA_TYPE, TO_DATA_TYPE) \ extern template bool tryConvertDecimals(const typename FROM_DATA_TYPE::FieldType & value, UInt32 scale_from, UInt32 scale_to, typename TO_DATA_TYPE::FieldType & result); #define INVOKE(X) FOR_EACH_DECIMAL_TYPE_PASS(DISPATCH, X) FOR_EACH_DECIMAL_TYPE(INVOKE); #undef INVOKE #undef DISPATCH template requires (IsDataTypeDecimal && is_arithmetic_v) ReturnType convertFromDecimalImpl(const typename FromDataType::FieldType & value, UInt32 scale, typename ToDataType::FieldType & result); #define DISPATCH(FROM_DATA_TYPE, TO_DATA_TYPE) \ extern template void convertFromDecimalImpl(const typename FROM_DATA_TYPE::FieldType & value, UInt32 scale, typename TO_DATA_TYPE::FieldType & result); \ extern template bool convertFromDecimalImpl(const typename FROM_DATA_TYPE::FieldType & value, UInt32 scale, typename TO_DATA_TYPE::FieldType & result); #define INVOKE(X) FOR_EACH_DECIMAL_TYPE_PASS(DISPATCH, X) FOR_EACH_ARITHMETIC_TYPE(INVOKE); #undef INVOKE #undef DISPATCH template requires (IsDataTypeDecimal && is_arithmetic_v) typename ToDataType::FieldType convertFromDecimal(const typename FromDataType::FieldType & value, UInt32 scale); #define DISPATCH(FROM_DATA_TYPE, TO_DATA_TYPE) \ extern template typename TO_DATA_TYPE::FieldType convertFromDecimal(const typename FROM_DATA_TYPE::FieldType & value, UInt32 scale); #define INVOKE(X) FOR_EACH_DECIMAL_TYPE_PASS(DISPATCH, X) FOR_EACH_ARITHMETIC_TYPE(INVOKE); #undef INVOKE #undef DISPATCH template requires (IsDataTypeDecimal && is_arithmetic_v) bool tryConvertFromDecimal(const typename FromDataType::FieldType & value, UInt32 scale, typename ToDataType::FieldType& result); #define DISPATCH(FROM_DATA_TYPE, TO_DATA_TYPE) \ extern template bool tryConvertFromDecimal(const typename FROM_DATA_TYPE::FieldType & value, UInt32 scale, typename TO_DATA_TYPE::FieldType& result); #define INVOKE(X) FOR_EACH_DECIMAL_TYPE_PASS(DISPATCH, X) FOR_EACH_ARITHMETIC_TYPE(INVOKE); #undef INVOKE #undef DISPATCH template requires (is_arithmetic_v && IsDataTypeDecimal) ReturnType convertToDecimalImpl(const typename FromDataType::FieldType & value, UInt32 scale, typename ToDataType::FieldType& result); #define DISPATCH(FROM_DATA_TYPE, TO_DATA_TYPE) \ extern template void convertToDecimalImpl(const typename FROM_DATA_TYPE::FieldType & value, UInt32 scale, typename TO_DATA_TYPE::FieldType & result); \ extern template bool convertToDecimalImpl(const typename FROM_DATA_TYPE::FieldType & value, UInt32 scale, typename TO_DATA_TYPE::FieldType & result); #define INVOKE(X) FOR_EACH_ARITHMETIC_TYPE_PASS(DISPATCH, X) FOR_EACH_DECIMAL_TYPE(INVOKE); #undef INVOKE #undef DISPATCH template requires (is_arithmetic_v && IsDataTypeDecimal) typename ToDataType::FieldType convertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale); #define DISPATCH(FROM_DATA_TYPE, TO_DATA_TYPE) \ extern template typename TO_DATA_TYPE::FieldType convertToDecimal(const typename FROM_DATA_TYPE::FieldType & value, UInt32 scale); #define INVOKE(X) FOR_EACH_ARITHMETIC_TYPE_PASS(DISPATCH, X) FOR_EACH_DECIMAL_TYPE(INVOKE); #undef INVOKE #undef DISPATCH template requires (is_arithmetic_v && IsDataTypeDecimal) bool tryConvertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale, typename ToDataType::FieldType& result); #define DISPATCH(FROM_DATA_TYPE, TO_DATA_TYPE) \ extern template bool tryConvertToDecimal(const typename FROM_DATA_TYPE::FieldType & value, UInt32 scale, typename TO_DATA_TYPE::FieldType& result); #define INVOKE(X) FOR_EACH_ARITHMETIC_TYPE_PASS(DISPATCH, X) FOR_EACH_DECIMAL_TYPE(INVOKE); #undef INVOKE #undef DISPATCH template DataTypePtr createDecimalMaxPrecision(UInt64 scale); extern template DataTypePtr createDecimalMaxPrecision(UInt64 scale); extern template DataTypePtr createDecimalMaxPrecision(UInt64 scale); extern template DataTypePtr createDecimalMaxPrecision(UInt64 scale); extern template DataTypePtr createDecimalMaxPrecision(UInt64 scale); extern template class DataTypeDecimal; extern template class DataTypeDecimal; extern template class DataTypeDecimal; extern template class DataTypeDecimal; }