sunchao commented on code in PR #5682:
URL: https://github.com/apache/datafusion-comet/pull/5682#discussion_r3964548535


##########
native/spark-expr/src/conversion_funcs/string.rs:
##########
@@ -1636,34 +1641,58 @@ fn extract_offset_suffix(value: &str) -> Option<(&str, 
Tz)> {
 
 type TimestampParsePattern<T> = (&'static Regex, fn(&str, &T) -> 
SparkResult<Option<i64>>);
 
-// RE_YEAR allows only 4-6 digits (not 7) because a bare 7-digit string like 
"0119704"
-// is ambiguous and Spark rejects it. The other patterns (RE_MONTH, RE_DAY, 
etc.) keep
-// \d{4,7} because the `-` separator disambiguates the year portion, so 
"0002020-01-01"
-// is validly year 2020 with leading zeros. date_parser's is_valid_digits also 
allows up
-// to 7 year digits for the same reason.
-static RE_YEAR: LazyLock<Regex> = LazyLock::new(|| 
Regex::new(r"^-?\d{4,6}$").unwrap());
-static RE_MONTH: LazyLock<Regex> = LazyLock::new(|| 
Regex::new(r"^-?\d{4,7}-\d{2}$").unwrap());
-static RE_DAY: LazyLock<Regex> = LazyLock::new(|| 
Regex::new(r"^-?\d{4,7}-\d{2}-\d{2}$").unwrap());
+// These shapes transcribe the per-segment digit rules of Spark's
+// `SparkDateTimeUtils.parseTimestampString` (`isValidDigits`): the year takes 
4-6 digits
+// (`maxDigitsYear = 6`, so "0002020-01-01" is malformed for a timestamp even 
though
+// `stringToDate`, ported by `date_parser`, allows 7), 
month/day/hour/minute/second take 1-2
+// digits each, and the fraction takes any number of digits including none 
("12:34:56." is
+// valid), of which only the first six are kept. All digits must be ASCII, 
matching Spark's
+// byte scanner and the numeric parsers used after shape recognition.
+// Keep the ASCII ranges: Unicode `\d` also costs substantially more to match 
on valid input.
+static RE_YEAR: LazyLock<Regex> = LazyLock::new(|| 
Regex::new(r"^-?[0-9]{4,6}$").unwrap());
+static RE_MONTH: LazyLock<Regex> =
+    LazyLock::new(|| Regex::new(r"^-?[0-9]{4,6}-[0-9]{1,2}$").unwrap());

Review Comment:
   [P1] Guard offset parsing against mixed-width Unicode digits
   
   `2020-1१` (ASCII `1` followed by U+0967, a three-byte digit) matched the 
base's `\d{2}` month pattern, but no longer matches this ASCII pattern. Both 
timestamp parsers then try the date's `-` as an offset sign. 
`parse_sign_offset` sees four bytes after it and `rest[..2]` splits the Unicode 
character, panicking before Legacy/TRY can return NULL or ANSI can raise 
CAST_INVALID_INPUT. The exact head array cast panics for both TIMESTAMP and 
TIMESTAMP_NTZ in all three modes; Spark 4.1.3 rejects the input. Please reject 
non-ASCII offset bytes before fixed-width slicing (or use checked ranges), and 
add Parquet-backed column regressions for mixed ASCII/three-byte Unicode month 
and day digits. The current two-byte Unicode fixtures do not exercise this path.



##########
native/spark-expr/src/conversion_funcs/string.rs:
##########
@@ -1470,7 +1468,14 @@ fn timestamp_parser<T: TimeZone>(
 
     if !has_direct_match {
         if let Some((stripped, suffix_tz)) = extract_offset_suffix(value) {
-            return timestamp_parser_with_tz(stripped, eval_mode, &suffix_tz);
+            // Spark applies Java String.trim to the zone, not Unicode 
whitespace trimming.
+            let stripped = stripped.trim_end_matches(|c: char| c <= '\u{20}');

Review Comment:
   [P2] Reject malformed numeric offsets newly admitted by the prefix trim
   
   `2020-01-01 12:34:56 +08:000` now has its space removed here, passes 
`ends_with_seconds_segment`, and returns `1577853296000000` as TIMESTAMP. The 
base returns NULL (or an ANSI error), as does Spark 4.1.3; `+008:00` and 
`+18:01` have the same new behavior. `parse_sign_offset` parses colon-separated 
parts without a 1–2 digit limit and allows 18 hours plus nonzero minutes before 
normalizing to an Arrow offset. Could we validate the numeric zone's field 
widths and ±18:00 bound before accepting it, with separate column inputs under 
Legacy, TRY and ANSI? This newly accepted spaced TIMESTAMP case is the 
regression here; unspaced malformed offsets and NTZ acceptance already existed 
on the base.



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