Cast a struct column to match target struct fields, handling nested structs recursively. This function implements struct-to-struct casting with the assumption that **structs should always be allowed to cast to other structs**. However, the source column must already be a struct type - non-struct sources will result in an error. ## Field Matching Strategy - **By Name**: Source struct fields are m
(
source_col: &ArrayRef,
target_fields: &[Arc<Field>],
cast_options: &CastOptions,
)
| 54 | /// # Errors |
| 55 | /// Returns a `DataFusionError::Plan` if the source column is not a struct type |
| 56 | fn cast_struct_column( |
| 57 | source_col: &ArrayRef, |
| 58 | target_fields: &[Arc<Field>], |
| 59 | cast_options: &CastOptions, |
| 60 | ) -> Result<ArrayRef> { |
| 61 | if source_col.data_type() == &DataType::Null |
| 62 | || (!source_col.is_empty() && source_col.null_count() == source_col.len()) |
| 63 | { |
| 64 | return Ok(new_null_array( |
| 65 | &Struct(target_fields.to_vec().into()), |
| 66 | source_col.len(), |
| 67 | )); |
| 68 | } |
| 69 | |
| 70 | if let Some(source_struct) = source_col.as_any().downcast_ref::<StructArray>() { |
| 71 | let source_fields = source_struct.fields(); |
| 72 | validate_struct_compatibility(source_fields, target_fields)?; |
| 73 | let mut fields: Vec<Arc<Field>> = Vec::with_capacity(target_fields.len()); |
| 74 | let mut arrays: Vec<ArrayRef> = Vec::with_capacity(target_fields.len()); |
| 75 | let num_rows = source_col.len(); |
| 76 | |
| 77 | // Iterate target fields and pick source child by name when present. |
| 78 | for target_child_field in target_fields.iter() { |
| 79 | fields.push(Arc::clone(target_child_field)); |
| 80 | |
| 81 | let source_child_opt = |
| 82 | source_struct.column_by_name(target_child_field.name()); |
| 83 | |
| 84 | match source_child_opt { |
| 85 | Some(source_child_col) => { |
| 86 | let adapted_child = cast_column( |
| 87 | source_child_col, |
| 88 | target_child_field.data_type(), |
| 89 | cast_options, |
| 90 | ) |
| 91 | .map_err(|e| { |
| 92 | e.context(format!( |
| 93 | "While casting struct field '{}'", |
| 94 | target_child_field.name() |
| 95 | )) |
| 96 | })?; |
| 97 | arrays.push(adapted_child); |
| 98 | } |
| 99 | None => { |
| 100 | arrays.push(new_null_array(target_child_field.data_type(), num_rows)); |
| 101 | } |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | let struct_array = |
| 106 | StructArray::new(fields.into(), arrays, source_struct.nulls().cloned()); |
| 107 | Ok(Arc::new(struct_array)) |
| 108 | } else { |
| 109 | // Return error if source is not a struct type |
| 110 | _plan_err!( |
| 111 | "Cannot cast column of type {} to struct type. Source must be a struct to cast to struct.", |
| 112 | source_col.data_type() |
| 113 | ) |
no test coverage detected
searching dependent graphs…