andygrove opened a new issue, #6625:
URL: https://github.com/apache/datafusion-comet/issues/6625

   Part of #6615.
   
   ## What / Why
   
   This issue moves datetime expression coverage to Comet SQL tests under 
`sql-tests/expressions/datetime/`. The sources are 
`CometTemporalExpressionSuite` and the datetime tests in `CometExpressionSuite` 
(`date_add`/`date_sub`, `hour`/`minute`/`second`, `trunc`/`date_trunc`, INT96 
timestamps, `from_unixtime`, day-of-week, date partition columns). 
String-to-timestamp/date casts, including all of `CometDateTimeUtilsSuite`, are 
in the string-cast issue.
   
   Static analysis on `main` at 3bc2faa934 found the following:
   
   | Suite | Covered | Convert | Blocked | Split | Keep | Total |
   |---|---|---|---|---|---|---|
   | `CometTemporalExpressionSuite` | 5 | 24 | 1 | 0 | 7 | 37 |
   | `CometExpressionSuite` | 1 | 18 | 0 | 0 | 1 | 20 |
   | **Total** | **6** | **42** | **1** | **0** | **8** | **57** |
   
   The Scala tests pin far more than the fixtures do, which is why few are 
covered:
   
   - `date_trunc`: 15 formats, pinned in UTC and in non-UTC zones on the 
native, dispatch and fallback routes. Fixtures have at most 6 formats, mostly 
under allowIncompatible.
   - `date_format`: 23 native formats and the non-UTC routes. Fixtures have 3 
native formats.
   - `unix_timestamp` is tested across zones and on NTZ and date input; the 
fixtures are UTC-only.
   - `hour`/`minute`/`second` on NTZ are tested across four zones.
   
   Closed PR #4765 migrated four of these tests and concluded that the 
fuzz-based tests, `Days`/`Hours` and the operator-only allowIncompatible test 
could not move. Only the `Days`/`Hours` part holds up.
   
   - **Fuzz tests.** They reduce to curated values. `FuzzDataGenerator`'s 
default base date resolves to about 3333-01-01, so fuzz timestamps are winter 
dates around the 3332/3333 boundary, written as INT96 and never NULL. Use 
far-future winter values to mirror them; summer far-future values in DST zones 
would test behaviour the Scala tests never covered.
   - **The operator-only test (L737).** It converts with rows at 12:00 UTC, so 
`expect_native(date_format)` can compare answers too.
   
   ## Work
   
   Line numbers refer to `CometTemporalExpressionSuite` unless marked 
`CometExpressionSuite`.
   
   **New fixtures**
   
   - `trunc_timestamp_formats.sql` (L145, L170)
     - UTC.
     - Data: far-future INT96 timestamps with millisecond fractions, a 
pre-epoch value and NULL.
     - Add a format column with valid, mixed-case, invalid and NULL values.
     - `expect_native(date_trunc)` for each of the 15 formats, and 
`expect_dispatch(date_trunc)` for `'invalid'` and for the format column.
   - `trunc_timestamp_dispatch.sql` (L200): matrix over Los_Angeles, London and 
Tokyo, with 15 `expect_dispatch(date_trunc)` queries.
   - `trunc_timestamp_non_utc_fallback.sql` (L222)
     - New_York and London with the dispatcher off.
     - Assert `expect_fallback(date_trunc: 
spark.comet.exec.scalaUDF.codegen.enabled=false)`.
   - `trunc_timestamp_non_utc_native.sql` (L239)
     - Set `TruncTimestamp.allowIncompatible=true` and turn the dispatcher off.
     - Matrix over New_York, London and Tokyo, with data from 2024-05-21 to 
2024-07-10.
     - Assert `expect_native(date_trunc)`.
   - `trunc_timestamp_ntz.sql` (L317, `CometExpressionSuite` L1150)
     - Matrix over four zones, with NTZ values in summer 2024 and all 15 
formats.
     - No fixture runs `date_trunc` on NTZ today.
   - `unix_timestamp_timezones.sql` (L264, L273, L285)
     - Timestamp, date and NTZ columns with far-future, DST-date, pre-epoch and 
NULL values.
     - Matrix over four zones, with `expect_native(unix_timestamp)`.
   - `unix_timestamp_collation.sql` (L457, L481, `MinSparkVersion: 4.0`)
     - Use an allowIncompatible matrix.
     - Assert `expect_dispatch(unix_timestamp)` for string input with a 
collated format or subject.
     - Assert `expect_native(unix_timestamp)` for date, timestamp and NTZ input.
   - `hour_minute_second_ntz.sql` (L301): matrix over four zones, with 
`expect_native(hour, minute, second)` on NTZ.
   - `date_format_native_formats.sql` (L603, L620, L650)
     - UTC.
     - Every key in `CometDateFormat.supportedFormats` (23) as 
`expect_native(date_format)`, over far-future, AM/PM-edge, pre-epoch and NULL 
values.
     - Add five literal `TIMESTAMP '...'` queries.
   - `date_format_non_utc_fallback.sql` (L721).
   - `date_format_non_utc_native.sql` (L737)
     - Set `DateFormatClass.allowIncompatible=true` and turn the dispatcher off.
     - Matrix over New_York, London and Tokyo, with rows at 12:00 UTC.
   - `date_format_ntz.sql` (L349): matrix over four zones and 22 formats.
   - `timestamp_ntz_cross_timezone.sql` (L371)
     - Use a read-zone matrix: London, New_York, UTC and Auckland.
     - NTZ writes don't depend on the zone, so the Scala test's separate write 
zone adds nothing.
   - `date_add_overflow.sql` (`CometExpressionSuite` L722): `query 
ignore(https://github.com/apache/datafusion-comet/issues/2539)` over `d + 
2147483647`.
   - `date_sub_overflow.sql` (`MaxSparkVersion: 3.5`) and 
`date_sub_overflow_spark4.sql` (`MinSparkVersion: 4.0`) (L769)
     - `d - 2147483647`.
     - Assert `expect_error(integer overflow)` on Spark 3.x and 
`expect_error(EXPRESSION_DECODING_FAILED)` on Spark 4.
   - `int96_timestamp_conversion.sql` (L983, L1213)
     - Set `spark.sql.parquet.int96TimestampConversion=true`.
     - That conf turns off the whole Comet extension, so this leg compares 
Spark with Spark. Use `spark_answer_only`, or drop this leg.
     - The conversion=false legs are covered once the trunc fixtures have all 
15 formats, because INT96 is Spark's default timestamp output type.
   - `date_timestamp_literals.sql` (L693)
     - `WHERE d > DATE'2020-01-01' AND ts < TIMESTAMP'2020-01-01 00:00:00'`, 
over data on both sides of the boundary.
     - The Scala data never passes this filter.
   - `dayofweek_weekday.sql` (L2308)
     - Set `spark.sql.parquet.datetimeRebaseModeInWrite=CORRECTED`.
     - A DATE column covering the epoch week, leap days, 1900-01-01, 0001-01-01 
and 9999-12-31.
   - `date_partition_column.sql` (L2279): a `PARTITIONED BY (cal_dt)` table, 
`CAST(cal_dt AS STRING)`, and `SHOW PARTITIONS` as `spark_answer_only`.
   
   **Existing fixtures to extend**
   
   - `trunc_date.sql` (L82, `CometExpressionSuite` L1080)
     - Add the `yyyy`, `yy`, `mon`, `mm` and `week` formats, plus the 
upper-case aliases `YEAR`, `YYYY`, `YY`, `QUARTER`, `MON`, `MONTH`, `MM` and 
`WEEK`, as `expect_native(trunc)`.
     - Add dates across the 3332/3333 boundary.
     - Add `expect_dispatch(trunc)` for `'invalid'` and for a format column.
   - `trunc_date_enabled.sql` (L1094): the same aliases as values in the format 
column.
   - `trunc_timestamp.sql` (L1113)
     - Add the 11 missing formats, over pre-epoch fractional values and one 
microsecond-precision value.
     - Pin the session time zone. Today the file sets 
`TruncTimestamp.allowIncompatible=true` without one, so on a non-UTC machine it 
runs the Incompatible native path in that machine's zone.
   - `trunc_timestamp_enabled.sql` (L1187): all 15 formats as format-column 
