mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-25 00:52:02 +00:00
Added tryParseDecimal functions
This commit is contained in:
parent
17b43ca721
commit
51f53ce8e9
@ -206,23 +206,32 @@ inline typename DecimalType::NativeType getFractionalPart(const DecimalType & de
|
||||
}
|
||||
|
||||
/// Decimal to integer/float conversion
|
||||
template <typename To, typename DecimalType>
|
||||
To convertTo(const DecimalType & decimal, size_t scale)
|
||||
template <typename To, typename DecimalType, typename ReturnType>
|
||||
ReturnType convertToImpl(const DecimalType & decimal, size_t scale, To &result)
|
||||
{
|
||||
using NativeT = typename DecimalType::NativeType;
|
||||
static constexpr bool throw_exception = std::is_same_v<ReturnType, void>;
|
||||
|
||||
if constexpr (std::is_floating_point_v<To>)
|
||||
{
|
||||
return static_cast<To>(decimal.value) / static_cast<To>(scaleMultiplier<NativeT>(scale));
|
||||
result = static_cast<To>(decimal.value) / static_cast<To>(scaleMultiplier<NativeT>(scale));
|
||||
}
|
||||
else if constexpr (is_integer_v<To> && (sizeof(To) >= sizeof(NativeT)))
|
||||
{
|
||||
NativeT whole = getWholePart(decimal, scale);
|
||||
|
||||
if constexpr (is_unsigned_v<To>)
|
||||
{
|
||||
if (whole < 0)
|
||||
{
|
||||
if constexpr (throw_exception)
|
||||
throw Exception("Convert overflow", ErrorCodes::DECIMAL_OVERFLOW);
|
||||
return static_cast<To>(whole);
|
||||
else
|
||||
return ReturnType(true);
|
||||
}
|
||||
}
|
||||
|
||||
result = static_cast<To>(whole);
|
||||
}
|
||||
else if constexpr (is_integer_v<To>)
|
||||
{
|
||||
@ -235,9 +244,34 @@ To convertTo(const DecimalType & decimal, size_t scale)
|
||||
static const constexpr CastTo max_to = std::numeric_limits<ToNativeT>::max();
|
||||
|
||||
if (whole < min_to || whole > max_to)
|
||||
{
|
||||
if constexpr (throw_exception)
|
||||
throw Exception("Convert overflow", ErrorCodes::DECIMAL_OVERFLOW);
|
||||
return static_cast<CastTo>(whole);
|
||||
else
|
||||
return ReturnType(true);
|
||||
}
|
||||
|
||||
result = static_cast<CastTo>(whole);
|
||||
}
|
||||
|
||||
return ReturnType(true);
|
||||
}
|
||||
|
||||
|
||||
template <typename To, typename DecimalType>
|
||||
To convertTo(const DecimalType & decimal, size_t scale)
|
||||
{
|
||||
To result;
|
||||
|
||||
convertToImpl<To, DecimalType, void>(decimal, scale, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename To, typename DecimalType>
|
||||
bool tryConvertTo(const DecimalType & decimal, size_t scale, To& result)
|
||||
{
|
||||
return convertToImpl<To, DecimalType, bool>(decimal, scale, result);
|
||||
}
|
||||
|
||||
template <bool is_multiply, bool is_division, typename T, typename U, template <typename> typename DecimalType>
|
||||
|
@ -96,22 +96,29 @@ inline UInt32 getDecimalScale(const DataTypeDecimal<T> & data_type)
|
||||
return data_type.getScale();
|
||||
}
|
||||
|
||||
template <typename FromDataType, typename ToDataType>
|
||||
inline std::enable_if_t<IsDataTypeDecimal<FromDataType> && IsDataTypeDecimal<ToDataType>, typename ToDataType::FieldType>
|
||||
convertDecimals(const typename FromDataType::FieldType & value, UInt32 scale_from, UInt32 scale_to)
|
||||
template <typename FromDataType, typename ToDataType, typename ReturnType = void>
|
||||
inline std::enable_if_t<IsDataTypeDecimal<FromDataType> && IsDataTypeDecimal<ToDataType>, ReturnType>
|
||||
convertDecimalsImpl(const typename FromDataType::FieldType & value, UInt32 scale_from, UInt32 scale_to, typename ToDataType::FieldType& result)
|
||||
{
|
||||
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;
|
||||
|
||||
static constexpr bool throw_exception = std::is_same_v<ReturnType, void>;
|
||||
|
||||
MaxNativeType converted_value;
|
||||
if (scale_to > scale_from)
|
||||
{
|
||||
converted_value = DecimalUtils::scaleMultiplier<MaxNativeType>(scale_to - scale_from);
|
||||
if (common::mulOverflow(static_cast<MaxNativeType>(value.value), converted_value, converted_value))
|
||||
{
|
||||
if constexpr (throw_exception)
|
||||
throw Exception(std::string(ToDataType::family_name) + " convert overflow",
|
||||
ErrorCodes::DECIMAL_OVERFLOW);
|
||||
else
|
||||
return ReturnType(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
converted_value = value.value / DecimalUtils::scaleMultiplier<MaxNativeType>(scale_from - scale_to);
|
||||
@ -120,35 +127,87 @@ convertDecimals(const typename FromDataType::FieldType & value, UInt32 scale_fro
|
||||
{
|
||||
if (converted_value < std::numeric_limits<typename ToFieldType::NativeType>::min() ||
|
||||
converted_value > std::numeric_limits<typename ToFieldType::NativeType>::max())
|
||||
{
|
||||
if constexpr (throw_exception)
|
||||
throw Exception(std::string(ToDataType::family_name) + " convert overflow",
|
||||
ErrorCodes::DECIMAL_OVERFLOW);
|
||||
else
|
||||
return ReturnType(false);
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<typename ToFieldType::NativeType>(converted_value);
|
||||
result = static_cast<typename ToFieldType::NativeType>(converted_value);
|
||||
|
||||
return ReturnType(true);
|
||||
}
|
||||
|
||||
template <typename FromDataType, typename ToDataType>
|
||||
inline std::enable_if_t<IsDataTypeDecimal<FromDataType> && IsDataTypeDecimal<ToDataType>, typename ToDataType::FieldType>
|
||||
convertDecimals(const typename FromDataType::FieldType & value, UInt32 scale_from, UInt32 scale_to)
|
||||
{
|
||||
using ToFieldType = typename ToDataType::FieldType;
|
||||
ToFieldType result;
|
||||
|
||||
convertDecimalsImpl<FromDataType, ToDataType, void>(value, scale_from, scale_to, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename FromDataType, typename ToDataType>
|
||||
inline std::enable_if_t<IsDataTypeDecimal<FromDataType> && IsDataTypeDecimal<ToDataType>, bool>
|
||||
tryConvertDecimals(const typename FromDataType::FieldType & value, UInt32 scale_from, UInt32 scale_to, typename ToDataType::FieldType& result)
|
||||
{
|
||||
return convertDecimalsImpl<FromDataType, ToDataType, bool>(value, scale_from, scale_to, result);
|
||||
}
|
||||
|
||||
template <typename FromDataType, typename ToDataType, typename ReturnType>
|
||||
inline std::enable_if_t<IsDataTypeDecimal<FromDataType> && IsNumber<typename ToDataType::FieldType>, ReturnType>
|
||||
convertFromDecimalImpl(const typename FromDataType::FieldType & value, UInt32 scale, typename ToDataType::FieldType& result)
|
||||
{
|
||||
using FromFieldType = typename FromDataType::FieldType;
|
||||
using ToFieldType = typename ToDataType::FieldType;
|
||||
|
||||
return DecimalUtils::convertToImpl<ToFieldType, FromFieldType, ReturnType>(value, scale, result);
|
||||
}
|
||||
|
||||
template <typename FromDataType, typename ToDataType>
|
||||
inline std::enable_if_t<IsDataTypeDecimal<FromDataType> && IsNumber<typename ToDataType::FieldType>, typename ToDataType::FieldType>
|
||||
convertFromDecimal(const typename FromDataType::FieldType & value, UInt32 scale)
|
||||
{
|
||||
using ToFieldType = typename ToDataType::FieldType;
|
||||
typename ToDataType::FieldType result;
|
||||
|
||||
return DecimalUtils::convertTo<ToFieldType>(value, scale);
|
||||
convertFromDecimalImpl<FromDataType, ToDataType, void>(value, scale, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename FromDataType, typename ToDataType>
|
||||
inline std::enable_if_t<IsNumber<typename FromDataType::FieldType> && IsDataTypeDecimal<ToDataType>, typename ToDataType::FieldType>
|
||||
convertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale)
|
||||
inline std::enable_if_t<IsDataTypeDecimal<FromDataType> && IsNumber<typename ToDataType::FieldType>, bool>
|
||||
tryConvertFromDecimal(const typename FromDataType::FieldType & value, UInt32 scale, typename ToDataType::FieldType& result)
|
||||
{
|
||||
return convertFromDecimalImpl<FromDataType, ToDataType, bool>(value, scale, result);
|
||||
}
|
||||
|
||||
template <typename FromDataType, typename ToDataType, typename ReturnType>
|
||||
inline std::enable_if_t<IsNumber<typename FromDataType::FieldType> && IsDataTypeDecimal<ToDataType>, ReturnType>
|
||||
convertToDecimalImpl(const typename FromDataType::FieldType & value, UInt32 scale, typename ToDataType::FieldType& result)
|
||||
{
|
||||
using FromFieldType = typename FromDataType::FieldType;
|
||||
using ToFieldType = typename ToDataType::FieldType;
|
||||
using ToNativeType = typename ToFieldType::NativeType;
|
||||
|
||||
static constexpr bool throw_exception = std::is_same_v<ReturnType, void>;
|
||||
|
||||
if constexpr (std::is_floating_point_v<FromFieldType>)
|
||||
{
|
||||
if (!std::isfinite(value))
|
||||
{
|
||||
if constexpr (throw_exception)
|
||||
throw Exception(std::string(ToDataType::family_name) + " convert overflow. Cannot convert infinity or NaN to decimal",
|
||||
ErrorCodes::DECIMAL_OVERFLOW);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
auto out = value * static_cast<FromFieldType>(DecimalUtils::scaleMultiplier<ToNativeType>(scale));
|
||||
if constexpr (std::is_same_v<ToNativeType, Int128>)
|
||||
@ -157,29 +216,60 @@ convertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale)
|
||||
static constexpr Int128 max_int128 = maxInt128();
|
||||
|
||||
if (out <= static_cast<ToNativeType>(min_int128) || out >= static_cast<ToNativeType>(max_int128))
|
||||
{
|
||||
if constexpr (throw_exception)
|
||||
throw Exception(std::string(ToDataType::family_name) + " convert overflow. Float is out of Decimal range",
|
||||
ErrorCodes::DECIMAL_OVERFLOW);
|
||||
else
|
||||
return ReturnType(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (out <= static_cast<FromFieldType>(std::numeric_limits<ToNativeType>::min()) ||
|
||||
out >= static_cast<FromFieldType>(std::numeric_limits<ToNativeType>::max()))
|
||||
{
|
||||
if constexpr (throw_exception)
|
||||
throw Exception(std::string(ToDataType::family_name) + " convert overflow. Float is out of Decimal range",
|
||||
ErrorCodes::DECIMAL_OVERFLOW);
|
||||
else
|
||||
return ReturnType(false);
|
||||
}
|
||||
return static_cast<ToNativeType>(out);
|
||||
}
|
||||
|
||||
result = static_cast<ToNativeType>(out);
|
||||
|
||||
return ReturnType(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (is_big_int_v<FromFieldType>)
|
||||
return convertDecimals<DataTypeDecimal<Decimal256>, ToDataType>(static_cast<Int256>(value), 0, scale);
|
||||
return ReturnType(convertDecimalsImpl<DataTypeDecimal<Decimal256>, ToDataType, ReturnType>(static_cast<Int256>(value), 0, scale, result));
|
||||
else if constexpr (std::is_same_v<FromFieldType, UInt64>)
|
||||
return convertDecimals<DataTypeDecimal<Decimal128>, ToDataType>(value, 0, scale);
|
||||
return ReturnType(convertDecimalsImpl<DataTypeDecimal<Decimal128>, ToDataType, ReturnType>(value, 0, scale, result));
|
||||
else
|
||||
return convertDecimals<DataTypeDecimal<Decimal64>, ToDataType>(value, 0, scale);
|
||||
return ReturnType(convertDecimalsImpl<DataTypeDecimal<Decimal64>, ToDataType, ReturnType>(value, 0, scale, result));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FromDataType, typename ToDataType>
|
||||
inline std::enable_if_t<IsNumber<typename FromDataType::FieldType> && IsDataTypeDecimal<ToDataType>, typename ToDataType::FieldType>
|
||||
convertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale)
|
||||
{
|
||||
typename ToDataType::FieldType result;
|
||||
|
||||
convertToDecimalImpl<FromDataType, ToDataType, void>(value, scale, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename FromDataType, typename ToDataType>
|
||||
inline std::enable_if_t<IsNumber<typename FromDataType::FieldType> && IsDataTypeDecimal<ToDataType>, bool>
|
||||
tryConvertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale, typename ToDataType::FieldType& result)
|
||||
{
|
||||
return convertToDecimalImpl<FromDataType, ToDataType, bool>(value, scale, result);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline DataTypePtr createDecimalMaxPrecision(UInt64 scale)
|
||||
{
|
||||
|
@ -191,7 +191,24 @@ struct ConvertImpl
|
||||
{
|
||||
if constexpr (IsDataTypeDecimal<FromDataType> || IsDataTypeDecimal<ToDataType>)
|
||||
{
|
||||
try
|
||||
if constexpr (std::is_same_v<Additions, AccurateOrNullConvertStrategyAdditions>)
|
||||
{
|
||||
ToFieldType result;
|
||||
bool convert_result = false;
|
||||
|
||||
if constexpr (IsDataTypeDecimal<FromDataType> && IsDataTypeDecimal<ToDataType>)
|
||||
tryConvertDecimals<FromDataType, ToDataType>(vec_from[i], vec_from.getScale(), vec_to.getScale(), result);
|
||||
else if constexpr (IsDataTypeDecimal<FromDataType> && IsDataTypeNumber<ToDataType>)
|
||||
tryConvertFromDecimal<FromDataType, ToDataType>(vec_from[i], vec_from.getScale(), result);
|
||||
else if constexpr (IsDataTypeNumber<FromDataType> && IsDataTypeDecimal<ToDataType>)
|
||||
tryConvertToDecimal<FromDataType, ToDataType>(vec_from[i], vec_to.getScale(), result);
|
||||
|
||||
if (convert_result)
|
||||
vec_to[i] = result;
|
||||
else
|
||||
(*vec_null_map_to)[i] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (IsDataTypeDecimal<FromDataType> && IsDataTypeDecimal<ToDataType>)
|
||||
vec_to[i] = convertDecimals<FromDataType, ToDataType>(vec_from[i], vec_from.getScale(), vec_to.getScale());
|
||||
@ -200,23 +217,9 @@ struct ConvertImpl
|
||||
else if constexpr (IsDataTypeNumber<FromDataType> && IsDataTypeDecimal<ToDataType>)
|
||||
vec_to[i] = convertToDecimal<FromDataType, ToDataType>(vec_from[i], vec_to.getScale());
|
||||
else
|
||||
{
|
||||
throw Exception("Unsupported data type in conversion function", ErrorCodes::CANNOT_CONVERT_TYPE);
|
||||
}
|
||||
}
|
||||
catch (const Exception & exception)
|
||||
{
|
||||
if constexpr (std::is_same_v<Additions, AccurateOrNullConvertStrategyAdditions>)
|
||||
{
|
||||
if (exception.code() == ErrorCodes::CANNOT_CONVERT_TYPE || exception.code() == ErrorCodes::DECIMAL_OVERFLOW)
|
||||
(*vec_null_map_to)[i] = true;
|
||||
else
|
||||
throw exception;
|
||||
}
|
||||
else
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/// If From Data is Nan or Inf and we convert to integer type, throw exception
|
||||
|
Loading…
Reference in New Issue
Block a user