DuanRuixiao opened a new issue, #17501:
URL: https://github.com/apache/iceberg/issues/17501

   ### Apache Iceberg version
   
   1.11.0 (latest release)
   
   ### Query engine
   
   Snowflake
   
   ### Please describe the bug 🐞
   
   ## Bug description
   
   `ValueWriters.FixedByteBufferWriter.write(ByteBuffer, Encoder)` calls 
`encoder.writeBytes(bytes)`
   instead of `encoder.writeFixed(arr, 0, length)`. For Avro `fixed[N]` fields 
this is wrong:
   `writeBytes` prepends a zigzag-encoded length (e.g. `0x06` for a 3-byte 
value) before the data,
   but the Avro reader consumes exactly N bytes for a `fixed` field and has no 
length prefix to skip.
   The stray prefix byte spills into the next field in the record.
   
   **Affected version:** 1.11.0 (also present in prior versions)
   
   ## Where the bug is
   
   `core/src/main/java/org/apache/iceberg/avro/ValueWriters.java`, inner class 
`FixedByteBufferWriter`:
   
   ```java
   private static class FixedByteBufferWriter implements 
ValueWriter<ByteBuffer> {
     private final int length;
   
     @Override
     public void write(ByteBuffer bytes, Encoder encoder) throws IOException {
       Preconditions.checkArgument(bytes.remaining() == length, ...);
       encoder.writeBytes(bytes);   // ← BUG: should be writeFixed
     }
   }
   ```
   
   The sibling class `FixedWriter` (which handles `byte[]`) already does it 
correctly:
   
   ```java
   private static class FixedWriter implements ValueWriter<byte[]> {
     @Override
     public void write(byte[] bytes, Encoder encoder) throws IOException {
       Preconditions.checkArgument(bytes.length == length, ...);
       encoder.writeFixed(bytes);   // ← correct
     }
   }
   ```
   
   ## Concrete corruption example
   
   Writing a `FIXED(3)` partition value `[AB CD EF]` via 
`FixedByteBufferWriter`:
   
   | Encoding | Output bytes | What the reader sees |
   |---|---|---|
   | `writeBytes` (current) | `06 AB CD EF` | `fixed[3]` consumes `06 AB CD`; 
`EF` spills into the next field |
   | `writeFixed` (correct) | `AB CD EF` | `fixed[3]` consumes `AB CD EF` ✓ |
   
   When the spill byte `EF` prefixes the subsequent `record_count` varint `08` 
(zigzag for 4 rows),
   the combined varint `EF 08` decodes to raw value `1135`, which 
zigzag-decodes to `-568`. Every
   reader (Java, native, Spark) trusts this value from the manifest and sees 
`record_count = -568`
   for a file that has 4 rows.
   
   ## How to reproduce
   
   1. Create a partitioned Iceberg table with a `FIXED(3)` identity-partition 
column.
   2. Write a data file via the Iceberg Java writer (triggers `InternalWriter` 
→ `FixedByteBufferWriter`).
   3. Read the written manifest Avro directly and inspect the 
`data_file.record_count` field for the
      partition entry — it will be a large negative number instead of the 
actual row count.
   4. Alternatively: observe that `data_file.partition.val8` in the manifest 
contains `06abcd` instead
      of `abcdef` for a `[AB CD EF]` partition value.
   
   ## Proposed fix
   
   In `FixedByteBufferWriter.write()`, extract the bytes from the `ByteBuffer` 
and call
   `encoder.writeFixed()`:
   
   ```java
   @Override
   public void write(ByteBuffer bytes, Encoder encoder) throws IOException {
     Preconditions.checkArgument(bytes.remaining() == length,
         "Cannot write byte buffer of length %s as fixed[%s]", 
bytes.remaining(), length);
     byte[] arr = new byte[length];
     bytes.duplicate().get(arr);
     encoder.writeFixed(arr);
   }
   ```
   
   A regression test should assert that a round-trip write/read of a manifest 
entry with a `FIXED(N)`
   identity-partition column preserves the exact partition value bytes and the 
correct `record_count`.
   
   ### Willingness to contribute
   
   - [ ] I can contribute a fix for this bug independently
   - [ ] I would be willing to contribute a fix for this bug with guidance from 
the Iceberg community
   - [ ] I cannot contribute a fix for this bug at this time


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