From 215acf5e5bc0f77e392c6dca7d002dcc5889beb0 Mon Sep 17 00:00:00 2001 From: lhuang09287750 Date: Sun, 9 Oct 2022 05:30:01 +0000 Subject: [PATCH] check the result of conversion for decimal IN float --- src/Interpreters/ActionsVisitor.cpp | 24 +++++++++++++++++-- src/Interpreters/convertFieldToType.cpp | 13 +++++----- ...ecimal_in_floating_point_literal.reference | 1 + 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/Interpreters/ActionsVisitor.cpp b/src/Interpreters/ActionsVisitor.cpp index 54faf37f236..980207c7f9c 100644 --- a/src/Interpreters/ActionsVisitor.cpp +++ b/src/Interpreters/ActionsVisitor.cpp @@ -91,15 +91,35 @@ static size_t getTypeDepth(const DataTypePtr & type) return 0; } +template +static bool decimalEqualsFloat(Field field, Float64 float_value) +{ + auto decimal_field = field.get>(); + auto decimal_to_float = DecimalUtils::convertTo(decimal_field.getValue(), decimal_field.getScale()); + return decimal_to_float == float_value; +} + /// Applies stricter rules than convertFieldToType: /// Doesn't allow : -/// - loss of precision with `Decimals` +/// - loss of precision converting to Decimal static bool convertFieldToTypeStrict(const Field & from_value, const IDataType & to_type, Field & result_value) { result_value = convertFieldToType(from_value, to_type); if (Field::isDecimal(from_value.getType()) && Field::isDecimal(result_value.getType())) return applyVisitor(FieldVisitorAccurateEquals{}, from_value, result_value); - + if (from_value.getType() == Field::Types::Float64 && Field::isDecimal(result_value.getType())) + { + /// Convert back to Float64 and compare + if (result_value.getType() == Field::Types::Decimal32) + return decimalEqualsFloat(result_value, from_value.get()); + if (result_value.getType() == Field::Types::Decimal64) + return decimalEqualsFloat(result_value, from_value.get()); + if (result_value.getType() == Field::Types::Decimal128) + return decimalEqualsFloat(result_value, from_value.get()); + if (result_value.getType() == Field::Types::Decimal256) + return decimalEqualsFloat(result_value, from_value.get()); + throw Exception(ErrorCodes::LOGICAL_ERROR, "Unknown decimal type {}", result_value.getTypeName()); + } return true; } diff --git a/src/Interpreters/convertFieldToType.cpp b/src/Interpreters/convertFieldToType.cpp index b6c72340472..55156cde7be 100644 --- a/src/Interpreters/convertFieldToType.cpp +++ b/src/Interpreters/convertFieldToType.cpp @@ -112,15 +112,16 @@ Field convertDecimalToDecimalType(const Field & from, const DataTypeDecimal & template Field convertFloatToDecimalType(const Field & from, const DataTypeDecimal & type) { - From dValue = from.get(); - if (!type.canStoreWhole(dValue)) + From value = from.get(); + if (!type.canStoreWhole(value)) throw Exception("Number is too big to place in " + type.getName(), ErrorCodes::ARGUMENT_OUT_OF_BOUND); - String sValue = convertFieldToString(from); - int fromScale = sValue.length()- sValue.find('.') - 1; + //String sValue = convertFieldToString(from); + //int fromScale = sValue.length()- sValue.find('.') - 1; + UInt32 scale = type.getScale(); - auto scaledValue = convertToDecimal, DataTypeDecimal>(dValue, fromScale); - return DecimalField(scaledValue, fromScale); + auto scaled_value = convertToDecimal, DataTypeDecimal>(value, scale); + return DecimalField(scaled_value, scale); } template diff --git a/tests/queries/0_stateless/02428_decimal_in_floating_point_literal.reference b/tests/queries/0_stateless/02428_decimal_in_floating_point_literal.reference index 3c58c27aef9..378b7d8cec4 100644 --- a/tests/queries/0_stateless/02428_decimal_in_floating_point_literal.reference +++ b/tests/queries/0_stateless/02428_decimal_in_floating_point_literal.reference @@ -18,3 +18,4 @@ 1 1 1 +1