You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@gluten.apache.org by ch...@apache.org on 2026/04/15 11:17:33 UTC

(gluten) 10/29: [GLUTEN-10134][VL] Add ANSI mode: checked_remainder, decimal sum/avg overflow, make_date

This is an automated email from the ASF dual-hosted git repository.

changchen pushed a commit to branch feature/ansi-ci-baseline
in repository https://gitbox.apache.org/repos/asf/gluten.git

commit 44d76052952fddcfd45e0c472ee7b537adda489e
Author: Chang chen <ch...@microsoft.com>
AuthorDate: Wed Apr 1 08:56:48 2026 +0000

    [GLUTEN-10134][VL] Add ANSI mode: checked_remainder, decimal sum/avg overflow, make_date
    
    - Add CHECKED_REMAINDER constant and ExpressionConverter mapping for Remainder
    - Add Remainder to withAnsiEvalMode/withTryEvalMode in Spark40/41 shims
    - Add remainder ANSI test in ArithmeticAnsiValidateSuite
    - Fix spotless formatting in UnaryExpressionTransformer
    
    Batch 4 of Phase 1 ANSI mode support (Issue #10134):
    - Task 8: CheckedRemainder function (integer div-by-zero throws exception)
    - Task 9: Decimal sum/avg overflow throws exception in ANSI mode
    - Task 10: make_date throws exception on invalid date in ANSI mode
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
---
 .../apache/gluten/functions/ArithmeticAnsiValidateSuite.scala | 11 +++++++++++
 .../org/apache/gluten/expression/ExpressionConverter.scala    |  8 ++++++++
 .../apache/gluten/expression/UnaryExpressionTransformer.scala | 10 ++--------
 .../scala/org/apache/gluten/expression/ExpressionNames.scala  |  1 +
 .../org/apache/gluten/sql/shims/spark40/Spark40Shims.scala    |  2 ++
 .../org/apache/gluten/sql/shims/spark41/Spark41Shims.scala    |  2 ++
 6 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/backends-velox/src/test/scala/org/apache/gluten/functions/ArithmeticAnsiValidateSuite.scala b/backends-velox/src/test/scala/org/apache/gluten/functions/ArithmeticAnsiValidateSuite.scala
index a1633c4cb4..0fb59fe9c0 100644
--- a/backends-velox/src/test/scala/org/apache/gluten/functions/ArithmeticAnsiValidateSuite.scala
+++ b/backends-velox/src/test/scala/org/apache/gluten/functions/ArithmeticAnsiValidateSuite.scala
@@ -100,4 +100,15 @@ class ArithmeticAnsiValidateSuite extends FunctionsValidateSuite {
     }
   }
 
+  test("remainder") {
+    runQueryAndCompare("SELECT int_field1 % 3 FROM datatab WHERE int_field1 IS NOT NULL") {
+      checkGlutenPlan[ProjectExecTransformer]
+    }
+    if (isSparkVersionGE("3.4")) {
+      intercept[SparkException] {
+        sql("SELECT 1 % 0").collect()
+      }
+    }
+  }
+
 }
diff --git a/gluten-substrait/src/main/scala/org/apache/gluten/expression/ExpressionConverter.scala b/gluten-substrait/src/main/scala/org/apache/gluten/expression/ExpressionConverter.scala
index 73f7b86996..fd88427e1d 100644
--- a/gluten-substrait/src/main/scala/org/apache/gluten/expression/ExpressionConverter.scala
+++ b/gluten-substrait/src/main/scala/org/apache/gluten/expression/ExpressionConverter.scala
@@ -791,6 +791,14 @@ object ExpressionConverter extends SQLConfHelper with Logging {
           i,
           ExpressionNames.CHECKED_DIV
         )
