fix: [spark] honor ANSI mode in next_day, and fix a panic and a missing argument shape#23892
Open
andygrove wants to merge 1 commit into
Open
fix: [spark] honor ANSI mode in next_day, and fix a panic and a missing argument shape#23892andygrove wants to merge 1 commit into
andygrove wants to merge 1 commit into
Conversation
andygrove
force-pushed
the
next-day-spark-4-2-conformance
branch
from
July 25, 2026 17:46
4b7bee5 to
db5812e
Compare
…ent shape Spark's NextDay has taken failOnError = SQLConf.get.ansiEnabled since at least 3.5, raising on an unparseable day-of-week name and returning NULL otherwise. datafusion-spark ignored the flag and always returned NULL, with TODO comments acknowledging the gap. It now honors datafusion.execution.enable_ansi_mode, preserving Spark's per-row null intolerance: a NULL start date short circuits to NULL before the name is validated. Two version-independent bugs are fixed alongside it: - next_date_for_day_of_week used NaiveDate + Duration, which panicked for epoch days in 95026230..=95026236, reachable from plain SQL. It now uses checked_add_signed. - SELECT next_day(<date literal>, <string column>) hit an unreachable catch-all and raised a hard error. The match over ColumnarValue shapes is now exhaustive. The only version-specific change is the error message text, which now matches Spark 4.2.0's ILLEGAL_DAY_OF_WEEK template rather than 3.5.8's older IllegalArgumentException string. The remaining cross-version divergence, the ANSI default flip and error class change, is not addressed here and is tracked by apache#23890
andygrove
force-pushed
the
next-day-spark-4-2-conformance
branch
from
July 25, 2026 17:52
db5812e to
5ed5d6a
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #23892 +/- ##
========================================
Coverage 80.65% 80.66%
========================================
Files 1091 1092 +1
Lines 371031 371148 +117
Branches 371031 371148 +117
========================================
+ Hits 299256 299376 +120
+ Misses 53935 53923 -12
- Partials 17840 17849 +9 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Which issue does this PR close?
No single issue tracks these fixes. They were surfaced by an audit of
next_dayagainst the Spark source and a live Spark 4.2.0. The divergencesthis PR does not fix are filed separately and referenced from the test file:
next_dayrejectsSTRINGandTIMESTAMPstart dates that Spark acceptsin the ANSI default and error class between Spark 3.5 and 4.x
next_dayreturns NULLfor far-future start dates where Spark returns a value
Rationale for this change
Three problems, only one of which is version-related.
The ANSI flag was ignored. Spark's
NextDayhas takenfailOnError: Boolean = SQLConf.get.ansiEnabledsince at least 3.5, raising onan unparseable day-of-week name and returning NULL otherwise. This is not new
in Spark 4: what changed in 4.0 is the default value of
ansiEnabledand theexception type, not the behavior the flag selects.
datafusion-sparkignoredthe flag entirely and always returned NULL, with
TODOcomments in the sourceacknowledging the gap.
A panic reachable from SQL.
next_date_for_day_of_weekusedNaiveDate + Duration.Date32Type::to_naive_date_optsucceeds up tochrono::NaiveDate::MAX(epoch day95026236), and the subsequent additionthen panics on overflow. Every epoch day in
95026230..=95026236panicked, forany weekday:
This is reachable from plain SQL and from any
Date32column containing such avalue.
A whole argument shape was unsupported.
SELECT next_day(<date literal>, <string column>)fell into anexec_err!catch-all and raised a hard error ona query Spark evaluates normally.
The last two are version-independent bugs. The cross-version divergence proper,
the ANSI default flip and the error class change between 3.5 and 4.x, is not
fixed here and is tracked by
#23890.
What changes are included in this PR?
next_date_for_day_of_weekuseschecked_add_signed, trading the panic forNULL. NULL still diverges from Spark, which computes on the epoch day as
Intwith no calendar limit, so the residual gap is filed as [Bug] next_day returns NULL for far-future start dates where Spark returns a value #23891.ColumnarValueshapes is now exhaustive over all fourcombinations, so the
(Scalar, Array)case works and the compiler enforcescoverage. The
_ => exec_err!catch-all is gone.datafusion.execution.enable_ansi_mode, matchinghow
math/abs.rsandmath/negative.rsread it. Spark's per-row nullintolerance is preserved: a NULL start date short-circuits to NULL before the
day-of-week name is validated, so
next_day(NULL, 'xx')is NULL in bothmodes. On the
(Array, Scalar)path this is expressed asdate_array.null_count() < date_array.len(), which is the closed form ofexactly when the row-wise path raises.
ILLEGAL_DAY_OF_WEEKtemplate rather than Spark 3.5.8's olderIllegalArgumentExceptiontext.spark_next_dayis split intoparse_day_of_weekandnext_date_for_day_of_week. The old code round-tripped"MO"through"MONDAY"intostr::parse::<Weekday>()with an unreachableErrarm; thereplacement is a single table matching
DateTimeUtils.getDayOfWeekFromStringcase for case.
Are these changes tested?
Yes.
next_day.sltgrows from 90 to 336 lines. Every expected value wasobserved by running the query against a local
pyspark==4.2.0rather thanderived from reading the Spark source.
Coverage is organized as a product rather than a checklist, because the two
bugs above hid in the gaps between axes: all four
ColumnarValueshapes, eachcrossed with all-NULL, some-NULL and no-NULL inputs, each crossed with both
ANSI modes. The
(Array, Scalar)null-intolerance case in particular passes onthe row-wise path and previously failed on the vectorized one, so testing only
one shape would have missed it.
Also covered: boundary dates through
+262142-12-31including the entirepreviously-panicking range, day-name parsing (all three lengths, case
insensitivity, whitespace padding, non-ASCII), and the argument type and arity
errors.
Divergences that are not fixed here are checked in as commented-out queries
carrying the Spark 4.2.0 result and a link to the tracking issue. Uncommenting
one is the contract for verifying a future fix.
Verified with: