Skip to content

Commit 0547b6a

Browse files
viiryaIsaac
andcommitted
Skip the fast-fail for zero
Zero fits any decimal type whatever its exponent, so strings like '0e39' should not be rejected as out of range. Co-authored-by: Isaac <no-reply@databricks.com>
1 parent 6d4638e commit 0547b6a

4 files changed

Lines changed: 23 additions & 8 deletions

File tree

‎sql/api/src/main/scala/org/apache/spark/sql/types/Decimal.scala‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -649,8 +649,10 @@ object Decimal {
649649
try {
650650
val bigDecimal = stringToJavaBigDecimal(str)
651651
// We fast fail because constructing a very large JavaBigDecimal to Decimal is very slow.
652-
// For example: Decimal("6.0790316E+25569151")
653-
if (numDigitsInIntegralPart(bigDecimal) > DecimalType.MAX_PRECISION &&
652+
// For example: Decimal("6.0790316E+25569151"). Zero fits any decimal type whatever its
653+
// exponent, e.g. "0e39", so it is not checked.
654+
if (bigDecimal.signum != 0 &&
655+
numDigitsInIntegralPart(bigDecimal) > DecimalType.MAX_PRECISION &&
654656
!SqlApiConf.get.allowNegativeScaleOfDecimalEnabled) {
655657
null
656658
} else {
@@ -669,8 +671,10 @@ object Decimal {
669671
try {
670672
val bigDecimal = stringToJavaBigDecimal(str)
671673
// We fast fail because constructing a very large JavaBigDecimal to Decimal is very slow.
672-
// For example: Decimal("6.0790316E+25569151")
673-
if (numDigitsInIntegralPart(bigDecimal) > DecimalType.MAX_PRECISION &&
674+
// For example: Decimal("6.0790316E+25569151"). Zero fits any decimal type whatever its
675+
// exponent, e.g. "0e39", so it is not checked.
676+
if (bigDecimal.signum != 0 &&
677+
numDigitsInIntegralPart(bigDecimal) > DecimalType.MAX_PRECISION &&
674678
!SqlApiConf.get.allowNegativeScaleOfDecimalEnabled) {
675679
throw DataTypeErrors.outOfDecimalTypeRangeError(str)
676680
} else {

‎sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastWithAnsiOffSuite.scala‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,9 +559,12 @@ class CastWithAnsiOffSuite extends CastSuiteBase {
559559
Decimal("60000000000000000000000000000000000000"))
560560
checkEvaluation(cast("6E+38", DecimalType(38, 0)), null)
561561
checkEvaluation(cast("6E+37", DecimalType(38, 1)), null)
562-
Seq("1e2147483647", "0e2147483647", "1.5e2147483647", "1e2147483648").foreach { s =>
562+
Seq("1e2147483647", "1.5e2147483647", "1e2147483648").foreach { s =>
563563
checkEvaluation(cast(s, DecimalType(10, 2)), null)
564564
}
565+
Seq("0e39", "0e2147483647", "0.0e2147483648").foreach { s =>
566+
checkEvaluation(cast(s, DecimalType(10, 2)), Decimal("0.00"))
567+
}
565568

566569
checkEvaluation(cast("abcd", DecimalType(38, 1)), null)
567570
}

‎sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastWithAnsiOnSuite.scala‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,11 +475,14 @@ class CastWithAnsiOnSuite extends CastSuiteBase with QueryErrorsBase {
475475
checkExceptionInExpression[ArithmeticException](
476476
cast("6E+37", DecimalType(38, 1)),
477477
"cannot be represented as Decimal(38, 1)")
478-
Seq("1e2147483647", "0e2147483647", "1.5e2147483647", "1e2147483648").foreach { s =>
478+
Seq("1e2147483647", "1.5e2147483647", "1e2147483648").foreach { s =>
479479
checkExceptionInExpression[ArithmeticException](
480480
cast(s, DecimalType(10, 2)),
481481
"NUMERIC_OUT_OF_SUPPORTED_RANGE")
482482
}
483+
Seq("0e39", "0e2147483647", "0.0e2147483648").foreach { s =>
484+
checkEvaluation(cast(s, DecimalType(10, 2)), Decimal("0.00"))
485+
}
483486

484487
checkExceptionInExpression[NumberFormatException](
485488
cast("abcd", DecimalType(38, 1)),

‎sql/catalyst/src/test/scala/org/apache/spark/sql/types/DecimalSuite.scala‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,15 +448,20 @@ class DecimalSuite extends SparkFunSuite with PrivateMethodTester with SQLHelper
448448

449449
test("UTF8String to Decimal with exponent near Int.MaxValue") {
450450
// The number of integral digits (precision - scale) of these values overflows Int.
451-
Seq("1e2147483647", "-1E+2147483647", "0e2147483647", "12e2147483647",
452-
"1.5e2147483647", "1e2147483648").foreach { string =>
451+
Seq("1e2147483647", "-1E+2147483647", "12e2147483647", "1.5e2147483647",
452+
"1e2147483648").foreach { string =>
453453
assert(Decimal.fromString(UTF8String.fromString(string)) === null)
454454
checkError(
455455
exception = intercept[SparkArithmeticException](
456456
Decimal.fromStringANSI(UTF8String.fromString(string))),
457457
condition = "NUMERIC_OUT_OF_SUPPORTED_RANGE",
458458
parameters = Map("value" -> string))
459459
}
460+
// Zero fits any decimal type whatever its exponent.
461+
Seq("0e39", "-0E+100", "0e2147483647", "0.0e2147483648").foreach { string =>
462+
assert(Decimal.fromString(UTF8String.fromString(string)) === Decimal(0))
463+
assert(Decimal.fromStringANSI(UTF8String.fromString(string)) === Decimal(0))
464+
}
460465
}
461466

462467
// 18 is a max number of digits in Decimal's compact long

0 commit comments

Comments
 (0)