+      case a: Remainder =>
+        BackendsApiManager.getSparkPlanExecApiInstance.genArithmeticTransformer(
+          substraitExprName,
+          replaceWithExpressionTransformer0(a.left, attributeSeq, expressionsMap),
+          replaceWithExpressionTransformer0(a.right, attributeSeq, expressionsMap),
+          a,
+          ExpressionNames.CHECKED_REMAINDER
+        )
       case tryEval: TryEval =>
         // This is a placeholder to handle try_eval(other expressions).
         BackendsApiManager.getSparkPlanExecApiInstance.genTryEvalTransformer(
diff --git a/gluten-substrait/src/main/scala/org/apache/gluten/expression/UnaryExpressionTransformer.scala b/gluten-substrait/src/main/scala/org/apache/gluten/expression/UnaryExpressionTransformer.scala
index a076c46b40..52cd0115db 100644
--- a/gluten-substrait/src/main/scala/org/apache/gluten/expression/UnaryExpressionTransformer.scala
+++ b/gluten-substrait/src/main/scala/org/apache/gluten/expression/UnaryExpressionTransformer.scala
@@ -46,15 +46,9 @@ case class CastTransformer(substraitExprName: String, child: ExpressionTransform
   override def doTransform(context: SubstraitContext): ExpressionNode = {
     original.dataType match {
       case CharType(length) =>
-        buildCastWithWriteSideCheck(
-          context,
-          ExpressionNames.CHAR_TYPE_WRITE_SIDE_CHECK,
-          length)
+        buildCastWithWriteSideCheck(context, ExpressionNames.CHAR_TYPE_WRITE_SIDE_CHECK, length)
       case VarcharType(length) =>
-        buildCastWithWriteSideCheck(
-          context,
-          ExpressionNames.VARCHAR_TYPE_WRITE_SIDE_CHECK,
-          length)
+        buildCastWithWriteSideCheck(context, ExpressionNames.VARCHAR_TYPE_WRITE_SIDE_CHECK, length)
       case _ =>
         val typeNode = ConverterUtils.getTypeNode(dataType, original.nullable)
         ExpressionBuilder.makeCast(
diff --git a/shims/common/src/main/scala/org/apache/gluten/expression/ExpressionNames.scala b/shims/common/src/main/scala/org/apache/gluten/expression/ExpressionNames.scala
index d4afb7ff73..617aa2cd69 100644
--- a/shims/common/src/main/scala/org/apache/gluten/expression/ExpressionNames.scala
+++ b/shims/common/src/main/scala/org/apache/gluten/expression/ExpressionNames.scala
@@ -93,6 +93,7 @@ object ExpressionNames {
   final val CHECKED_DIVIDE = "checked_divide"
   final val CHECKED_MULTIPLY = "checked_multiply"
   final val CHECKED_DIV = "checked_div"
+  final val CHECKED_REMAINDER = "checked_remainder"
 
   // SparkSQL String functions
   final val ASCII = "ascii"
diff --git a/shims/spark40/src/main/scala/org/apache/gluten/sql/shims/spark40/Spark40Shims.scala b/shims/spark40/src/main/scala/org/apache/gluten/sql/shims/spark40/Spark40Shims.scala
index 0c3b163ce5..ebccadf96b 100644
--- a/shims/spark40/src/main/scala/org/apache/gluten/sql/shims/spark40/Spark40Shims.scala
+++ b/shims/spark40/src/main/scala/org/apache/gluten/sql/shims/spark40/Spark40Shims.scala
@@ -496,6 +496,7 @@ class Spark40Shims extends SparkShims {
       case d: Divide => d.evalMode == EvalMode.TRY
       case m: Multiply => m.evalMode == EvalMode.TRY
       case c: Cast => c.evalMode == EvalMode.TRY
+      case r: Remainder => r.evalMode == EvalMode.TRY
       case _ => false
     }
   }
@@ -508,6 +509,7 @@ class Spark40Shims extends SparkShims {
       case m: Multiply => m.evalMode == EvalMode.ANSI
       case c: Cast => c.evalMode == EvalMode.ANSI
       case i: IntegralDivide => i.evalMode == EvalMode.ANSI
+      case r: Remainder => r.evalMode == EvalMode.ANSI
       case _ => false
     }
   }
diff --git a/shims/spark41/src/main/scala/org/apache/gluten/sql/shims/spark41/Spark41Shims.scala b/shims/spark41/src/main/scala/org/apache/gluten/sql/shims/spark41/Spark41Shims.scala
index 5ff9d51c71..1c8d267204 100644
--- a/shims/spark41/src/main/scala/org/apache/gluten/sql/shims/spark41/Spark41Shims.scala
+++ b/shims/spark41/src/main/scala/org/apache/gluten/sql/shims/spark41/Spark41Shims.scala
@@ -495,6 +495,7 @@ class Spark41Shims extends SparkShims {
       case d: Divide => d.evalMode == EvalMode.TRY
       case m: Multiply => m.evalMode == EvalMode.TRY
       case c: Cast => c.evalMode == EvalMode.TRY
+      case r: Remainder => r.evalMode == EvalMode.TRY
       case _ => false
     }
   }
@@ -507,6 +508,7 @@ class Spark41Shims extends SparkShims {
       case m: Multiply => m.evalMode == EvalMode.ANSI
       case c: Cast => c.evalMode == EvalMode.ANSI
       case i: IntegralDivide => i.evalMode == EvalMode.ANSI
+      case r: Remainder => r.evalMode == EvalMode.ANSI
       case _ => false
     }
   }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@gluten.apache.org
For additional commands, e-mail: commits-help@gluten.apache.org