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

gengliangwang pushed a commit to branch branch-4.x
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/branch-4.x by this push:
     new 68dae3699839 [SPARK-57169][SQL] Simplify NextDay codegen under ANSI 
mode
68dae3699839 is described below

commit 68dae369983940ccd1bd896106fbad0af9889b2c
Author: Gengliang Wang <[email protected]>
AuthorDate: Mon Jun 1 09:43:08 2026 -0700

    [SPARK-57169][SQL] Simplify NextDay codegen under ANSI mode
    
    ### What changes were proposed in this pull request?
    
    Add `DateTimeExpressionUtils.getNextDateExact(int startDate, UTF8String 
dayOfWeek)` and route `NextDay`'s ANSI (`failOnError = true`) eval and codegen 
paths through it.
    
    In ANSI mode the previous codegen emitted `try { ... } catch 
(SparkIllegalArgumentException e) { throw e; }` -- a no-op catch that simply 
rethrew the same exception. The ANSI branch now emits a single 
`getNextDateExact(...)` call with no try/catch (the helper lets the 
`SparkIllegalArgumentException` from `DateTimeUtils.getDayOfWeekFromString` 
propagate, which is exactly the ANSI behavior). The non-ANSI branch keeps the 
inline `try/catch -> isNull` form (matching the already-merged `Ma [...]
    
    ### Why are the changes needed?
    
    Part of SPARK-56908 (umbrella). Dropping the dead try/catch wrapper (and 
the two chained `DateTimeUtils` calls) in the ANSI path shrinks the generated 
Java for `next_day`, helping with the JVM 64KB method / constant-pool limits, 
Janino compile time, and JIT work.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No. The compiled behavior is identical; only the emitted Java source text 
changes.
    
    ### How was this patch tested?
    
    ```
    build/sbt "catalyst/testOnly *DateExpressionsSuite"
    ```
    
    75/75 pass, including `next_day` (exercised both with and without 
whole-stage codegen).
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Opus 4.8)
    
    Closes #56219 from gengliangwang/spark-next-day-codegen.
    
    Authored-by: Gengliang Wang <[email protected]>
    Signed-off-by: Gengliang Wang <[email protected]>
    (cherry picked from commit c19056aabd5d195528f8dc5269fddc74ea48779d)
    Signed-off-by: Gengliang Wang <[email protected]>
---
 .../expressions/DateTimeExpressionUtils.java       | 14 +++++++
 .../catalyst/expressions/datetimeExpressions.scala | 46 +++++++++++-----------
 2 files changed, 38 insertions(+), 22 deletions(-)

diff --git 
a/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/DateTimeExpressionUtils.java
 
b/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/DateTimeExpressionUtils.java
index 16312cdb648a..8cde11c577d5 100644
--- 
a/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/DateTimeExpressionUtils.java
+++ 
b/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/DateTimeExpressionUtils.java
@@ -31,6 +31,7 @@ import org.apache.spark.sql.catalyst.util.TimestampFormatter;
 import org.apache.spark.sql.errors.QueryExecutionErrors;
 import org.apache.spark.sql.types.Decimal;
 import org.apache.spark.unsafe.types.CalendarInterval;
+import org.apache.spark.unsafe.types.UTF8String;
 
 /**
  * Static helpers shared by date/time/interval expression {@code doGenCode}
@@ -165,4 +166,17 @@ public final class DateTimeExpressionUtils {
       throw QueryExecutionErrors.ansiDateTimeParseError(e, 
suggestedFuncOnFail);
     }
   }
+
+  /**
+   * Computes the first date after {@code startDate} that falls on the weekday
+   * named by {@code dayOfWeek} for {@code NextDay} (next_day) in ANSI mode
+   * ({@code failOnError = true}). The {@code SparkIllegalArgumentException}
+   * thrown by {@code DateTimeUtils.getDayOfWeekFromString} for an invalid
+   * day-of-week string propagates to the caller unchanged (in ANSI mode the
+   * caller wants exactly that exception), so no try/catch wrapper is emitted.
+   */
+  public static int getNextDateExact(int startDate, UTF8String dayOfWeek) {
+    int dow = DateTimeUtils.getDayOfWeekFromString(dayOfWeek);
+    return DateTimeUtils.getNextDateForDayOfWeek(startDate, dow);
+  }
 }
diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
index 9b16a5685fb1..e7867b0ac6b4 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
@@ -1594,17 +1594,16 @@ case class NextDay(
   override def nullable: Boolean = true
 
   override def nullSafeEval(start: Any, dayOfW: Any): Any = {
-    try {
-      val dow = 
DateTimeUtils.getDayOfWeekFromString(dayOfW.asInstanceOf[UTF8String])
-      val sd = start.asInstanceOf[Int]
-      DateTimeUtils.getNextDateForDayOfWeek(sd, dow)
-    } catch {
-      case e: SparkIllegalArgumentException =>
-        if (failOnError) {
-          throw e
-        } else {
-          null
-        }
+    if (failOnError) {
+      DateTimeExpressionUtils.getNextDateExact(
+        start.asInstanceOf[Int], dayOfW.asInstanceOf[UTF8String])
+    } else {
+      try {
+        val dow = 
DateTimeUtils.getDayOfWeekFromString(dayOfW.asInstanceOf[UTF8String])
+        DateTimeUtils.getNextDateForDayOfWeek(start.asInstanceOf[Int], dow)
+      } catch {
+        case _: SparkIllegalArgumentException => null
+      }
     }
   }
 
@@ -1615,19 +1614,22 @@ case class NextDay(
       dayOfWeekTerm: String,
       sd: String,
       dowS: String): String = {
-    val failOnErrorBranch = if (failOnError) {
-      "throw e;"
+    if (failOnError) {
+      // In ANSI mode the only exception (SparkIllegalArgumentException for an
+      // invalid day-of-week) must propagate, so the previous catch merely
+      // rethrew it. Delegate to the helper and drop the no-op try/catch.
+      val utils = classOf[DateTimeExpressionUtils].getName
+      s"${ev.value} = $utils.getNextDateExact($sd, $dowS);"
     } else {
-      s"${ev.isNull} = true;"
+      s"""
+       |try {
+       |  int $dayOfWeekTerm = 
$dateTimeUtilClass.getDayOfWeekFromString($dowS);
+       |  ${ev.value} = $dateTimeUtilClass.getNextDateForDayOfWeek($sd, 
$dayOfWeekTerm);
+       |} catch (org.apache.spark.SparkIllegalArgumentException e) {
+       |  ${ev.isNull} = true;
+       |}
+       |""".stripMargin
     }
-    s"""
-     |try {
-     |  int $dayOfWeekTerm = $dateTimeUtilClass.getDayOfWeekFromString($dowS);
-     |  ${ev.value} = $dateTimeUtilClass.getNextDateForDayOfWeek($sd, 
$dayOfWeekTerm);
-     |} catch (org.apache.spark.SparkIllegalArgumentException e) {
-     |  $failOnErrorBranch
-     |}
-     |""".stripMargin
   }
 
   override protected def doGenCode(ctx: CodegenContext, ev: ExprCode): 
ExprCode = {


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

Reply via email to