Skip to content

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
apache:mainfrom
andygrove:next-day-spark-4-2-conformance
Open

fix: [spark] honor ANSI mode in next_day, and fix a panic and a missing argument shape#23892
andygrove wants to merge 1 commit into
apache:mainfrom
andygrove:next-day-spark-4-2-conformance

Conversation

@andygrove

@andygrove andygrove commented Jul 25, 2026

Copy link
Copy Markdown
Member

Which issue does this PR close?

  • Closes #.

No single issue tracks these fixes. They were surfaced by an audit of
next_day against the Spark source and a live Spark 4.2.0. The divergences
this PR does not fix are filed separately and referenced from the test file:

Rationale for this change

Three problems, only one of which is version-related.

The ANSI flag was ignored. Spark's NextDay has taken
failOnError: Boolean = SQLConf.get.ansiEnabled since at least 3.5, raising on
an 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 ansiEnabled and the
exception type, not the behavior the flag selects. datafusion-spark ignored
the flag entirely and always returned NULL, with TODO comments in the source
acknowledging the gap.

A panic reachable from SQL. next_date_for_day_of_week used
NaiveDate + Duration. Date32Type::to_naive_date_opt succeeds up to
chrono::NaiveDate::MAX (epoch day 95026236), and the subsequent addition
then panics on overflow. Every epoch day in 95026230..=95026236 panicked, for
any weekday:

SELECT next_day(arrow_cast(95026236, 'Date32'), 'Mon'::string);
-- thread panicked: `NaiveDate + TimeDelta` overflowed

This is reachable from plain SQL and from any Date32 column containing such a
value.

A whole argument shape was unsupported. SELECT next_day(<date literal>, <string column>) fell into an exec_err! catch-all and raised a hard error on
a 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_week uses checked_add_signed, trading the panic for
    NULL. NULL still diverges from Spark, which computes on the epoch day as
    Int with 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.
  • The match over ColumnarValue shapes is now exhaustive over all four
    combinations, so the (Scalar, Array) case works and the compiler enforces
    coverage. The _ => exec_err! catch-all is gone.
  • ANSI mode is honored via datafusion.execution.enable_ansi_mode, matching
    how math/abs.rs and math/negative.rs read it. Spark's per-row null
    intolerance 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 both
    modes. On the (Array, Scalar) path this is expressed as
    date_array.null_count() < date_array.len(), which is the closed form of
    exactly when the row-wise path raises.
  • The error message gains Spark 4.2.0's trailing period, matching the
    ILLEGAL_DAY_OF_WEEK template rather than Spark 3.5.8's older
    IllegalArgumentException text.
  • spark_next_day is split into parse_day_of_week and
    next_date_for_day_of_week. The old code round-tripped "MO" through
    "MONDAY" into str::parse::<Weekday>() with an unreachable Err arm; the
    replacement is a single table matching DateTimeUtils.getDayOfWeekFromString
    case for case.

Are these changes tested?

Yes. next_day.slt grows from 90 to 336 lines. Every expected value was
observed by running the query against a local pyspark==4.2.0 rather than
derived 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 ColumnarValue shapes, each
crossed with all-NULL, some-NULL and no-NULL inputs, each crossed with both
ANSI modes. The (Array, Scalar) null-intolerance case in particular passes on
the 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-31 including the entire
previously-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:

cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --test sqllogictests -- spark/datetime/next_day
cargo test -p datafusion-spark --lib next_day

@andygrove andygrove changed the title fix: make next_day match Spark 4.2.0 semantics fix: honor ANSI mode in next_day, and fix a panic and a missing argument shape Jul 25, 2026
@andygrove
andygrove force-pushed the next-day-spark-4-2-conformance branch from 4b7bee5 to db5812e Compare July 25, 2026 17:46
…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
andygrove force-pushed the next-day-spark-4-2-conformance branch from db5812e to 5ed5d6a Compare July 25, 2026 17:52
@github-actions github-actions Bot added sqllogictest SQL Logic Tests (.slt) spark labels Jul 25, 2026
@andygrove andygrove changed the title fix: honor ANSI mode in next_day, and fix a panic and a missing argument shape fix: [spark] honor ANSI mode in next_day, and fix a panic and a missing argument shape Jul 25, 2026
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.38053% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.66%. Comparing base (f1ab86d) to head (5ed5d6a).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
datafusion/spark/src/function/datetime/next_day.rs 89.38% 9 Missing and 3 partials ⚠️
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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

spark sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants