andygrove opened a new pull request, #6445:
URL: https://github.com/apache/datafusion-comet/pull/6445

   ## Which issue does this PR close?
   
   Closes #5165.
   
   Part of #5149. Timestamp and timestamp_ntz are the last cast targets in that 
epic; the one item left there is filing a separate issue for `to_csv`'s 
whitespace options.
   
   ## Rationale for this change
   
   `CAST(string AS TIMESTAMP)` and `CAST(string AS TIMESTAMP_NTZ)` trimmed 
their input with Rust's `str::trim`, which strips Unicode whitespace. Spark 
trims the `UTF8String.trimAll` byte set (`0x00`-`0x20` and `0x7F`) through 
`SparkDateTimeUtils.getTrimmedStart` / `getTrimmedEnd`, and never trims 
non-ASCII whitespace. So Comet diverged in both directions:
   
   | Input                                           | Spark                    
                  | Comet before this PR                       |
   | ----------------------------------------------- | 
------------------------------------------ | 
------------------------------------------ |
   | `'2020-01-01 12:34:56'` with a leading `0x01`   | `2020-01-01 12:34:56`    
                  | `NULL`, or `CAST_INVALID_INPUT` under ANSI |
   | `'2020-01-01 12:34:56'` with a leading `U+3000` | `NULL`, or 
`CAST_INVALID_INPUT` under ANSI | `2020-01-01 12:34:56`                      |
   
   The second row is a silently wrong result, and under ANSI it swallows the 
error Spark raises.
   
   While checking this I also found that an empty or all-whitespace string 
returned `NULL` under ANSI for both targets. Spark raises `CAST_INVALID_INPUT` 
there: `parseTimestampString` finds no segments, and `stringToTimestampAnsi` / 
`stringToTimestampWithoutTimeZoneAnsi` throw when the parse returns `None`. I 
confirmed this against the Spark 4.1.1 jars; 3.4 and 3.5 take the same path.
   
   This supersedes the trimming half of #5172. The other half of #5165, a 
leading `+` returning `NULL` under ANSI, was already fixed on main by #5858.
   
   ## What changes are included in this PR?
   
   - `timestamp_parser` and `timestamp_ntz_parser` trim with the existing 
`trim_all` helpers from `conversion_funcs::trim` instead of `str::trim`.
   - Spark 4.0+ rejects padding before a time-only `T`, because it only treats 
the `T` as a time-only marker at raw byte 0. That check now uses the trimmed 
start offset instead of `trim_start()`, so a leading ISO control character 
counts as padding there too: `\u0001T2` is `NULL` on 4.0+ and valid on 3.x, as 
in Spark.
   - `cast_utf8_to_timestamp!` no longer calls `trim_end()` on each value 
before parsing. The parsers do all of the trimming now, and that `trim_end()` 
would still have stripped trailing non-ASCII whitespace.
   - A value that trims to nothing raises `CAST_INVALID_INPUT` under ANSI for 
both targets. It still returns `NULL` in legacy and try mode.
   - The compatibility guide no longer lists the divergence, and its trim table 
now includes `TIMESTAMP_NTZ`.
   
   ## How are these changes tested?
   
   - Rust: `assert_trim_parity` now covers timestamp and timestamp_ntz. It runs 
the full codepoint matrix (every byte `0x00`-`0x20`, `0x7F`, and eleven 
non-ASCII whitespace codepoints, in leading, trailing, both-ends, interior and 
padding-only position, plus the empty string) in all three eval modes. This 
replaces the test that pinned the old divergence. 
`test_leading_whitespace_t_hm` gains control-character and `U+3000` cases for 
the Spark 4 check.
   - `CometNativeCastSuite`, with Spark as the oracle:
     - whitespace trim parity tests for timestamp, timestamp_ntz and date (date 
already matched but had only Rust coverage);
     - a per-value ANSI test for inputs that trim to nothing, since the 
batch-wide ANSI comparison in `castTest` only checks that both sides throw 
somewhere in the batch;
     - control-character and `U+3000` cases in the T-hour-only whitespace test.
   - `cast_string_trim.sql` gains timestamp and timestamp_ntz columns.
   
   Locally: `datafusion-comet-spark-expr` tests and clippy pass; the full 
`CometNativeCastSuite` passes on the default Spark 4.1 profile (189 succeeded, 
0 failed); its whitespace tests also pass on `-Pspark-3.5`, which covers the 
Spark 3.x side of the time-only `T` check; and the `expressions/cast` SQL file 
tests pass.
   


-- 
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