-
Notifications
You must be signed in to change notification settings - Fork 387
fix: match Iceberg's rounding for pre-1970 timestamps in native years/months/days/hours #6456
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d9d943c
60037f5
d711633
ccbe740
c5d00f7
8e8513a
69fe5e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -855,8 +855,9 @@ fn file_name_prefix(partition_id: i32, task_attempt_id: i64, operation_id: &str) | |
| /// | ||
| /// This replaces iceberg-rust's `RecordBatchPartitionSplitter`, which computes the values with | ||
| /// iceberg-rust's own transforms -- they turn a `year` or `month` past `chrono`'s calendar into a | ||
| /// NULL (apache/datafusion-comet#6145) -- and groups rows through a HashMap, which emits parts in | ||
| /// unspecified order. | ||
| /// NULL (apache/datafusion-comet#6145) and put some pre-epoch timestamps in a different time | ||
| /// partition from iceberg-java (apache/datafusion-comet#6426) -- and groups rows through a | ||
| /// HashMap, which emits parts in unspecified order. | ||
| struct PartitionSplitter { | ||
| calculator: PartitionValueCalculator, | ||
| partition_spec: PartitionSpecRef, | ||
|
|
@@ -3314,11 +3315,11 @@ mod tests { | |
| /// A partitioned write runs both: the sort in front of [`IcebergWriteExec`] is keyed on the | ||
| /// `datafusion-comet-spark-expr` kernels (Iceberg plans the sort as `bucket(...)`, `days(...)`, | ||
| /// ... system-function calls), while [`ClusteredWriter`] groups the sorted rows by the partition | ||
| /// values that [`PartitionValueCalculator`] computes -- with the same kernels for `years` and | ||
| /// `months`, and with iceberg-rust's transforms for everything else. The writer requires the two | ||
| /// to agree: when they do not it fails at runtime with "The input is not sorted! Cannot write to | ||
| /// partition that was previously closed". These tests make an iceberg-rust bump that changes a | ||
| /// transform break here first. | ||
| /// values that [`PartitionValueCalculator`] computes -- with the same kernels for the time | ||
| /// transforms of dates and timestamps, and with iceberg-rust's transforms for everything else. The | ||
| /// writer requires the two to agree: when they do not it fails at runtime with "The input is not | ||
| /// sorted! Cannot write to partition that was previously closed". These tests make an iceberg-rust | ||
| /// bump that changes a transform break here first. | ||
| #[cfg(test)] | ||
| mod iceberg_rust_transform_parity { | ||
| use arrow::array::{ | ||
|
|
@@ -3569,7 +3570,10 @@ mod iceberg_rust_transform_parity { | |
| } | ||
| } | ||
|
|
||
| /// `days` and `hours` are plain floor division on both sides, so the whole domain agrees. | ||
| /// `days` and `hours` agree with iceberg-rust except on the pre-epoch timestamps where | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: a couple of doc comments the PR doesn't touch still describe the old split. The one on
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed both in d711633, along with two more that a grep turned up: the |
||
| /// iceberg-rust parts from iceberg-java (see `PartitionValueCalculator`), which is why the | ||
| /// writer computes both for timestamps with the Comet kernels; agreeing here means the switch | ||
| /// changed no other value. `day` of a date still goes through iceberg-rust. | ||
| #[test] | ||
| fn days_and_hours_agree_with_iceberg_rust() { | ||
| let micros = vec![ | ||
|
|
@@ -3603,12 +3607,12 @@ mod iceberg_rust_transform_parity { | |
| assert_agree("days(date)", Transform::Day, &days_udf, &dates); | ||
| } | ||
|
|
||
| /// `years` and `months` agree over the dates iceberg-rust can represent -- it splits the | ||
| /// calendar with `chrono`, so anything past year 262142 comes back NULL there while Comet and | ||
| /// the JVM keep going (apache/iceberg-rust#3142; see the kernel's own unit tests for those). | ||
| /// That is why the writer computes these two with the Comet kernels itself | ||
| /// (apache/datafusion-comet#6145); agreeing here means the switch changed no value iceberg-rust | ||
| /// could compute. | ||
| /// `years` and `months` agree over the dates iceberg-rust can represent, apart from the | ||
| /// pre-epoch timestamps where it parts from iceberg-java (see `PartitionValueCalculator`). It | ||
| /// splits the calendar with `chrono`, so anything past year 262142 comes back NULL there while | ||
| /// Comet and the JVM keep going (apache/iceberg-rust#3142; see the kernel's own unit tests for | ||
| /// those). That is why the writer computes these two with the Comet kernels itself | ||
| /// (apache/datafusion-comet#6145); agreeing here means the switch changed no other value. | ||
| #[test] | ||
| fn years_and_months_agree_with_iceberg_rust_within_its_range() { | ||
| let years_udf = SparkIcebergTemporalTransform::years(); | ||
|
|
@@ -3648,14 +3652,17 @@ mod iceberg_rust_transform_parity { | |
| } | ||
| } | ||
|
|
||
| /// Why `years` and `months` are not delegated to iceberg-rust even though `bucket`, `days`, | ||
| /// and `hours` could be: its kernels go through Arrow's `date_part`, which honours the | ||
| /// array's timezone tag, while Iceberg's Java `DateTimeUtil` is always UTC. Comet only ever | ||
| /// produces `UTC` and untagged timestamps today, so the parity above holds; this pins the | ||
| /// reason the local kernel exists. Reported as apache/iceberg-rust#3142; if this ever fails, | ||
| /// iceberg-rust dropped the tag dependency. Delegating is still unsafe until it also covers | ||
| /// dates past `chrono`'s calendar, which the writer's own partition values depend on too: | ||
| /// see `years_and_months_past_chronos_calendar_match_iceberg_java` (`iceberg_partition_value`). | ||
| /// Why `years` and `months` are not delegated to iceberg-rust even though `bucket` could be: | ||
| /// its kernels go through Arrow's `date_part`, which honours the array's timezone tag, while | ||
| /// Iceberg's Java `DateTimeUtil` is always UTC. Comet only ever produces `UTC` and untagged | ||
| /// timestamps today, so the parity above holds; this pins one reason the local kernel exists. | ||
| /// Reported as apache/iceberg-rust#3142; if this ever fails, iceberg-rust dropped the tag | ||
| /// dependency. Delegating is still unsafe until it also covers dates past `chrono`'s calendar, | ||
| /// which the writer's own partition values depend on too: see | ||
| /// `years_and_months_past_chronos_calendar_match_iceberg_java` (`iceberg_partition_value`). | ||
| /// Nor can `days` and `hours` be delegated: all four time transforms place some pre-epoch | ||
| /// timestamps differently from iceberg-java, see | ||
| /// `pre_epoch_timestamps_partition_like_iceberg_java` there. | ||
| #[test] | ||
| fn iceberg_rust_years_follow_the_timezone_tag() { | ||
| // 1969-12-31T23:59:59.999999Z, which is 1970-01-01T05:44:59.999999 in Kathmandu. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: is there an iceberg-rust issue for the truncating
day? I couldn't find one. If not, would it be worth filing one and linking it here, as is done for apache/iceberg-rust#3142 on the year and month tag? That would tell the next reader when this special case can go.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, there isn't one. apache/iceberg-rust#3022 even says
Dayalready aligns with Java, butday_timestamp_microstill truncates the seconds toward zero. I've written one up with a reproducer and a one-line fix, and I'll link it here once it's filed.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed as apache/iceberg-rust#3315, and linked in 8e8513a, both in the doc comment here and in the test that pins iceberg-rust's values. That test will start failing when Comet picks up a fix, which is the cue to look at delegating
dayagain.year,monthandhourwould still need the kernels for the 999999 rows.