MaxGekk commented on code in PR #59956:
URL: https://github.com/apache/spark/pull/59956#discussion_r4426264762


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/intervalExpressions.scala:
##########
@@ -744,6 +744,54 @@ trait IntervalDivide {
     }
   }
 
+  /**
+   * The codegen counterpart of `checkDivideOverflow`: the check that an 
integral divisor does
+   * not overflow the interval type, which only the minimum value divided by 
-1 does.
+   */
+  def checkDivideOverflowCodegen(

Review Comment:
   Thanks for checking the history, you are right. The description now says 
that the interpreted path has raised the interval error class since the check 
was added, that SPARK-50226 only moved it to the `WITH_SUGGESTION` 
sub-condition, and that the generated code had its own copy of the check; 
"Under ANSI mode" is gone, since the expressions do not read the config and the 
non-ANSI golden file shows the same error.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/intervalExpressions.scala:
##########
@@ -744,6 +744,54 @@ trait IntervalDivide {
     }
   }
 
+  /**
+   * The codegen counterpart of `checkDivideOverflow`: the check that an 
integral divisor does
+   * not overflow the interval type, which only the minimum value divided by 
-1 does.
+   */
+  def checkDivideOverflowCodegen(
+      value: String,
+      minValueLiteral: String,
+      num: String,
+      errorContextReference: String): String = {
+    s"""
+       |if ($value == $minValueLiteral && $num == -1)
+       |  throw 
QueryExecutionErrors.withSuggestionIntervalArithmeticOverflowError(
+       |    "try_divide", $errorContextReference);
+       |""".stripMargin
+  }
+
+  /**
+   * Rounds the quotient of the interval by a decimal or a fractional divisor 
in `round`, and
+   * raises the interval overflow error when the rounded quotient does not fit 
the interval
+   * type: the rounding raises an `ArithmeticException` then. A fractional 
quotient that is not
+   * `finite`, e.g. with a NaN divisor, is left to the rounding, which raises 
for it as before.
+   */
+  def checkRoundingOverflow[T](context: QueryContext, finite: Boolean = 
true)(round: => T): T = {

Review Comment:
   Done in bda6facf7bc. `IntervalMathUtils.divide` has an overload per interval 
type (months as `Int`, micros as `Long`) and kind of divisor (`Long`, 
`Decimal`, `Double`), each with the division by zero check, the overflow checks 
and the error with the query context. Both expressions call them from 
`evalFunc`, and `doGenCode`, now shared in the `IntervalDivide` trait, is a 
single `defineCodeGen` call that widens the divisor to the overload's type. The 
trait's helpers and the generated try/catch are gone, as in `Add` and 
`Subtract` with `addExact`.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/intervalExpressions.scala:
##########
@@ -744,6 +744,54 @@ trait IntervalDivide {
     }
   }
 
