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

   ## Apache Iceberg Rust version
   
   main (also affects 0.6.0)
   
   ## Describe the bug
   
   When a projected field is not present in a data file, 
`RecordBatchTransformer` resolves it using the spec's Column Projection 
fallback rules. For a field with no `initial-default`, it always produces a 
null column (rule #4). This is correct for optional fields, but wrong for 
required fields.
   
   The spec's Default values section states that null is only a valid default 
for an optional field:
   
   > If either default is not set for an optional field, then the default value 
is null for compatibility with older spec versions.
   
   So a required field that is absent from a data file with no 
`initial-default` has no valid value. Producing a null column for it violates 
the field's required (non-nullable) constraint. In practice the transformer 
builds a non-nullable Arrow array containing nulls, which fails later with a 
confusing message rather than a clear error:
   
   ```
   Arrow Schema Error: Invalid argument error: Column '<name>' is declared as 
non-nullable but contains null values
   ```
   
   Iceberg-Java raises a clear error for this case instead. In 
`core/.../data/parquet/BaseParquetReaders.java` and 
`spark/.../data/SparkParquetReaders.java`, the reader's field-resolution 
precedence is: file value, then `initialDefault`, then null if optional, then 
throw:
   
   ```java
   private ParquetValueReader<?> defaultReader(Types.NestedField field, 
ParquetValueReader<?> reader, int constantDL) {
     if (reader != null) {
       return reader;
     } else if (field.initialDefault() != null) {
       return ParquetValueReaders.constant(..., constantDL);
     } else if (field.isOptional()) {
       return ParquetValueReaders.nulls();
     }
     throw new IllegalArgumentException(String.format("Missing required field: 
%s", field.name()));
   }
   ```
   
   iceberg-rust implements the first three cases but silently falls through to 
null for the fourth.
   
   ## To Reproduce
   
   Project a schema whose required field is absent from the data file and has 
no `initial-default`:
   
   ```rust
   // snapshot schema: required(1, "id", Int), required(2, "missing_str", 
String)
   // data file schema: only field id 1 ("id")
   // project field ids [1, 2]
   let mut transformer = RecordBatchTransformerBuilder::new(snapshot_schema, 
&[1, 2]).build();
   transformer.process_record_batch(file_batch_with_only_id)?; // <- produces a 
null column for "missing_str"
   ```
   
   Actual: the transformer builds a null column for the required `missing_str`, 
which later fails with `Column 'missing_str' is declared as non-nullable but 
contains null values`.
   
   ## Expected behavior
   
   Resolution of a field absent from the data file should mirror the spec (and 
Iceberg-Java): file value, then `initial-default`, then null if the field is 
optional, otherwise error. A required field absent with no `initial-default` 
should fail with a clear error, `Missing required field: <name>`, rather than 
producing an invalid null column.
   
   ## Willingness to contribute
   
   I can contribute a fix for this bug independently.
   
   ---
   
   ### Proposed fix
   
   In `crates/iceberg/src/arrow/record_batch_transformer.rs`, in the "not 
present" fallback (before choosing `initial_default` or null), add the 
required-field case:
   
   ```rust
   if iceberg_field.initial_default.is_none() && iceberg_field.required {
       return Err(Error::new(
           ErrorKind::DataInvalid,
           format!("Missing required field: {}", iceberg_field.name),
       ));
   }
   ```
   
   Tested with a required-field-absent case (asserts the error) and an 
optional-field-absent case (asserts null), pinning the precedence.
   
   ### References
   
   - Iceberg spec, "Default values" (null is only a valid default for optional 
fields) and "Column Projection" rules: 
https://iceberg.apache.org/spec/#default-values
   - Iceberg-Java reference behavior: 
`core/src/main/java/org/apache/iceberg/data/parquet/BaseParquetReaders.java` 
and `spark/.../data/SparkParquetReaders.java` (`Missing required field`).
   


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