zhangfengcdt opened a new issue, #3326:
URL: https://github.com/apache/iceberg-rust/issues/3326

   ### Apache Iceberg Rust version
   
   `main`. Verified at `1960386` (2026-10-01).
   
   ### Describe the bug
   
   `PartitionSpec::partition_to_path` formats `float` / `double` partition 
values differently from iceberg-java. Rust uses the float's `Display` output; 
Java uses `Float.toString` / `Double.toString`. They disagree for whole 
numbers, for values Java prints in scientific notation, and for infinities.
   
   Paths for a `double` column `d` with an identity partition (Java column from 
iceberg 1.11.0):
   
   | Value | iceberg-rust | iceberg-java |
   | --- | --- | --- |
   | `1.0` | `d=1` | `d=1.0` |
   | `100.0` | `d=100` | `d=100.0` |
   | `0.0` | `d=0` | `d=0.0` |
   | `-0.0` | `d=-0` | `d=-0.0` |
   | `1.0e7` | `d=10000000` | `d=1.0E7` |
   | `1.0e-5` | `d=0.00001` | `d=1.0E-5` |
   | `1.23456789e20` | `d=123456789000000000000` | `d=1.23456789E20` |
   | `+Infinity` | `d=inf` | `d=Infinity` |
   | `-Infinity` | `d=-inf` | `d=-Infinity` |
   
   `1.5`, `0.001` and `NaN` already match. `float` columns show the same 
pattern.
   
   The call path is `partition_to_path` → `Transform::to_human_string` → 
`Datum::to_human_string` → `Display for Datum`, which writes the float with 
`{val}`. In Java, `PartitionSpec.partitionToPath` → 
`Transform.toHumanString(Type, T)` falls through to `value.toString()`.
   
   This does not affect reads: readers take partition values from manifests, 
and the spec does not define the path layout. The path is used in two places:
   
   - Data file locations (`location_generator.rs`). A table written by both 
implementations gets two directories for one partition value, for example 
`d=1/` and `d=1.0/`.
   - Keys of the per-partition snapshot summary, `partitions.<path>` 
(`snapshot_summary.rs`). Java builds these keys from `partitionToPath` too, so 
the same partition gets different keys depending on the writer.
   
   ### To Reproduce
   
   ```rust
   use iceberg::spec::{Literal, PrimitiveType, Transform, Type};
   
   let double = Type::Primitive(PrimitiveType::Double);
   let human = |v: f64| Transform::Identity.to_human_string(&double, 
Some(&Literal::double(v)));
   
   // All pass today. iceberg-java gives "1.0", "-0.0", "1.0E7" and "Infinity".
   assert_eq!(human(1.0), "1");
   assert_eq!(human(-0.0), "-0");
   assert_eq!(human(1.0e7), "10000000");
   assert_eq!(human(f64::INFINITY), "inf");
   ```
   
   ### Expected behavior
   
   `float` / `double` values are formatted as Java's `Float.toString` / 
`Double.toString` do:
   
   - at least one digit after the decimal point (`1.0`, `-0.0`);
   - plain decimal when `1e-3 <= |v| < 1e7`, otherwise scientific notation such 
as `1.0E7` and `1.0E-5`;
   - `Infinity` / `-Infinity` for infinities.
   
   Changing this changes the directory that new files are written to in tables 
already written by iceberg-rust. Existing files stay valid, because manifests 
store full paths.
   
   ### Willingness to contribute
   
   None
   
   ### Additional context
   
   Found while investigating #3325. It is independent of that issue: the cause 
is value formatting, not partition equality.
   
   #3022 aligned the human strings of the date and time transforms with Java in 
the same function.
   


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