From 24e281c92278ae67a43408b62e641c76fd1ca925 Mon Sep 17 00:00:00 2001 From: Michael Kleen Date: Wed, 3 Jun 2026 10:01:37 +0200 Subject: [PATCH] Make sure cast error from null to non-null apears --- datafusion/physical-expr/src/expressions/cast.rs | 8 ++++---- datafusion/sqllogictest/test_files/struct.slt | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/datafusion/physical-expr/src/expressions/cast.rs b/datafusion/physical-expr/src/expressions/cast.rs index 26f06b546ad1d..37b43d68281bb 100644 --- a/datafusion/physical-expr/src/expressions/cast.rs +++ b/datafusion/physical-expr/src/expressions/cast.rs @@ -50,8 +50,8 @@ const DEFAULT_SAFE_CAST_OPTIONS: CastOptions<'static> = CastOptions { /// planning-time validation matches runtime validation, enabling fail-fast behavior /// instead of deferring errors to execution. Handles structs at any nesting level /// (e.g., `List`, `Dictionary<_, Struct>`). -fn can_cast_named_struct_types(source: &DataType, target: &DataType) -> bool { - validate_data_type_compatibility("", source, target).is_ok() +fn can_cast_named_struct_types(source: &DataType, target: &DataType) -> Result { + validate_data_type_compatibility("", source, target).map(|_| true) } /// CAST expression casts an expression to a specific data type and returns a runtime error on invalid cast @@ -399,7 +399,7 @@ pub fn cast_with_target_field( // applied at planning time (now) to fail fast, rather than deferring errors // to execution time. The name-based casting logic will be executed at runtime // via ColumnarValue::cast_to. - can_cast_named_struct_types(&expr_type, cast_type) + can_cast_named_struct_types(&expr_type, cast_type)? } else { can_cast_types(&expr_type, cast_type) }; @@ -1046,7 +1046,7 @@ mod tests { let err = cast_with_options(col("a", &schema)?, &schema, invalid_target, None) .expect_err("missing required struct field should fail"); - assert!(err.to_string().contains("Unsupported CAST")); + assert!(err.to_string().contains("Cannot cast struct")); Ok(()) } diff --git a/datafusion/sqllogictest/test_files/struct.slt b/datafusion/sqllogictest/test_files/struct.slt index 982e2c6f4acce..d166223eec8f6 100644 --- a/datafusion/sqllogictest/test_files/struct.slt +++ b/datafusion/sqllogictest/test_files/struct.slt @@ -887,9 +887,13 @@ SELECT CAST({a: 1, b: 2, extra: 3} AS STRUCT(a INT, b INT)); {a: 1, b: 2} # Test no overlap with mismatched field count - should fail because no field names match -statement error DataFusion error: (Plan error|Error during planning|This feature is not implemented): (Cannot cast struct: at least one field name must match between source and target|Cannot cast struct with 3 fields to 2 fields without name overlap|Unsupported CAST from Struct) +statement error DataFusion error: Error during planning: Cannot cast struct with 3 fields to 2 SELECT CAST(struct(1, 'x', 'y') AS STRUCT(a INT, b VARCHAR)); +# Cannot cast to nullable struct field to non nullable struct field +statement error Optimizer rule 'simplify_expressions' failed +select arrow_cast(struct(10), 'Struct("c0": non-null Int64)') + # Test nested struct with field reordering query ? SELECT CAST(