2018-07-20 19:05:07 +00:00
|
|
|
#pragma once
|
2019-05-15 12:28:44 +00:00
|
|
|
|
2019-12-03 10:06:34 +00:00
|
|
|
#include <common/arithmeticOverflow.h>
|
|
|
|
#include <Common/typeid_cast.h>
|
2018-08-01 19:50:19 +00:00
|
|
|
#include <DataTypes/IDataType.h>
|
2019-10-02 05:53:38 +00:00
|
|
|
#include <DataTypes/DataTypeDecimalBase.h>
|
2018-07-20 19:05:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2018-07-23 20:19:26 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2018-09-25 16:03:50 +00:00
|
|
|
extern const int DECIMAL_OVERFLOW;
|
2018-07-23 20:19:26 +00:00
|
|
|
}
|
|
|
|
|
2018-07-20 19:05:07 +00:00
|
|
|
/// Implements Decimal(P, S), where P is precision, S is scale.
|
|
|
|
/// Maximum precisions for underlying types are:
|
|
|
|
/// Int32 9
|
|
|
|
/// Int64 18
|
|
|
|
/// Int128 38
|
|
|
|
/// Operation between two decimals leads to Decimal(P, S), where
|
|
|
|
/// P is one of (9, 18, 38); equals to the maximum precision for the biggest underlying type of operands.
|
2018-09-25 16:03:50 +00:00
|
|
|
/// S is maximum scale of operands. The allowed valuas are [0, precision]
|
2018-07-20 19:05:07 +00:00
|
|
|
template <typename T>
|
2019-10-02 05:53:38 +00:00
|
|
|
class DataTypeDecimal final : public DataTypeDecimalBase<T>
|
2018-07-20 19:05:07 +00:00
|
|
|
{
|
2019-10-02 05:53:38 +00:00
|
|
|
using Base = DataTypeDecimalBase<T>;
|
2018-09-12 17:50:51 +00:00
|
|
|
static_assert(IsDecimalNumber<T>);
|
|
|
|
|
2018-07-20 19:05:07 +00:00
|
|
|
public:
|
2019-10-02 05:53:38 +00:00
|
|
|
using typename Base::FieldType;
|
|
|
|
using typename Base::ColumnType;
|
|
|
|
using Base::Base;
|
2018-07-20 19:05:07 +00:00
|
|
|
|
2019-11-05 11:59:46 +00:00
|
|
|
static constexpr auto family_name = "Decimal";
|
2019-10-30 10:10:51 +00:00
|
|
|
|
2019-11-05 11:59:46 +00:00
|
|
|
const char * getFamilyName() const override { return family_name; }
|
2018-12-13 13:41:47 +00:00
|
|
|
std::string doGetName() const override;
|
2018-08-20 15:17:55 +00:00
|
|
|
TypeIndex getTypeId() const override { return TypeId<T>::value; }
|
2019-01-25 14:16:23 +00:00
|
|
|
bool canBePromoted() const override { return true; }
|
|
|
|
DataTypePtr promoteNumericType() const override;
|
2018-07-20 19:05:07 +00:00
|
|
|
|
|
|
|
void serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const override;
|
|
|
|
void deserializeText(IColumn & column, ReadBuffer & istr, const FormatSettings &) const override;
|
2019-05-15 13:51:17 +00:00
|
|
|
void deserializeTextCSV(IColumn & column, ReadBuffer & istr, const FormatSettings &) const override;
|
2018-07-20 19:05:07 +00:00
|
|
|
|
2019-02-26 14:06:05 +00:00
|
|
|
void serializeProtobuf(const IColumn & column, size_t row_num, ProtobufWriter & protobuf, size_t & value_index) const override;
|
2019-02-19 20:01:31 +00:00
|
|
|
void deserializeProtobuf(IColumn & column, ProtobufReader & protobuf, bool allow_add_row, bool & row_added) const override;
|
2019-01-23 19:41:18 +00:00
|
|
|
|
2018-07-20 19:05:07 +00:00
|
|
|
bool equals(const IDataType & rhs) const override;
|
|
|
|
|
2018-07-30 18:10:38 +00:00
|
|
|
T parseFromString(const String & str) const;
|
2019-10-02 10:54:59 +00:00
|
|
|
void readText(T & x, ReadBuffer & istr, bool csv = false) const { readText(x, istr, this->precision, this->scale, csv); }
|
2018-07-30 18:10:38 +00:00
|
|
|
|
2019-10-02 10:54:59 +00:00
|
|
|
static void readText(T & x, ReadBuffer & istr, UInt32 precision_, UInt32 scale_, bool csv = false);
|
|
|
|
static bool tryReadText(T & x, ReadBuffer & istr, UInt32 precision_, UInt32 scale_);
|
2018-07-20 19:05:07 +00:00
|
|
|
};
|
|
|
|
|
2018-07-25 19:38:21 +00:00
|
|
|
template <typename T>
|
|
|
|
inline const DataTypeDecimal<T> * checkDecimal(const IDataType & data_type)
|
|
|
|
{
|
|
|
|
return typeid_cast<const DataTypeDecimal<T> *>(&data_type);
|
2018-07-23 20:19:26 +00:00
|
|
|
}
|
2018-07-20 19:05:07 +00:00
|
|
|
|
2018-09-26 14:59:23 +00:00
|
|
|
inline UInt32 getDecimalScale(const IDataType & data_type, UInt32 default_value = std::numeric_limits<UInt32>::max())
|
2018-08-21 18:25:38 +00:00
|
|
|
{
|
2018-08-21 18:55:36 +00:00
|
|
|
if (auto * decimal_type = checkDecimal<Decimal32>(data_type))
|
2018-08-21 18:25:38 +00:00
|
|
|
return decimal_type->getScale();
|
2018-08-21 18:55:36 +00:00
|
|
|
if (auto * decimal_type = checkDecimal<Decimal64>(data_type))
|
2018-08-21 18:25:38 +00:00
|
|
|
return decimal_type->getScale();
|
2018-08-21 18:55:36 +00:00
|
|
|
if (auto * decimal_type = checkDecimal<Decimal128>(data_type))
|
2018-08-21 18:25:38 +00:00
|
|
|
return decimal_type->getScale();
|
2018-09-26 14:59:23 +00:00
|
|
|
return default_value;
|
2018-08-21 18:25:38 +00:00
|
|
|
}
|
|
|
|
|
2019-10-02 05:53:38 +00:00
|
|
|
template <typename T>
|
|
|
|
inline UInt32 getDecimalScale(const DataTypeDecimal<T> & data_type)
|
|
|
|
{
|
|
|
|
return data_type.getScale();
|
|
|
|
}
|
2018-07-20 19:05:07 +00:00
|
|
|
|
2018-08-21 18:25:38 +00:00
|
|
|
template <typename FromDataType, typename ToDataType>
|
2018-09-10 13:52:18 +00:00
|
|
|
inline std::enable_if_t<IsDataTypeDecimal<FromDataType> && IsDataTypeDecimal<ToDataType>, typename ToDataType::FieldType>
|
2018-08-21 18:25:38 +00:00
|
|
|
convertDecimals(const typename FromDataType::FieldType & value, UInt32 scale_from, UInt32 scale_to)
|
|
|
|
{
|
2018-09-25 16:03:50 +00:00
|
|
|
using FromFieldType = typename FromDataType::FieldType;
|
|
|
|
using ToFieldType = typename ToDataType::FieldType;
|
|
|
|
using MaxFieldType = std::conditional_t<(sizeof(FromFieldType) > sizeof(ToFieldType)), FromFieldType, ToFieldType>;
|
|
|
|
using MaxNativeType = typename MaxFieldType::NativeType;
|
2018-08-21 18:25:38 +00:00
|
|
|
|
2018-09-25 16:03:50 +00:00
|
|
|
MaxNativeType converted_value;
|
|
|
|
if (scale_to > scale_from)
|
2018-08-21 18:25:38 +00:00
|
|
|
{
|
2019-11-16 13:54:56 +00:00
|
|
|
converted_value = MaxFieldType::getScaleMultiplier(scale_to - scale_from);
|
2018-09-25 16:03:50 +00:00
|
|
|
if (common::mulOverflow(static_cast<MaxNativeType>(value), converted_value, converted_value))
|
2019-11-05 11:59:46 +00:00
|
|
|
throw Exception(std::string(ToDataType::family_name) + " convert overflow",
|
2019-10-30 10:10:51 +00:00
|
|
|
ErrorCodes::DECIMAL_OVERFLOW);
|
2018-08-21 18:25:38 +00:00
|
|
|
}
|
|
|
|
else
|
2019-11-16 13:54:56 +00:00
|
|
|
converted_value = value / MaxFieldType::getScaleMultiplier(scale_from - scale_to);
|
2018-09-25 16:03:50 +00:00
|
|
|
|
|
|
|
if constexpr (sizeof(FromFieldType) > sizeof(ToFieldType))
|
2018-08-21 18:25:38 +00:00
|
|
|
{
|
2018-09-25 16:03:50 +00:00
|
|
|
if (converted_value < std::numeric_limits<typename ToFieldType::NativeType>::min() ||
|
|
|
|
converted_value > std::numeric_limits<typename ToFieldType::NativeType>::max())
|
2019-11-05 11:59:46 +00:00
|
|
|
throw Exception(std::string(ToDataType::family_name) + " convert overflow",
|
2019-10-30 10:10:51 +00:00
|
|
|
ErrorCodes::DECIMAL_OVERFLOW);
|
2018-08-21 18:25:38 +00:00
|
|
|
}
|
2018-09-25 16:03:50 +00:00
|
|
|
|
|
|
|
return converted_value;
|
2018-08-21 18:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename FromDataType, typename ToDataType>
|
2019-10-30 10:10:51 +00:00
|
|
|
inline std::enable_if_t<IsDataTypeDecimal<FromDataType> && IsNumber<typename ToDataType::FieldType>, typename ToDataType::FieldType>
|
2018-09-25 16:03:50 +00:00
|
|
|
convertFromDecimal(const typename FromDataType::FieldType & value, UInt32 scale)
|
2018-08-21 18:25:38 +00:00
|
|
|
{
|
2018-09-25 16:03:50 +00:00
|
|
|
using FromFieldType = typename FromDataType::FieldType;
|
|
|
|
using ToFieldType = typename ToDataType::FieldType;
|
2018-08-21 18:25:38 +00:00
|
|
|
|
2018-09-25 16:03:50 +00:00
|
|
|
if constexpr (std::is_floating_point_v<ToFieldType>)
|
2019-11-16 13:54:56 +00:00
|
|
|
return static_cast<ToFieldType>(value) / FromFieldType::getScaleMultiplier(scale);
|
2018-08-21 18:25:38 +00:00
|
|
|
else
|
2018-09-25 16:03:50 +00:00
|
|
|
{
|
|
|
|
FromFieldType converted_value = convertDecimals<FromDataType, FromDataType>(value, scale, 0);
|
|
|
|
|
|
|
|
if constexpr (sizeof(FromFieldType) > sizeof(ToFieldType) || !std::numeric_limits<ToFieldType>::is_signed)
|
|
|
|
{
|
|
|
|
if constexpr (std::numeric_limits<ToFieldType>::is_signed)
|
|
|
|
{
|
|
|
|
if (converted_value < std::numeric_limits<ToFieldType>::min() ||
|
|
|
|
converted_value > std::numeric_limits<ToFieldType>::max())
|
2019-11-05 11:59:46 +00:00
|
|
|
throw Exception(std::string(FromDataType::family_name) + " convert overflow",
|
2019-10-30 10:10:51 +00:00
|
|
|
ErrorCodes::DECIMAL_OVERFLOW);
|
2018-09-25 16:03:50 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
using CastIntType = std::conditional_t<std::is_same_v<ToFieldType, UInt64>, Int128, Int64>;
|
|
|
|
|
|
|
|
if (converted_value < 0 ||
|
|
|
|
converted_value > static_cast<CastIntType>(std::numeric_limits<ToFieldType>::max()))
|
2019-11-05 11:59:46 +00:00
|
|
|
throw Exception(std::string(FromDataType::family_name) + " convert overflow",
|
2019-10-30 10:10:51 +00:00
|
|
|
ErrorCodes::DECIMAL_OVERFLOW);
|
2018-09-25 16:03:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return converted_value;
|
|
|
|
}
|
2018-08-21 18:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename FromDataType, typename ToDataType>
|
2019-10-30 10:10:51 +00:00
|
|
|
inline std::enable_if_t<IsNumber<typename FromDataType::FieldType> && IsDataTypeDecimal<ToDataType>, typename ToDataType::FieldType>
|
2018-09-25 16:03:50 +00:00
|
|
|
convertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale)
|
2018-08-21 18:25:38 +00:00
|
|
|
{
|
2018-09-25 16:03:50 +00:00
|
|
|
using FromFieldType = typename FromDataType::FieldType;
|
2019-11-16 13:54:56 +00:00
|
|
|
using ToFieldType = typename ToDataType::FieldType;
|
|
|
|
using ToNativeType = typename ToFieldType::NativeType;
|
2018-08-21 18:25:38 +00:00
|
|
|
|
2018-09-25 16:03:50 +00:00
|
|
|
if constexpr (std::is_floating_point_v<FromFieldType>)
|
2019-05-15 12:28:44 +00:00
|
|
|
{
|
2019-06-13 20:28:14 +00:00
|
|
|
if (!std::isfinite(value))
|
2019-11-05 11:59:46 +00:00
|
|
|
throw Exception(std::string(ToDataType::family_name) + " convert overflow. Cannot convert infinity or NaN to decimal",
|
2019-10-30 10:10:51 +00:00
|
|
|
ErrorCodes::DECIMAL_OVERFLOW);
|
2019-06-13 20:28:14 +00:00
|
|
|
|
2019-11-16 13:54:56 +00:00
|
|
|
auto out = value * ToFieldType::getScaleMultiplier(scale);
|
2019-06-13 08:40:30 +00:00
|
|
|
if constexpr (std::is_same_v<ToNativeType, Int128>)
|
|
|
|
{
|
2019-06-17 14:49:21 +00:00
|
|
|
static constexpr __int128 min_int128 = __int128(0x8000000000000000ll) << 64;
|
|
|
|
static constexpr __int128 max_int128 = (__int128(0x7fffffffffffffffll) << 64) + 0xffffffffffffffffll;
|
2019-06-18 05:25:16 +00:00
|
|
|
if (out <= static_cast<ToNativeType>(min_int128) || out >= static_cast<ToNativeType>(max_int128))
|
2019-11-05 11:59:46 +00:00
|
|
|
throw Exception(std::string(ToDataType::family_name) + " convert overflow. Float is out of Decimal range",
|
2019-10-30 10:10:51 +00:00
|
|
|
ErrorCodes::DECIMAL_OVERFLOW);
|
2019-06-13 08:40:30 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-06-18 05:25:16 +00:00
|
|
|
if (out <= std::numeric_limits<ToNativeType>::min() || out >= std::numeric_limits<ToNativeType>::max())
|
2019-11-05 11:59:46 +00:00
|
|
|
throw Exception(std::string(ToDataType::family_name) + " convert overflow. Float is out of Decimal range",
|
2019-10-30 10:10:51 +00:00
|
|
|
ErrorCodes::DECIMAL_OVERFLOW);
|
2019-06-13 08:40:30 +00:00
|
|
|
}
|
2019-06-17 14:49:21 +00:00
|
|
|
return out;
|
2019-06-13 14:48:13 +00:00
|
|
|
}
|
2018-09-25 16:03:50 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if constexpr (std::is_same_v<FromFieldType, UInt64>)
|
|
|
|
if (value > static_cast<UInt64>(std::numeric_limits<Int64>::max()))
|
|
|
|
return convertDecimals<DataTypeDecimal<Decimal128>, ToDataType>(value, 0, scale);
|
2019-11-20 08:57:19 +00:00
|
|
|
|
2018-09-25 16:03:50 +00:00
|
|
|
return convertDecimals<DataTypeDecimal<Decimal64>, ToDataType>(value, 0, scale);
|
|
|
|
}
|
2018-08-21 18:25:38 +00:00
|
|
|
}
|
|
|
|
|
2018-07-20 19:05:07 +00:00
|
|
|
}
|