fix(variant): convert shredded timestamps to the column's time unit - #882
jackylee-ch wants to merge 1 commit into
Conversation
|
Reviewed head b75b8b9. Requirement fit: SUPPORTED. The seven focused shredded-timestamp tests pass, but two follow-ups remain. Integration/rebase follow-up: main commit d05cb03 (#884) added |
JingsongLi
left a comment
There was a problem hiding this comment.
Reviewed head a9eff7c6. Fixing the Arrow unit mismatch has real end-to-end value, especially for spec-conforming files written by another engine. The precision-zero reconciliation and old-writer fixture address parts of my earlier comment. I found two production blockers:
[P1] New writes silently change a Variant timestamp that the declared leaf cannot represent. try_typed_shred (crates/paimon/src/variant.rs:2998-3003) puts any microsecond timestamp into typed_value. The new timestamp_array conversion (crates/paimon/src/arrow/shredding/variant.rs:1058-1068) floors it to seconds/millis, and reassembly reconstructs from that rounded typed value because the original value is absent. I ran a temporary complete Variant shred→assemble roundtrip: a TIMESTAMP_NTZ value of 1_700_000_000_123_456 microseconds with a TIMESTAMP(3) shredding schema came back as 1_700_000_000_123_000. Please keep the original Variant in the value fallback when it is not exactly representable in the typed leaf, and add a persisted-file roundtrip test. The same representability check should send a valid microsecond timestamp outside the nanosecond leaf's range to value instead of failing the entire write batch.
[P1] The on-disk unit change needs an executable migration and rollout path. For explicit shredding schemas at precision 0–3 or 7–9, a new reader reinterprets old Rust files, while an old reader misinterprets newly written conforming files. The old-writer unit test now documents one wrong-result case, but it does not prevent mixed-version reads/writes or identify which existing files need rewriting; precision-zero historical files need coverage too. Before a production merge, please document how to inventory affected tables/files, stop or coordinate old writers/readers, rewrite affected data using a version that still interprets it correctly, verify values, and roll back safely. Otherwise this can silently change persisted timestamps during a rolling upgrade.
Validation: all 20 arrow::shredding::variant::tests passed and head CI is green. My temporary full roundtrip regression failed with the exact values above, then I removed it and restored a clean checkout. The Parquet Variant shredding specification permits retaining an unrepresentable typed value in the Variant value field.
ShreddedValue::Timestamp always carries microseconds, but timestamp_array wrote that integer into an Arrow array whose unit follows the declared precision, and timestamp_value_at read it back unconverted, so outside precision 4..=6 both sides were off by 1000x. Precision 7..=9 maps to a NANOS leaf that parquet-format permits, so a conforming file from another engine was mis-read too. Convert on both sides instead of reinterpreting: the write scales micros to the leaf unit and rejects micros beyond i64 nanoseconds; the read keys off the array's own TimeUnit so a foreign file decodes from its own schema. Precision 0 follows apache#884's SECOND leaf. Files written before this fix at precision outside 4..=6 hold micros under a MILLIS/NANOS annotation with no marker to tell them apart, so a legacy read mode is not implementable and such columns must be rewritten; a migration fixture documents the reinterpretation.
a9eff7c to
a1baa6e
Compare
|
Rebased onto main. Precision-0 SECOND arm + tests, plus a rewrite policy and migration fixture. |
|
Re-reviewed head The two P1 production blockers from my previous review remain unresolved:
The rebase/merge conflict concern is resolved. I am leaving the PR open for these fixes. |
|
Closing in favor of #983. This PR rescales the shredded timestamp to the column's declared precision, but the Parquet Variant shredding spec requires a shredded timestamp |
ShreddedValue::Timestampis always micros, but the shredded leaf's Arrow unit follows the declared precision (MILLIS <4, MICROS 4..=6, NANOS >6). Both sides passed the integer through unchanged, so a TIMESTAMP leaf outside 4..=6 was 1000x off. A NANOS leaf is spec-conforming, so foreign files were mis-read too.Write now scales micros to the leaf unit, flooring into MILLIS, and errors on micros beyond i64 nanoseconds (~1677..2262) instead of wrapping. Read keys off the array's TimeUnit, so a foreign file decodes from its own schema.
Disclosure: files paimon-rust already wrote outside 4..=6 hold micros under a MILLIS/NANOS annotation. They read back correctly only because the reader repeated the mistake; after this change they decode 1000x wrong, and nothing in the file tells them apart. Only an explicit
variant.shreddingSchemaproduces such a leaf — inference picks precision 6.