Xuanwo commented on code in PR #25122:
URL: https://github.com/apache/datafusion/pull/25122#discussion_r3988047972


##########
datafusion/functions/src/core/getfield.rs:
##########
@@ -236,9 +251,19 @@ fn extract_single_field(base: ColumnarValue, name: 
ScalarValue) -> Result<Column
         }
         (DataType::Struct(_), _, Some(k)) => {
             let as_struct_array = as_struct_array(&array)?;
-            match as_struct_array.column_by_name(&k) {
-                None => exec_err!("Field {k} not found in struct"),
-                Some(col) => Ok(ColumnarValue::Array(Arc::clone(col))),
+            let nulls = as_struct_array.nulls();
+            match (as_struct_array.column_by_name(&k), nulls) {
+                (None, _) => exec_err!("Field {k} not found in struct"),
+                (Some(col), None) => Ok(ColumnarValue::Array(Arc::clone(col))),
+                (Some(col), Some(parent_nulls)) => {
+                    // NullArray is already entirely null and cannot have a 
validity bitmap.
+                    if col.data_type().is_null() {
+                        return Ok(ColumnarValue::Array(Arc::clone(col)));
+                    }
+                    let nulls = NullBuffer::union(col.nulls(), 
Some(parent_nulls));
+                    let data = 
col.to_data().into_builder().nulls(nulls).build()?;

Review Comment:
   There is one remaining edge case here: extracting a Union child from a 
nullable Struct now fails with `cannot contain a null bitmask`. Union arrays 
cannot carry a validity bitmap, so excluding only `DataType::Null` does not 
cover every child type.
   
   I would treat this as a non-blocking follow-up, since the previous 
implementation also lost the parent’s nulls for this case.
   
   <details>
   <summary>Reproducer</summary>
   
   Tested on `8a137f8b45b9404381758348de7f4673bca07fe9`. Add this to the 
existing tests in `getfield.rs` and run:
   
   ```sh
   cargo test -p datafusion-functions --lib review_get_field_union_parent_nulls 
--locked
   ```
   
   ```rust
   #[test]
   fn review_get_field_union_parent_nulls() -> Result<()> {
       use arrow::array::UnionArray;
       use arrow::datatypes::UnionFields;
       use arrow_buffer::ScalarBuffer;
       let child = UnionArray::try_new(
           UnionFields::try_new([0], [Field::new("value", DataType::Int32, 
true)])?,
           ScalarBuffer::from(vec![0_i8, 0, 0]),
           None,
           vec![Arc::new(Int32Array::from(vec![1, 2, 3]))],
       )?;
       let parent = StructArray::new(
           vec![Field::new("u", child.data_type().clone(), true)].into(),
           vec![Arc::new(child)],
           Some(NullBuffer::from(vec![true, false, true])),
       );
       let func = GetFieldFunc::new();
       let name = ScalarValue::Utf8(Some("u".to_string()));
       let arg_fields = vec![
           Arc::new(Field::new("s", parent.data_type().clone(), true)),
           Arc::new(Field::new("name", DataType::Utf8, false)),
       ];
       let return_field = func.return_field_from_args(ReturnFieldArgs {
           arg_fields: &arg_fields,
           scalar_arguments: &[None, Some(&name)],
       })?;
       let result = func.invoke_with_args(ScalarFunctionArgs {
           args: vec![ColumnarValue::Array(Arc::new(parent)), 
ColumnarValue::Scalar(name)],
           arg_fields,
           number_rows: 3,
           return_field,
           config_options: Default::default(),
       })?.into_array(3)?;
       assert_eq!(result.logical_nulls(), Some(NullBuffer::from(vec![true, 
false, true])));
       Ok(())
   }
   ```
   
   The call errors before reaching the assertion.
   
   </details>



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