LuciferYang opened a new pull request, #68148:
URL: https://github.com/apache/doris/pull/68148

   ### What problem does this PR solve?
   
   Issue Number: close #68118
   
   Problem Summary:
   
   The v1 Parquet reader turns a TIMESTAMP column's min/max into a zone map 
without the safety the v2 reader has, so pruning can drop matching rows. Both 
defects are in `ParquetPredicate::parse_min_max_value` 
(`be/src/format/parquet/parquet_predicate.h`), v1 only 
(`enable_file_scanner_v2` defaults true).
   
   An adjusted-to-UTC INT64 timestamp mapped to DATETIMEV2 has its physical 
min/max converted to local civil time. That conversion is not monotonic across 
a backward clock transition: in `America/New_York`, UTC `[05:30, 06:30]` 
converts to civil `[01:30, 01:30]`, while an interior `05:59` converts to 
`01:59`, outside the converted range. `dt > '2021-11-07 01:45:00'` then prunes 
a row group that has a matching row. The v2 reader fences this with 
`timestamp_min_max_is_safe` / `utc_timestamp_range_is_monotonic`; v1 had no 
equivalent.
   
   Separately, the INT96 / DATETIMEV2 branch read both local operands from 
`min_field`:
   
   ```cpp
   auto min_value = min_field->get<TYPE_DATETIMEV2>();
   auto max_value = min_field->get<TYPE_DATETIMEV2>();
   ...
   if (min_value != max_value) { return Status::DataQualityError(...); }
   ```
   
   so the `min_value != max_value` check compared a value with itself and never 
fired. That check exists to reject legacy INT96 stats whose ordering is 
unreliable (PARQUET-1065). The footer path is still covered by 
`read_column_stats`, which rejects unequal INT96 stats before this point; the 
page-index path reaches `parse_min_max_value` directly and was left exposed.
   
   The `INT96 || DATETIMEV2` branch is split in two. The output fields 
`min_field` / `max_field` are set correctly upstream, so only the validation 
changes.
   
   - INT96: reject when the raw encoded bounds differ (`encoded_min != 
encoded_max`), comparing physical bytes rather than converted values. A 
single-point range cannot span a transition, so it needs no clock fence.
   - DATETIMEV2 (reached only by INT64 physical): a new helper 
`adjusted_utc_timestamp_range_is_monotonic` mirrors the unit / adjusted-to-UTC 
derivation in `TimestampConverter::init` (including the legacy `converted_type` 
TIMESTAMP_MILLIS / MICROS), decodes the raw INT64 range, and defers the 
transition check to the shared v2 helper 
`format::utc_timestamp_range_is_monotonic`. A non-adjusted timestamp is 
displayed in UTC (no transitions) and stays usable; TIMESTAMPTZ never reaches 
this branch, so it is exempt, matching v2.
   
   An unusable range returns `DataQualityError`, which every caller already 
turns into no zone map / no pruning, not a scan error.
   
   ### Release note
   
   Fixed a bug where reading a Parquet TIMESTAMP column with the v1 scanner 
could drop matching rows when the min/max range crossed a daylight-saving clock 
rollback.
   
   ### Check List (For Author)
   
   - Test <!-- At least one of them must be included. -->
       - [ ] Regression test
       - [X] Unit Test
       - [ ] Manual test (add detailed scripts or steps below)
       - [ ] No need to test or manual test. Explain why:
           - [ ] This is a refactor/code format and no logic has been changed.
           - [ ] Previous test can cover this change.
           - [ ] No code files have been changed.
           - [ ] Other reason <!-- Add your reason?  -->
   
   `ParseMinMaxRejectsTimestampRangeCrossingClockRollback` drives 
`parse_min_max_value` with a synthetic adjusted-to-UTC INT64 timestamp schema 
under `America/New_York`: a range crossing the 2021-11-07 fall-back is 
rejected, a transition-free range that day stays usable, a spring-forward range 
is not rejected for crossing the gap, and the same fall-back range stays usable 
when the column is not adjusted to UTC. `ParseMinMaxAppliesInt96SingletonRule` 
checks that equal INT96 encoded bounds stay usable and unequal ones are 
rejected. Both were mutation-checked: neutering the clock fence fails the 
first, neutering the INT96 comparison fails the second.
   
   The end-to-end path the issue asks for, a v1 scan 
(`enable_file_scanner_v2=false`, `time_zone='America/New_York'`) over a real 
Parquet file whose row group and page index span the rollback, needs a 
checked-in Parquet artifact this change cannot synthesize; the unit tests pin 
the parser directly, and the file-backed regression is a follow-up.
   
   ### Behavior changed:
   
   - [ ] No.
   - [X] Yes.
   
   A v1 Parquet TIMESTAMP min/max range that crosses a backward clock 
transition, and an INT96 range with differing bounds reached through the page 
index, no longer drive pruning. Ranges that were already usable are unaffected.
   
   ### Does this need documentation?
   
   - [X] No.
   


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