values, plus an NTZ column and pre-epoch values.
   - `unix_timestamp_strings.sql` (L423): add `ConfigMatrix: 
spark.comet.expression.UnixTimestamp.allowIncompatible=false,true`.
   - `date_format.sql` (L703)
     - Replace the Los_Angeles `Config` with a matrix over New_York, 
Los_Angeles, London and Tokyo.
     - Switch the queries to `expect_dispatch(date_format)`.
   - `unix_date.sql` (L758)
     - Change `spark_answer_only` to `query`, since `CometUnixDate` is a native 
cast.
     - Add 1960-01-01, 1970-01-02 and dates near 3333.
   - `date_add.sql` / `date_sub.sql` (L707, L741, L755, L789): add tinyint and 
smallint day counts, using `2Y`/`2S` literals and tinyint/smallint columns.
   - `hour.sql`, `minute.sql`, `second.sql` (L934)
     - Add pre-epoch timestamps with fractional seconds.
     - Fix the stale comments saying TimestampNTZ is Incompatible and 
dispatched (#3180). `CometHour`, `CometMinute` and `CometSecond` have no NTZ 
check, and the native kernel extracts NTZ fields directly.
   - `from_unix_time_enabled.sql` (L2334)
     - Change the default-format queries from `spark_answer_only` to `query`.
     - Add a string-input column and seconds in -128..127.
     - Add an Asia/Kathmandu variant.
   
   **Blocked**
   
   - **#6617: L51** (`next_day` / `make_date` ANSI exception parity).
     - The test checks exception class, error class, SQLSTATE, message 
parameters and exact message, and that the error is not a 
`CometNativeException`.
     - Interim: `make_date(1000000000, 1, 1)` and `make_date(1000000000, 13, 
0)` as `expect_error`.
   
   ## Stays in Scala
   
   - **L795, L805, L819, L885, L899.** `Days` / `Hours` are `Unevaluable` 
partition transforms built with `getColumnFromExpression`. SQL cannot call them.
   - **L111** unit-tests `CometTimeZone.nativeId`. Eight of its IDs are covered 
end to end by `session_timezone_ids.sql`; EST, GMT and +00:00 could be added 
there.
   - **L138** checks the native tzdata version and a warning-text helper.
   - **`CometExpressionSuite` L960** asserts that Spark constant-folds 
`hour`/`minute`/`second`, which is optimizer plan shape.
   
   ## Fixture problems to fix along the way
   
   - **NULL literal arguments are folded by `NullPropagation`** and never reach 
Comet: `last_day.sql:29`, `date_diff.sql:37`, `unix_date.sql:29`, 
`date_format_time_parser_policy.sql:48-49`, `next_day.sql:73-74` (the whole 
query) and `make_date.sql:57-64`. Read NULLs from a column instead.
   - **`date_format_time_parser_policy.sql` uses `spark_answer_only`** although 
the plan is native (UTC with whitelisted formats).
   - **The leap-year `datediff` literals** look like calendar tests, but 
`CometCast` parses the `DATE('...')` literals on the JVM. Native code only 
subtracts two integers. Use date columns.
   
   ## Done when
   
   - Every test in the table below is accounted for. Either a fixture covers it 
(the same inputs, configs and assertion strength, or stronger), the fixture 
that already covers it is cited, or it stays in Scala for the reason given 
above.
   - Each converted Scala test is deleted in the PR that adds its coverage. A 
suite left empty is deleted and removed from the suite lists in 
`.github/workflows/pr_build_linux.yml` and `pr_build_macos.yml`.
   - The new and changed fixtures pass on every Spark profile. Apply 
`run-all-spark-profiles`, because pull requests run only the default profile.
   
   <details><summary>Every Scala test in scope, with its verdict and target 
fixture</summary>
   
   | Suite | Line | Test | Verdict | Target |
   |---|---|---|---|---|
   | `CometExpressionSuite` | 693 | date and timestamp type literals | convert 
| datetime/date_timestamp_literals.sql (new) |
   | `CometExpressionSuite` | 707 | date_add with int scalars | convert | 
datetime/date_add.sql |
   | `CometExpressionSuite` | 722 | date_add with scalar overflow (ignored, 
TODO #2539) | convert | datetime/date_add_overflow.sql (new) |
   | `CometExpressionSuite` | 741 | date_add with int arrays | convert | 
datetime/date_add.sql |
   | `CometExpressionSuite` | 755 | date_sub with int scalars | convert | 
datetime/date_sub.sql |
   | `CometExpressionSuite` | 769 | date_sub with scalar overflow | convert | 
datetime/date_sub_overflow.sql (new, MaxSparkVersion: 3.5) + 
datetime/date_sub_overflow_spark4.sql (new, MinSparkVersion: 4.0) |
   | `CometExpressionSuite` | 789 | date_sub with int arrays | convert | 
datetime/date_sub.sql |
   | `CometExpressionSuite` | 934 | hour, minute, second | convert | 
datetime/hour.sql + datetime/minute.sql + datetime/second.sql |
   | `CometExpressionSuite` | 960 | time expressions folded on jvm | keep |  |
   | `CometExpressionSuite` | 983 | hour on int96 timestamp column | convert | 
datetime/int96_timestamp_conversion.sql (new) |
   | `CometExpressionSuite` | 1080 | trunc | convert | datetime/trunc_date.sql |
   | `CometExpressionSuite` | 1094 | trunc with format array | convert | 
datetime/trunc_date_enabled.sql |
   | `CometExpressionSuite` | 1113 | date_trunc | convert | 
datetime/trunc_timestamp.sql |
   | `CometExpressionSuite` | 1150 | date_trunc with timestamp_ntz | convert | 
datetime/trunc_timestamp.sql |
   | `CometExpressionSuite` | 1187 | date_trunc with format array | convert | 
datetime/trunc_timestamp_enabled.sql |
   | `CometExpressionSuite` | 1213 | date_trunc on int96 timestamp column | 
convert | datetime/int96_timestamp_conversion.sql (new) + 
datetime/trunc_timestamp.sql |
   | `CometExpressionSuite` | 2279 | date partition column does not forget date 
type | convert | datetime/date_partition_column.sql (new) |
   | `CometExpressionSuite` | 2293 | DatePart functions: 
Year/Month/DayOfMonth/DayOfWeek/DayOfYear/WeekOfYear/Quarter | covered | 
datetime/datetime.sql |
   | `CometExpressionSuite` | 2308 | dayofweek/weekday over a date column, 
including ancient dates | convert | datetime/dayofweek_weekday.sql (new) |
   | `CometExpressionSuite` | 2334 | from_unixtime | convert | 
datetime/from_unix_time_enabled.sql + a new Asia/Kathmandu variant |
   | `CometTemporalExpressionSuite` | 51 | next_day and make_date ANSI errors 
match Spark exceptions | blocked: #6617 | datetime/next_day_ansi.sql; 
datetime/make_date_ansi.sql |
   | `CometTemporalExpressionSuite` | 82 | trunc (TruncDate) | convert | 
datetime/trunc_date.sql |
   | `CometTemporalExpressionSuite` | 111 | session timezone IDs are normalized 
for native code | keep |  |
   | `CometTemporalExpressionSuite` | 138 | native tzdata version is reported | 
keep |  |
   | `CometTemporalExpressionSuite` | 145 | date_trunc (TruncTimestamp) - 
reading from DataFrame | convert | datetime/trunc_timestamp_formats.sql (new) |
   | `CometTemporalExpressionSuite` | 170 | date_trunc (TruncTimestamp) - 
reading from Parquet | convert | datetime/trunc_timestamp_formats.sql (new) |
   | `CometTemporalExpressionSuite` | 200 | date_trunc - non-UTC timezone 
routes via codegen dispatcher | convert | datetime/trunc_timestamp_dispatch.sql 
(new) |
   | `CometTemporalExpressionSuite` | 222 | date_trunc - non-UTC timezone falls 
back when codegen dispatcher disabled | convert | 
datetime/trunc_timestamp_non_utc_fallback.sql (new) |
   | `CometTemporalExpressionSuite` | 239 | date_trunc - non-UTC timezone takes 
native path when allowIncompatible is enabled | convert | 
datetime/trunc_timestamp_non_utc_native.sql (new) |
   | `CometTemporalExpressionSuite` | 264 | unix_timestamp - timestamp input | 
convert | datetime/unix_timestamp_timezones.sql (new) |
   | `CometTemporalExpressionSuite` | 273 | unix_timestamp - date input | 
convert | datetime/unix_timestamp_timezones.sql (new) |
   | `CometTemporalExpressionSuite` | 285 | unix_timestamp - timestamp_ntz 
input | convert | datetime/unix_timestamp_timezones.sql (new) |
   | `CometTemporalExpressionSuite` | 301 | hour/minute/second - timestamp_ntz 
input | convert | datetime/hour_minute_second_ntz.sql (new) |
   | `CometTemporalExpressionSuite` | 317 | date_trunc - timestamp_ntz input | 
convert | datetime/trunc_timestamp_ntz.sql (new) |
   | `CometTemporalExpressionSuite` | 349 | date_format - timestamp_ntz input | 
convert | datetime/date_format_ntz.sql (new) |
   | `CometTemporalExpressionSuite` | 371 | timestamp_ntz - cross-timezone 
Parquet round-trip | convert | datetime/timestamp_ntz_cross_timezone.sql (new) |
   | `CometTemporalExpressionSuite` | 423 | unix_timestamp - string input uses 
codegen dispatch | convert | datetime/unix_timestamp_strings.sql |
   | `CometTemporalExpressionSuite` | 457 | unix_timestamp - collated strings 
use codegen even when native is opted into | convert | 
datetime/unix_timestamp_collation.sql (new) |
   | `CometTemporalExpressionSuite` | 481 | unix_timestamp - date and timestamp 
inputs ignore collated formats and stay native | convert | 
datetime/unix_timestamp_collation.sql (new) |
   | `CometTemporalExpressionSuite` | 528 | last_day | covered | 
datetime/last_day.sql |
   | `CometTemporalExpressionSuite` | 554 | datediff | covered | 
datetime/date_diff.sql |
   | `CometTemporalExpressionSuite` | 603 | date_format with timestamp column | 
convert | datetime/date_format_native_formats.sql (new) |
   | `CometTemporalExpressionSuite` | 620 | date_format with specific format 
strings | convert | datetime/date_format_native_formats.sql (new) |
   | `CometTemporalExpressionSuite` | 650 | date_format with literal timestamp 
| convert | datetime/date_format_native_formats.sql (new) |
   | `CometTemporalExpressionSuite` | 669 | date_format with null | covered | 
datetime/date_format_enabled.sql |
   | `CometTemporalExpressionSuite` | 678 | date_format unsupported format 
routes via codegen dispatcher | covered | datetime/routing_temporal_enabled.sql 
|
   | `CometTemporalExpressionSuite` | 691 | date_format unsupported format 
falls back when codegen dispatcher disabled | covered | 
datetime/routing_temporal_disabled.sql |
   | `CometTemporalExpressionSuite` | 703 | date_format with non-UTC timezone 
routes via codegen dispatcher | convert | datetime/date_format.sql |
   | `CometTemporalExpressionSuite` | 721 | date_format with non-UTC timezone 
falls back when codegen dispatcher disabled | convert | 
datetime/date_format_non_utc_fallback.sql (new) |
   | `CometTemporalExpressionSuite` | 737 | date_format with non-UTC timezone 
takes native path when allowIncompatible is enabled | convert | 
datetime/date_format_non_utc_native.sql (new) |
   | `CometTemporalExpressionSuite` | 758 | unix_date | convert | 
datetime/unix_date.sql |
   | `CometTemporalExpressionSuite` | 795 | days - date input | keep |  |
   | `CometTemporalExpressionSuite` | 805 | days - timestamp input | keep |  |
   | `CometTemporalExpressionSuite` | 819 | days - literal edge cases | keep |  
|
   | `CometTemporalExpressionSuite` | 885 | hours - timestamp input | keep |  |
   | `CometTemporalExpressionSuite` | 899 | hours - timestamp_ntz input | keep 
|  |
   | `CometTemporalExpressionSuite` | 924 | cast TimestampNTZ to Timestamp - 
DST edge cases | convert | cast/cast_timestamp_ntz.sql |
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to