#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;
}