+  /**
+   * The codegen counterpart of `checkDivideOverflow`: the check that an 
integral divisor does
+   * not overflow the interval type, which only the minimum value divided by 
-1 does.
+   */
+  def checkDivideOverflowCodegen(
+      value: String,
+      minValueLiteral: String,
+      num: String,
+      errorContextReference: String): String = {
+    s"""
+       |if ($value == $minValueLiteral && $num == -1)
+       |  throw 
QueryExecutionErrors.withSuggestionIntervalArithmeticOverflowError(
+       |    "try_divide", $errorContextReference);
+       |""".stripMargin
+  }
+
+  /**
+   * Rounds the quotient of the interval by a decimal or a fractional divisor 
in `round`, and
+   * raises the interval overflow error when the rounded quotient does not fit 
the interval
+   * type: the rounding raises an `ArithmeticException` then. A fractional 
quotient that is not
+   * `finite`, e.g. with a NaN divisor, is left to the rounding, which raises 
for it as before.
+   */
+  def checkRoundingOverflow[T](context: QueryContext, finite: Boolean = 
true)(round: => T): T = {
+    try {

Review Comment:
   Reused in bda6facf7bc: `withOverflow` takes a `context` parameter now, with 
`null` as the default for the existing callers, and the decimal and fractional 
divisions go through it with `"try_divide"` and the query context.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/intervalExpressions.scala:
##########
@@ -744,6 +744,54 @@ trait IntervalDivide {
     }
   }
 
+  /**
+   * The codegen counterpart of `checkDivideOverflow`: the check that an 
integral divisor does
+   * not overflow the interval type, which only the minimum value divided by 
-1 does.
+   */
+  def checkDivideOverflowCodegen(
+      value: String,
+      minValueLiteral: String,
+      num: String,
+      errorContextReference: String): String = {
+    s"""
+       |if ($value == $minValueLiteral && $num == -1)
+       |  throw 
QueryExecutionErrors.withSuggestionIntervalArithmeticOverflowError(
+       |    "try_divide", $errorContextReference);
+       |""".stripMargin
+  }
+
+  /**
+   * Rounds the quotient of the interval by a decimal or a fractional divisor 
in `round`, and
+   * raises the interval overflow error when the rounded quotient does not fit 
the interval
+   * type: the rounding raises an `ArithmeticException` then. A fractional 
quotient that is not
+   * `finite`, e.g. with a NaN divisor, is left to the rounding, which raises 
for it as before.
+   */
+  def checkRoundingOverflow[T](context: QueryContext, finite: Boolean = 
true)(round: => T): T = {
+    try {
+      round
+    } catch {
+      case _: ArithmeticException if finite =>
+        throw 
QueryExecutionErrors.withSuggestionIntervalArithmeticOverflowError(
+          "try_divide", context)
+    }
+  }
+
+  /** The codegen counterpart of `checkRoundingOverflow`, `finite` being a 
Java expression. */
+  def checkRoundingOverflowCodegen(
+      code: String,
+      errorContextReference: String,
+      finite: String = "true"): String = {

Review Comment:
   Gone with item 5 in bda6facf7bc: the decimal overloads wrap the rounding in 
`withOverflow` without a NaN check, and only the `Double` overloads test the 
quotient for NaN.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/intervalExpressions.scala:
##########
@@ -812,32 +864,34 @@ case class DivideYMInterval(
         }
         val javaType = CodeGenerator.javaType(dataType)
         nullSafeCodeGen(ctx, ev, (m, n) => {
-          val checkIntegralDivideOverflow =
-            s"""
-               |if ($m == ${Int.MinValue} && $n == -1)
-               |  throw 
QueryExecutionErrors.overflowInIntegralDivideError($errorContext);
-               |""".stripMargin
           // Similarly to non-codegen code. The result of `divide(Int, Long, 
...)` must fit
           // to `Int`. Casting to `Int` is safe here.
           s"""
              |${divideByZeroCheckCodegen(right.dataType, n, errorContext)}
-             |$checkIntegralDivideOverflow
+             |${checkDivideOverflowCodegen(m, Int.MinValue.toString, n, 
errorContext)}
              |${ev.value} = ($javaType)$math.divide($m, $n, 
java.math.RoundingMode.HALF_UP);
           """.stripMargin
         })
       case _: DecimalType =>
         nullSafeCodeGen(ctx, ev, (m, n) =>
           s"""
              |${divideByZeroCheckCodegen(right.dataType, n, errorContext)}
-             |${ev.value} = ((new 
Decimal()).set($m).$$div($n)).toJavaBigDecimal()
-             |  .setScale(0, java.math.RoundingMode.HALF_UP).intValueExact();
+             |${checkRoundingOverflowCodegen(
+                  s"""
+                     |${ev.value} = ((new 
Decimal()).set($m).$$div($n)).toJavaBigDecimal()
+                     |  .setScale(0, 
java.math.RoundingMode.HALF_UP).intValueExact();
+                   """.stripMargin, errorContext)}

Review Comment:
   Gone with item 5 in bda6facf7bc: `doGenCode` is a one-line `defineCodeGen` 
call, with no nested strings.



-- 
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