viirya commented on code in PR #59335:
URL: https://github.com/apache/spark/pull/59335#discussion_r4251323795


##########
sql/api/src/main/scala/org/apache/spark/sql/types/Decimal.scala:
##########
@@ -458,6 +458,20 @@ final class Decimal extends Ordered[Decimal] with 
Serializable {
     if (dv.ne(null)) {
       // We get here if either we started with a BigDecimal, or we switched to 
one because we would
       // have overflowed our Long; in either case we must rescale dv to the 
new scale.
+      if (math.abs(dv.scale.toLong - scale) > DecimalType.MAX_PRECISION) {

Review Comment:
   Thanks. #58939 (SPARK-59686) is already working on this path: it clamps 
`RoundBase._scale`, which every branch reads, including the decimal one and the 
generated code. I'd rather leave it there than fold it into SPARK-60133. If 
that PR stalls, I'll pick it up in SPARK-60133.



##########
sql/api/src/main/scala/org/apache/spark/sql/errors/DataTypeErrors.scala:
##########
@@ -207,10 +212,14 @@ private[sql] object DataTypeErrors extends 
DataTypeErrorsBase {
       decimalPrecision: Int,
       decimalScale: Int,
       context: QueryContext): ArithmeticException = {
+    // A huge negative scale (legacy mode only) makes the plain string too 
long to build,
+    // e.g. for 1E+2147483647.
+    val valueString =
+      if (value.scale < -MAX_PLAIN_STRING_TRAILING_ZEROS) value.toString else 
value.toPlainString

Review Comment:
   Good catch. Filed SPARK-60200 to bound the plain string for decimals with a 
huge negative scale in cast-to-string and `ToPrettyString`, possibly with a 
`Decimal`-level helper shared with this error message.



##########
sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastWithAnsiOnSuite.scala:
##########
@@ -481,6 +481,36 @@ class CastWithAnsiOnSuite extends CastSuiteBase with 
QueryErrorsBase {
       castErrMsg("abcd", DecimalType(38, 1)))
   }
 
+  test("SPARK-60119: cast string with a huge exponent to decimal with negative 
scale allowed") {
+    withSQLConf(SQLConf.LEGACY_ALLOW_NEGATIVE_SCALE_OF_DECIMAL_ENABLED.key -> 
"true") {
+      Seq("1e2147483647", "-1e2147483646", "12e2147483647", 
"1e100000000").foreach { str =>
+        checkExceptionInExpression[ArithmeticException](
+          cast(str, DecimalType(10, 2)),
+          "cannot be represented as Decimal(10, 2)")
+      }
+      checkEvaluation(cast("0e2147483647", DecimalType(10, 2)), 
Decimal("0.00"))
+
+      // The value is shown in plain notation unless its scale is hugely 
negative.
+      Seq("1e2147483647" -> "1E+2147483647", "1e40" -> ("1" + "0" * 
40)).foreach {
+        case (str, value) =>
+          if (!isTryCast) {
+            checkError(
+              exception = intercept[SparkArithmeticException](
+                cast(str, DecimalType(10, 2)).eval()),

Review Comment:
   Done, with one change: `checkErrorInExpression` doesn't pass `queryContext` 
to `checkError`, so it expects no context while this error carries an empty 
one, and the check fails. The test now runs `checkError` over the interpreted, 
mutable-projection and unsafe-projection paths itself.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to