Skip to content

Commit 11d690a

Browse files
zhztheplayermeta-codesync[bot]
authored andcommitted
feat: Support casting from large negative-exponent string to decimal (#17665)
Summary: The PR adds support for casting from large negative-exponent string to decimal zero, to align with Spark and Presto. E.g., the PR adds support for `CAST('6E-120' AS DECIMAL(38, 0)) == 0`, instead of returning an error. This is the step 2 in #17593, following the previous fix #17594. Pull Request resolved: #17665 Reviewed By: apurva-meta Differential Revision: D107421146 Pulled By: bikramSingh91 fbshipit-source-id: 11dc31328bed487036abb00f75f9c4fd3b281e76
1 parent 0190e4c commit 11d690a

2 files changed

Lines changed: 33 additions & 15 deletions

File tree

velox/type/DecimalUtil.h

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -181,19 +181,18 @@ class DecimalUtil {
181181
&rescaledValue);
182182
} else {
183183
scaleDifference = -scaleDifference;
184-
VELOX_RETURN_IF(
185-
scaleDifference > LongDecimalType::kMaxPrecision,
186-
Status::UserError(
187-
"Decimal scale difference is too large: {} vs max {}.",
188-
scaleDifference,
189-
LongDecimalType::kMaxPrecision));
190-
const auto scalingFactor = DecimalUtil::kPowersOfTen[scaleDifference];
191-
rescaledValue /= scalingFactor;
192-
int128_t remainder = inputValue % scalingFactor;
193-
if (inputValue >= 0 && remainder >= scalingFactor / 2) {
194-
++rescaledValue;
195-
} else if (remainder <= -scalingFactor / 2) {
196-
--rescaledValue;
184+
if (scaleDifference > LongDecimalType::kMaxPrecision) {
185+
rescaledValue = 0;
186+
} else {
187+
VELOX_DCHECK_LT(scaleDifference, std::size(DecimalUtil::kPowersOfTen));
188+
const auto scalingFactor = DecimalUtil::kPowersOfTen[scaleDifference];
189+
rescaledValue /= scalingFactor;
190+
int128_t remainder = inputValue % scalingFactor;
191+
if (inputValue >= 0 && remainder >= scalingFactor / 2) {
192+
++rescaledValue;
193+
} else if (remainder <= -scalingFactor / 2) {
194+
--rescaledValue;
195+
}
197196
}
198197
}
199198
// Check overflow.

velox/type/tests/DecimalTest.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -795,9 +795,28 @@ TEST(DecimalTest, castFromStringError) {
795795
"9e", 12, 2, "Value is not a number. The exponent part is empty.");
796796
testCastFromString<int64_t>(
797797
"09{xi+yD", 12, 2, "Value is not a number. Chars are invalid.");
798+
}
798799

799-
// Large negative exponent string.
800-
testCastFromString<int128_t>("6E-120", 38, 0, "Value too large.");
800+
TEST(DecimalTest, castFromStringNegativeExponent) {
801+
testCastFromString<int128_t>(
802+
std::vector<std::string>{
803+
"123E-2",
804+
"123E-3",
805+
"567E-3",
806+
"567E-4",
807+
"5E-1",
808+
"4E-1",
809+
"-5E-1",
810+
"-4E-1",
811+
"500E-3",
812+
"499E-3",
813+
"6E-120",
814+
"99999999999999999999999999999999999999E-38",
815+
"50000000000000000000000000000000000000E-38",
816+
"49999999999999999999999999999999999999E-38"},
817+
38,
818+
0,
819+
std::vector<int128_t>{1, 0, 1, 0, 1, 0, -1, 0, 1, 0, 0, 1, 1, 0});
801820
}
802821
} // namespace
803822
} // namespace facebook::velox

0 commit comments

Comments
 (0)