diff --git a/native/core/src/execution/shuffle/row.rs b/native/core/src/execution/shuffle/row.rs index 821607ddb9..93eadd8d93 100644 --- a/native/core/src/execution/shuffle/row.rs +++ b/native/core/src/execution/shuffle/row.rs @@ -634,29 +634,42 @@ pub(crate) fn append_columns( let struct_builder = builder .as_any_mut() .downcast_mut::() - .expect("StructBuilder"); - let mut row = SparkUnsafeRow::new(schema); - - for i in row_start..row_end { - let row_addr = unsafe { *row_addresses_ptr.add(i) }; - let row_size = unsafe { *row_sizes_ptr.add(i) }; - row.point_to(row_addr, row_size); + .expect("Should be a StructBuilder"); - let is_null = row.is_null_at(column_idx); - - let nested_row = if is_null { - // The struct is null. - // Append a null value to the struct builder and field builders. - struct_builder.append_null(); - SparkUnsafeRow::default() - } else { - struct_builder.append(true); - row.get_struct(column_idx, fields.len()) - }; + let mut row = SparkUnsafeRow::new(schema); - for (idx, field) in fields.into_iter().enumerate() { - append_field(field.data_type(), struct_builder, &nested_row, idx)?; - } + // 1. Calculate validity and record it in the parent struct + // FIXED: Added underscore prefix to variable name to silence 'unused' error + let _nested_is_null: Vec = (row_start..row_end) + .map(|i| { + let row_addr = unsafe { *row_addresses_ptr.add(i) }; + let row_size = unsafe { *row_sizes_ptr.add(i) }; + row.point_to(row_addr, row_size); + + let is_null = row.is_null_at(column_idx); + + // Record the parent's null status + if is_null { + struct_builder.append_null(); + } else { + struct_builder.append(true); + } + is_null + }) + .collect(); + + // 2. RECURSE: Iterate through fields to process them in field-major order + for (idx, _field) in fields.into_iter().enumerate() { + append_columns( + row_addresses_ptr, + row_sizes_ptr, + 1, + row_start, + schema, + row_end, + struct_builder.field_builder(idx).unwrap(), + prefer_dictionary_ratio, + )?; } } _ => {