mbutrovich opened a new issue, #3387: URL: https://github.com/apache/iceberg-rust/issues/3387
## Apache Iceberg Rust version main (b2e90754b1f9eaea741d353d51ae644aa9cef479), also v0.10.1 ## Describe the bug Format v3 allows promoting `date` to `timestamp` and `timestamp_ns` ([spec](https://github.com/apache/iceberg/blob/5e7169168db3d34e29354c6f59ec4d6e420b8d2d/format/spec.md?plain=1#L356-L362)). Type promotion doesn't rewrite existing bounds, so a reader must decode a 4-byte bound on a `timestamp` or `timestamp_ns` column as a `date` ([spec](https://github.com/apache/iceberg/blob/5e7169168db3d34e29354c6f59ec4d6e420b8d2d/format/spec.md?plain=1#L366-L377)). `Datum::try_from_bytes` reads `timestamp` and `timestamp_ns` bounds only as 8 bytes ([`datum.rs#L408-L416`](https://github.com/apache/iceberg-rust/blob/b2e90754b1f9eaea741d353d51ae644aa9cef479/crates/iceberg/src/spec/values/datum.rs#L408-L416)), and returns an error for 4 bytes. The `long` arm already handles the 4-byte `int` case from the same table ([`datum.rs#L385-L392`](https://github.com/apache/iceberg-rust/blob/b2e90754b1f9eaea741d353d51ae644aa9cef479/crates/iceberg/src/spec/values/datum.rs#L385-L392)), and so does the `double` arm for `float`. Manifest parsing decodes every bound and returns the first error ([`_serde.rs#L263-L282`](https://github.com/apache/iceberg-rust/blob/b2e90754b1f9eaea741d353d51ae644aa9cef479/crates/iceberg/src/spec/manifest/_serde.rs#L263-L282)). One such bound fails the whole manifest read, including for scans that don't filter on that column. No writer I know of produces these bounds yet. Java's `TypeUtil.isPromotionAllowed` doesn't allow `date` to `timestamp` ([`TypeUtil.java#L471-L497`](https://github.com/apache/iceberg/blob/5e7169168db3d34e29354c6f59ec4d6e420b8d2d/api/src/main/java/org/apache/iceberg/types/TypeUtil.java#L471-L497)), and neither do PyIceberg or iceberg-rust's `UpdateSchemaAction`. The read fails as soon as an engine implements the promotion. ## To Reproduce ```rust use iceberg::spec::{Datum, PrimitiveType}; // 2026-10-09, written while the column was a `date`. let bytes = 20_735i32.to_le_bytes(); // Err(DataInvalid => failed to convert byte slice to array) Datum::try_from_bytes(&bytes, PrimitiveType::Timestamp); // Err(DataInvalid => failed to convert byte slice to array) Datum::try_from_bytes(&bytes, PrimitiveType::TimestampNs); ``` ## Expected behavior A 4-byte bound on a `timestamp` column decodes as a `date` and converts to microseconds since the epoch (days times 86,400,000,000). On a `timestamp_ns` column it converts to nanoseconds (days times 86,400,000,000,000). A day count whose product doesn't fit in an `i64` returns an error, because the spec requires values outside the promoted type's range to fail at runtime. A 4-byte bound on `timestamptz` or `timestamptz_ns` stays an error, since the spec doesn't allow promoting `date` to those types. ## Willingness to contribute I can contribute a fix for this bug independently -- 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]
