PPL date/time fixes 15 new scalars, TIME comparison, sub-ms precision, format tokens#22086
Conversation
PR Reviewer Guide 🔍(Review updated until commit be091ed)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to be091ed Explore these optional code suggestions:
Previous suggestionsSuggestions up to commit 978d627
Suggestions up to commit b329c6d
Suggestions up to commit 8feacbe
Suggestions up to commit 98e0a57
Suggestions up to commit 19cfc05
|
87b1de6 to
6014422
Compare
|
Persistent review updated to latest commit ebc0b11 |
e0d4b3a to
c0b2d21
Compare
PR Code Analyzer ❗AI-powered 'Code-Diff-Analyzer' found issues on commit c0b2d21.
The table above displays the top 10 most important findings. Pull Requests Author(s): Please update your Pull Request according to the report above. Repository Maintainer(s): You can Thanks. |
c0b2d21 to
109bb0b
Compare
|
Persistent review updated to latest commit 109bb0b |
109bb0b to
19cfc05
Compare
|
Persistent review updated to latest commit 19cfc05 |
Lowers ADDDATE/SUBDATE, DATEDIFF, TO_DAYS/TO_SECONDS/FROM_DAYS/TIME_TO_SEC,
SEC_TO_TIME, WEEKDAY, PERIOD_ADD/PERIOD_DIFF, GET_FORMAT, ADDTIME/SUBTIME/
TIMEDIFF, LAST_DAY, YEARWEEK to DataFusion-native expressions via per-function
adapters. Each rewrites to to_unixtime/from_unixtime + integer arithmetic,
date_trunc, maketime, or a Rust UDF that lowers through the Substrait catalog.
Includes:
- DateAddSubAdapter: handle ADDDATE/SUBDATE integer form (treated as
INTERVAL N DAY per MySQL).
- TimeFormatAdapter: coerce a TIME first operand to TIMESTAMP (substrait-java
0.89.1 has no precision_time<P> binding, so calls like time_format(maketime,
...) need anchoring) — same workaround DatePartAdapters uses.
- EarliestLatestAdapter: pin result type to the call's declared nullable
BOOLEAN so a non-null timestamp operand doesn't trip Calcite's BOOLEAN-vs-
BOOLEAN-NOT-NULL assert in the enclosing Project/Filter.
- SubstraitPlanPojoRewriter: only rescale precision-9 (ns) literals to ms;
precision-6 (µs) literals pass through so cast('… .123456' AS TIMESTAMP)
preserves the µs fraction.
- New os_yearweek Rust UDF sharing os_week's per-mode math.
Unit tests cover every adapter at the rewrite-shape level; QA ITs in
DateTimeScalarFunctionsIT pin MySQL semantics (year-boundary roll, leap-Feb
last_day, MOD-86400 wrap, today-anchor cancellation, integer-form ADDDATE,
…). Unmutes 15 ExtensiveCoveragePplIT golden queries.
Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
Calcite's binary-comparison type-coercion wraps a TIME operand with
to_timestamp(precision_time<P>) to align with a DATE/TIMESTAMP peer, but
the yaml has no impl for that signature — isthmus throws "Unable to
convert call to_timestamp(precision_time<9>?)" and the query fails with
HTTP 400.
Extend ComparisonTemporalCoercionAdapter (already handling
VARCHAR-vs-TIMESTAMP) to also rewrite the TIME side to a today-anchored
TIMESTAMP via the existing DatePartAdapters.coerceCharacterOperandToTimestamp
helper, mirroring PPL's TIME-vs-{DATE,TIMESTAMP} semantics. TIME-vs-TIME
is left on the native Substrait path.
Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
ADDDATE / SUBDATE were unbound in the analytics-engine scalar registry, so PPL queries using either UDF returned `No backend supports scalar function [ADDDATE]`. Both alias DATE_ADD / DATE_SUB but additionally accept an integer second operand (days), which the existing DateAddSubAdapter rejected. Add ADDDATE / SUBDATE to ScalarFunction, register them against the shared DateAddSubAdapter, and extend the adapter to rebuild integer operands as INTERVAL N DAY before the existing interval-lowering path. Cluster verified — 10/10 affected queries return HTTP 200 with expected values; null-row semantics preserved. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
Calcite's makeTimestampLiteral(value, precision) truncates the value to
`precision` digits, so timestamp('2020-09-16 17:30:00.123456') folded at
the parquet-resolved precision (3) silently dropped the .456 µs digits
the user typed. microsecond() and date_format(_, '%f') then read 123000
instead of 123456.
Bump fold precision to 6 in TimestampFunctionAdapter when the input
carries non-zero sub-ms digits; ms-aligned values stay at the resolved
precision. Drop the stale precision-3 rescale in SubstraitPlanPojoRewriter
— DataFusion 53.x coerces precision-6 literals against ms parquet columns
without a runtime cost, verified end-to-end against 14 PPL queries.
Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
Pre-fix, an invalid input like DAYNAME('2025-13-02') flowed through
plan-time and crashed the streaming fragment with a generic
StreamException. PPL's negative-path tests want a structured
"unsupported format" rejection at plan time so the user sees a
typed error instead of a streaming-layer crash.
Add validateFirstArgIfStringLiteral(...) calls to DaynameAdapter and
MonthnameAdapter, mirroring the existing DateFormatAdapter /
TimeFormatAdapter siblings. Valid inputs pass through unchanged.
Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
Two-arg DATETIME(name, tz) lowers to convert_tz, which had a precision-9 binding gap pre-fix (already addressed in earlier commit dd3a231 via SAFE-cast in ConvertTzAdapter). Add an IT method exercising convert_tz on a null-typed VARCHAR column to lock in the cast-then-fold-to-null contract against future regression. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
Five narrow fixes that unmute six previously-pending DatetimeCoverageIT /
DateTimeScalarFunctionsIT regression gates:
- ArrowValues TIMESTAMP/TIME render: switch fixed-width SSSSSSSSS to
appendFraction(NANO_OF_SECOND, 1, 9, true). Trailing zeros stripped, so
'23:59:59.999999000' → '23:59:59.999999' and '2262-04-11 23:47:16.854000'
→ '2262-04-11 23:47:16.854'. Dispatcher (nano==0 ? NO_NANO : WITH_NANO)
guarantees ≥1 fractional digit so the 1..9 minimum never trips.
- DatetimeAdapter (1-arg): TIME first operand serialises to substrait
precision_time<P>, no to_timestamp yaml binding. Anchor to TIMESTAMP via
DatePartAdapters.coerceCharacterOperandToTimestamp before to_timestamp.
- DatetimeAdapter (2-arg, column path): synthesised "+00:00" target-tz
literal as VARCHAR (not CHAR(6)) so isthmus binds the
convert_tz(precision_timestamp, string, string) yaml arm; previously
emitted convert_tz(_, char<6>, _) which mismatched.
- DatetimeAdapter (2-arg fold + column): MySQL semantics — when the value
has no embedded TZ offset, the user's tz arg is the SOURCE (target=UTC),
not the target. The previous direction inverted the offset
(DATETIME('2008-01-01 02:00:00', '+10:00') was returning
'2008-01-01 12:00:00' instead of '2007-12-31 16:00:00').
- os_strftime (Rust UDF): %c emits month with no leading zero (MySQL
documented behavior, was zero-padded "01"); %U/%u/%V/%v emit
zero-padded week numbers width 2 (was unpadded "4" instead of "04").
Companion Rust unit tests updated.
testClusterA_spanCustomFormatDate stays @AwaitsFix — requires
OpenSearchTypeFactory DateOnlyType bridging in the SQL plugin, which is
read-only on this branch; the rationale is captured in the test's Javadoc.
Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
Test method names previously embedded the internal grouping (testClusterA_*, testClusterB_*, etc.) which leaked the maintenance taxonomy into the surface contract. Renamed each method to describe what it tests (testSpanDateTypePreservesDate, testTwoArgDatetimeColInput, etc.) and trimmed the section banner / Javadoc prefixes to drop the cluster-letter naming. No assertion or query changes. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
19cfc05 to
98e0a57
Compare
|
Persistent review updated to latest commit 98e0a57 |
Mainline upgrade to DataFusion 54 (opensearch-project#22063) removed as_any from the ScalarUDFImpl trait — the udf_identity! macro now provides it. Sibling OsWeekUdf already shed the override; OsYearweekUdf added on this branch still declared it and broke cargoTest with E0407. Drop the override; trait dispatch falls through to the macro's impl. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
|
Persistent review updated to latest commit 8feacbe |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #22086 +/- ##
=========================================
Coverage 73.37% 73.38%
- Complexity 75572 75592 +20
=========================================
Files 6038 6038
Lines 343009 343009
Branches 49348 49348
=========================================
+ Hits 251674 251703 +29
- Misses 71305 71313 +8
+ Partials 20030 19993 -37 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Persistent review updated to latest commit b329c6d |
|
Persistent review updated to latest commit 978d627 |
SQL `/` truncates toward zero, so naive `to_unixtime(x) / 86400` rounds negative epoch seconds the wrong way and puts e.g. `1969-12-31 12:00` on the same epoch-day as `1970-01-01 00:00`. Express the floor in pure integer arithmetic — `(x - ((x MOD d + d) MOD d)) / d` — since isthmus has no `FLOOR(i64)` signature in the bound catalog. Pin with two DateTimeScalarFunctionsIT cases that span and sit below the epoch. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
Calcite infers CHAR(N) from a literal's length, but the convert_tz yaml binds tz operands as unbounded `string` (VARCHAR). Without the cast, a user-supplied tz literal like `'+05:30'` lowers as `convert_tz(precision_timestamp, char<6>, char<6>)` — same CHAR-vs-string mismatch already fixed for the synthesised target tz literal, just from the other side. Cast the source tz to VARCHAR for symmetry; the literal target was already cast. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
Per PR 22086 review feedback (expani, mch2): adapters shouldn't be stripping OperatorAnnotation themselves; the driver should normalise the tree. Tag the local strip helper as a follow-up so the cleanup covers every adapter doing this together. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
978d627 to
be091ed
Compare
|
Persistent review updated to latest commit be091ed |
|
❕ Gradle check result for be091ed: UNSTABLE Please review all flaky tests that succeeded after retry and create an issue if one does not already exist to track the flaky failure. |
…, format tokens (opensearch-project#22086) * Add 15 PPL datetime scalars over DataFusion Lowers ADDDATE/SUBDATE, DATEDIFF, TO_DAYS/TO_SECONDS/FROM_DAYS/TIME_TO_SEC, SEC_TO_TIME, WEEKDAY, PERIOD_ADD/PERIOD_DIFF, GET_FORMAT, ADDTIME/SUBTIME/ TIMEDIFF, LAST_DAY, YEARWEEK to DataFusion-native expressions via per-function adapters. Each rewrites to to_unixtime/from_unixtime + integer arithmetic, date_trunc, maketime, or a Rust UDF that lowers through the Substrait catalog. Includes: - DateAddSubAdapter: handle ADDDATE/SUBDATE integer form (treated as INTERVAL N DAY per MySQL). - TimeFormatAdapter: coerce a TIME first operand to TIMESTAMP (substrait-java 0.89.1 has no precision_time<P> binding, so calls like time_format(maketime, ...) need anchoring) — same workaround DatePartAdapters uses. - EarliestLatestAdapter: pin result type to the call's declared nullable BOOLEAN so a non-null timestamp operand doesn't trip Calcite's BOOLEAN-vs- BOOLEAN-NOT-NULL assert in the enclosing Project/Filter. - SubstraitPlanPojoRewriter: only rescale precision-9 (ns) literals to ms; precision-6 (µs) literals pass through so cast('… .123456' AS TIMESTAMP) preserves the µs fraction. - New os_yearweek Rust UDF sharing os_week's per-mode math. Unit tests cover every adapter at the rewrite-shape level; QA ITs in DateTimeScalarFunctionsIT pin MySQL semantics (year-boundary roll, leap-Feb last_day, MOD-86400 wrap, today-anchor cancellation, integer-form ADDDATE, …). Unmutes 15 ExtensiveCoveragePplIT golden queries. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com> * Fix TIME-vs-{DATE,TIMESTAMP} comparison via operand coercion Calcite's binary-comparison type-coercion wraps a TIME operand with to_timestamp(precision_time<P>) to align with a DATE/TIMESTAMP peer, but the yaml has no impl for that signature — isthmus throws "Unable to convert call to_timestamp(precision_time<9>?)" and the query fails with HTTP 400. Extend ComparisonTemporalCoercionAdapter (already handling VARCHAR-vs-TIMESTAMP) to also rewrite the TIME side to a today-anchored TIMESTAMP via the existing DatePartAdapters.coerceCharacterOperandToTimestamp helper, mirroring PPL's TIME-vs-{DATE,TIMESTAMP} semantics. TIME-vs-TIME is left on the native Substrait path. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com> * Register PPL ADDDATE/SUBDATE with integer-days overload ADDDATE / SUBDATE were unbound in the analytics-engine scalar registry, so PPL queries using either UDF returned `No backend supports scalar function [ADDDATE]`. Both alias DATE_ADD / DATE_SUB but additionally accept an integer second operand (days), which the existing DateAddSubAdapter rejected. Add ADDDATE / SUBDATE to ScalarFunction, register them against the shared DateAddSubAdapter, and extend the adapter to rebuild integer operands as INTERVAL N DAY before the existing interval-lowering path. Cluster verified — 10/10 affected queries return HTTP 200 with expected values; null-row semantics preserved. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com> * Preserve sub-millisecond precision in timestamp literal folds Calcite's makeTimestampLiteral(value, precision) truncates the value to `precision` digits, so timestamp('2020-09-16 17:30:00.123456') folded at the parquet-resolved precision (3) silently dropped the .456 µs digits the user typed. microsecond() and date_format(_, '%f') then read 123000 instead of 123456. Bump fold precision to 6 in TimestampFunctionAdapter when the input carries non-zero sub-ms digits; ms-aligned values stay at the resolved precision. Drop the stale precision-3 rescale in SubstraitPlanPojoRewriter — DataFusion 53.x coerces precision-6 literals against ms parquet columns without a runtime cost, verified end-to-end against 14 PPL queries. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com> * Reject invalid string literals in DAYNAME/MONTHNAME at plan time Pre-fix, an invalid input like DAYNAME('2025-13-02') flowed through plan-time and crashed the streaming fragment with a generic StreamException. PPL's negative-path tests want a structured "unsupported format" rejection at plan time so the user sees a typed error instead of a streaming-layer crash. Add validateFirstArgIfStringLiteral(...) calls to DaynameAdapter and MonthnameAdapter, mirroring the existing DateFormatAdapter / TimeFormatAdapter siblings. Valid inputs pass through unchanged. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com> * Pin convert_tz precision-9 path with regression IT Two-arg DATETIME(name, tz) lowers to convert_tz, which had a precision-9 binding gap pre-fix (already addressed in earlier commit dd3a231 via SAFE-cast in ConvertTzAdapter). Add an IT method exercising convert_tz on a null-typed VARCHAR column to lock in the cast-then-fold-to-null contract against future regression. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com> * Unmute 14 datetime ITs Five narrow fixes that unmute six previously-pending DatetimeCoverageIT / DateTimeScalarFunctionsIT regression gates: - ArrowValues TIMESTAMP/TIME render: switch fixed-width SSSSSSSSS to appendFraction(NANO_OF_SECOND, 1, 9, true). Trailing zeros stripped, so '23:59:59.999999000' → '23:59:59.999999' and '2262-04-11 23:47:16.854000' → '2262-04-11 23:47:16.854'. Dispatcher (nano==0 ? NO_NANO : WITH_NANO) guarantees ≥1 fractional digit so the 1..9 minimum never trips. - DatetimeAdapter (1-arg): TIME first operand serialises to substrait precision_time<P>, no to_timestamp yaml binding. Anchor to TIMESTAMP via DatePartAdapters.coerceCharacterOperandToTimestamp before to_timestamp. - DatetimeAdapter (2-arg, column path): synthesised "+00:00" target-tz literal as VARCHAR (not CHAR(6)) so isthmus binds the convert_tz(precision_timestamp, string, string) yaml arm; previously emitted convert_tz(_, char<6>, _) which mismatched. - DatetimeAdapter (2-arg fold + column): MySQL semantics — when the value has no embedded TZ offset, the user's tz arg is the SOURCE (target=UTC), not the target. The previous direction inverted the offset (DATETIME('2008-01-01 02:00:00', '+10:00') was returning '2008-01-01 12:00:00' instead of '2007-12-31 16:00:00'). - os_strftime (Rust UDF): %c emits month with no leading zero (MySQL documented behavior, was zero-padded "01"); %U/%u/%V/%v emit zero-padded week numbers width 2 (was unpadded "4" instead of "04"). Companion Rust unit tests updated. testClusterA_spanCustomFormatDate stays @AwaitsFix — requires OpenSearchTypeFactory DateOnlyType bridging in the SQL plugin, which is read-only on this branch; the rationale is captured in the test's Javadoc. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com> * Rename DatetimeCoverageIT methods by behavior, drop cluster labels Test method names previously embedded the internal grouping (testClusterA_*, testClusterB_*, etc.) which leaked the maintenance taxonomy into the surface contract. Renamed each method to describe what it tests (testSpanDateTypePreservesDate, testTwoArgDatetimeColInput, etc.) and trimmed the section banner / Javadoc prefixes to drop the cluster-letter naming. No assertion or query changes. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com> * Drop as_any from OsYearweekUdf for DataFusion 54 compat Mainline upgrade to DataFusion 54 (opensearch-project#22063) removed as_any from the ScalarUDFImpl trait — the udf_identity! macro now provides it. Sibling OsWeekUdf already shed the override; OsYearweekUdf added on this branch still declared it and broke cargoTest with E0407. Drop the override; trait dispatch falls through to the macro's impl. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com> * Floor-divide DATEDIFF day-numbers for pre-1970 correctness SQL `/` truncates toward zero, so naive `to_unixtime(x) / 86400` rounds negative epoch seconds the wrong way and puts e.g. `1969-12-31 12:00` on the same epoch-day as `1970-01-01 00:00`. Express the floor in pure integer arithmetic — `(x - ((x MOD d + d) MOD d)) / d` — since isthmus has no `FLOOR(i64)` signature in the bound catalog. Pin with two DateTimeScalarFunctionsIT cases that span and sit below the epoch. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com> * Cast tzArg to VARCHAR in DATETIME 2-arg column path Calcite infers CHAR(N) from a literal's length, but the convert_tz yaml binds tz operands as unbounded `string` (VARCHAR). Without the cast, a user-supplied tz literal like `'+05:30'` lowers as `convert_tz(precision_timestamp, char<6>, char<6>)` — same CHAR-vs-string mismatch already fixed for the synthesised target tz literal, just from the other side. Cast the source tz to VARCHAR for symmetry; the literal target was already cast. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com> * TODO: centralise annotation stripping in FragmentConversionDriver Per PR 22086 review feedback (expani, mch2): adapters shouldn't be stripping OperatorAnnotation themselves; the driver should normalise the tree. Tag the local strip helper as a follow-up so the cleanup covers every adapter doing this together. Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com> --------- Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
Summary
Wave 2 of PPL date/time fixes on the analytics-engine route. Adds 15 missing datetime scalars, lowers query shapes that previously hit Substrait binding gaps, and tightens MySQL-semantic correctness on existing functions. Unmutes 16 of the 18
@AwaitsFixITs gated in #22045.What's in each commit
Add 15 PPL datetime scalars over DataFusion
ADDDATE,SUBDATE,DATEDIFF,TO_DAYS/TO_SECONDS/FROM_DAYS/TIME_TO_SEC,SEC_TO_TIME,WEEKDAY,PERIOD_ADD/PERIOD_DIFF,GET_FORMAT,ADDTIME/SUBTIME/TIMEDIFF,LAST_DAY,YEARWEEK.to_unixtime/from_unixtime+ integer arithmetic,date_trunc,maketime, or a Rust UDF (newos_yearweek).ExtensiveCoveragePplITgolden queries (q112/119/125/126/128/137/138/139/144/147/148/151/152/156/158).Fix TIME-vs-{DATE,TIMESTAMP} comparison via operand coercion
to_timestamp(precision_time<P>), which has no yaml binding (substrait-java 0.89.1 lacksToTypeStringforPrecisionTime).ComparisonTemporalCoercionAdapterto anchor the TIME side to a today-UTC TIMESTAMP.time('00:00:00') = date('2004-07-09')now resolve.Register PPL ADDDATE/SUBDATE with integer-days overload
adddate(date, 7)) was bailed byDateAddSubAdapter.INTERVAL N DAYbefore the standard interval-lowering path runs.Preserve sub-millisecond precision in timestamp literal folds
timestamp('2020-09-16 17:30:00.123456')was folded at parquet's resolved precision (3) and silently truncated to.123.TimestampFunctionAdapternow bumps fold precision to 6 when the input carries non-zero sub-ms digits.microsecond(...)anddate_format(_, '%f')round-trip the full 6 digits.Reject invalid string literals in DAYNAME/MONTHNAME at plan time
DAYNAME('2025-13-02')previously crashed the streaming fragment with a genericStreamException.unsupported formathint, matching theDATE/TIME/TIMESTAMPsiblings.Pin convert_tz precision-9 path with regression IT
dd3a231eb2e) against future regression.CalcitePPLBuiltinFunctionsNullIT's null-string DATETIME shape.Unmute 14 datetime ITs
Five narrow follow-up fixes that flip previously-pending regression gates green:
ArrowValuesTIMESTAMP/TIME render: variable-fraction (1..9 digits, trailing zeros stripped) instead of fixed-9 —.999999000→.999999.DatetimeAdapter(1-arg): TIME operand anchored to TIMESTAMP beforeto_timestamp(yaml has noprecision_time<P>arm).DatetimeAdapter(2-arg, column path): synthesised tz literal as VARCHAR (was CHAR(N)) so isthmus binds theconvert_tz(_, string, string)arm.DatetimeAdapter(2-arg, fold + column): MySQL semantics — when the value has no embedded TZ offset, the user's tz arg is the source zone (target=UTC), not the target. Inverted the offset direction pre-fix.os_strftimeRust UDF:%cemits unpadded month;%U/%u/%V/%vemit zero-padded width-2 week numbers (matches MySQL docs and PPL DateTimeFormatterUtil).Drop as_any from OsYearweekUdf for DataFusion 54 compat
as_anyfromScalarUDFImpl(theudf_identity!macro now provides it). The newOsYearweekUdfstill declared the override.Also includes a behavior-only rename of
DatetimeCoverageITtest methods (dropped internal cluster-letter labels in favor of behavior-named methods).Query shapes added / fixed
New scalars (each lowers to a DataFusion-native plan)
ADDDATE,SUBDATEadddate(date0, 7),adddate(date0, interval 7 day),subdate(date0, interval 1 month),adddate(datetime0, interval 5 hour),subdate(datetime0, interval 30 minute),adddate('2020-08-26', interval 7 day)DATEDIFFdatediff('2000-01-02 00:00:00', '2000-01-01 23:59:59')(= 1, time-of-day discarded),datediff(time('23:59:59'), time('00:00:00'))(= 0, both anchored to today)TO_DAYSto_days('1970-01-01')(= 719528, MySQL day-1 origin)TO_SECONDSto_seconds('1970-01-01 00:00:00')(= 62167219200)FROM_DAYSfrom_days(719528)(= 1970-01-01)TIME_TO_SECtime_to_sec(datetime0),time_to_sec(time('19:36:22'))SEC_TO_TIMEsec_to_time(123456)(= 10:17:36, MOD-86400 wrap)WEEKDAYweekday(datetime0)(Mon=0..Sun=6)PERIOD_ADDperiod_add(202612, 1)(= 202701, year-boundary roll)PERIOD_DIFFperiod_diff(202612, 202601)(= 11)GET_FORMATget_format(DATE, 'EUR')(= '%d.%m.%Y')ADDTIME,SUBTIMEaddtime(datetime0, time('14:00:00'))(cross-midnight),subtime(datetime0, time('11:00:00')),addtime(datetime0, time1),addtime(time1, time('02:30:00'))TIMEDIFFtimediff(time('23:59:59'), time('13:00:00'))(= 10:59:59)LAST_DAYlast_day('2024-02-15')(= 2024-02-29, leap-year),last_day(date0),last_day(datetime0)YEARWEEKyearweek('2003-10-03')(= 200339),yearweek('2003-10-03', 3)(= 200340),yearweek(datetime0)Function-overload gaps closed
datetime('2008-01-01 02:00:00', '+10:00')datetime('2008-01-01 02:00:00', 'America/Los_Angeles')datetime(datetime0, '+00:00')datetime('2008-01-01 02:00:00', '+15:00')DATETIME(null_str, '+10:00')sysdate(0)/now(0)date_add(time('09:00:00'), interval 1 hour),date_sub(time('09:00:00'), interval 30 minute)timestampadd(YEAR, 1, '2024-01-15 12:00:00'),timestampdiff(DAY, '...', '...'),timestampdiff(MONTH, '...', '...')hour(time('17:30:45')),minute(time('17:30:45')),second(time('17:30:45'))from_unixtime(1521467703, '%Y-%m-%d %H:%i:%s')timestamp(date0, time1)timestamp(time('10:20:30'))Comparisons across mixed temporal types
time('00:00:00') = date('2004-07-09')date('2020-09-16') < time('09:07:00')time('10:20:30') = timestamp('<today> 10:20:30')timestamp('1984-12-15 10:20:30') != time('10:20:30')Span types
span(date0, 1d),span(date1, 1month)dateschema type (was2004-04-15 00:00:00/timestamp)span(time1, 1h),span(time1, 1minute)timeschema type (was1970-01-01 19:00:00)Format-token / rendering
date_format(date('2024-01-28'), '%c %U %u %V %v')1 04 04 04 04(was01 4 4 4 4)date_format(timestamp('1998-01-31 13:14:15'), '%a %b %c %D %d %H %i %M %m %S')Sat Jan 1 31st 31 13 14 January 01 15(wasSat Jan 01 …)date_format('2024-01-15 12:00:00.123456', '%f')123456(was123000)microsecond('2024-01-15 12:00:00.123456')123456(was123000)microsecond('2024-01-15 12:00:00.000001')1(was0)cast('2023-10-01 12:00:00.123456' as TIMESTAMP)rendered.123456preserved (was truncated to.123)cast('2262-04-11 23:47:16.854' as TIMESTAMP)2262-04-11 23:47:16.854(was…854000)cast('23:59:59.999999' as TIME)23:59:59.999999(was…999999000)date_add(datetime0, interval 500 millisecond)2004-07-09 10:17:35.5(was…500000000)cast('1985-10-09 12:00:00' as TIME)12:00:00maketime(20.2, 49.5, 42.1)rendered viatime_format(_, '%H:%i:%s')20:50:42Error-contract / validation
unsupported formatdayname('2025-13-02'),monthname('2025-13-02')StreamException500)date('2025-13-02'),time('16:00:61'),timestamp('2025-12-01 15:02:61')cast('xxx' as DATE),cast('xxx' as TIME),cast('xxx' as TIMESTAMP)timestampadd(YEAR, 1, '2025-13-02'),timestampdiff(DAY, '2025-13-02', ...)hour('99:99:99')datetime('2025-13-02')convert_tz(_, '+15:00', '+00:00')Boundary / range
cast('0001-01-01' as DATE),cast('9999-12-31' as DATE)cast('1677-09-21 00:12:44' as TIMESTAMP)cast('2200-01-01 00:00:00' as TIMESTAMP)cast('00:00:00' as TIME)timestamp('3077-04-12 09:07:00')outside the supported range(no opaque Arrow overflow)Other
Still skipped (2 of 18)
DatetimeCoverageIT.testSpanCustomFormatDate—span()over an eval-deriveddate(...)returns the bucket as"2004-04-01 00:00:00"instead of the bare"2004-04-01". The renderer inAnalyticsExecutionEngine#convertonly strips the midnight suffix when the type isDateOnlyType(column-mapping UDT), but the eval-derived path producesExprDateType. Fix is one line in the SQL plugin (broaden the predicate toOpenSearchTypeFactory.isDateExprType(type)); out of scope here. TODO captured on the test.TwoShardCommandIT.testReduceCorrectnessAcrossTwoShards—timechartbucket renders as bareDATEinstead ofTIMESTAMP(3 of 18 reduce sub-checks fail). Same renderer/typing gap, surfaces in the multi-shard reduce harness.Test plan
:sandbox:plugins:analytics-backend-datafusion:check— green (Java + Rust unit tests).:sandbox:libs:analytics-framework:check— green.:sandbox:plugins:analytics-engine:check— green.:sandbox:qa:analytics-engine-rest:integTest— green for the 16 unmuted ITs against a 2-node test cluster; the 2 remaining@AwaitsFixtests stay skipped with rationale.