Skip to content
This repository was archived by the owner on Apr 1, 2026. It is now read-only.

Commit 233cfb2

Browse files
fix: add map coercion for binary ops
(cherry picked from commit 946446a)
1 parent 28451b5 commit 233cfb2

1 file changed

Lines changed: 65 additions & 0 deletions

File tree

  • datafusion/expr-common/src/type_coercion

datafusion/expr-common/src/type_coercion/binary.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,7 @@ pub fn comparison_coercion(lhs_type: &DataType, rhs_type: &DataType) -> Option<D
733733
.or_else(|| string_temporal_coercion(lhs_type, rhs_type))
734734
.or_else(|| binary_coercion(lhs_type, rhs_type))
735735
.or_else(|| struct_coercion(lhs_type, rhs_type))
736+
.or_else(|| map_coercion(lhs_type, rhs_type))
736737
}
737738

738739
/// Similar to [`comparison_coercion`] but prefers numeric if compares with
@@ -987,6 +988,25 @@ fn coerce_fields(common_type: DataType, lhs: &FieldRef, rhs: &FieldRef) -> Field
987988
Arc::new(Field::new(name, common_type, is_nullable))
988989
}
989990

991+
/// coerce two types if they are Maps by coercing their inner 'entries' fields' types
992+
/// using struct coercion
993+
fn map_coercion(lhs_type: &DataType, rhs_type: &DataType) -> Option<DataType> {
994+
use arrow::datatypes::DataType::*;
995+
match (lhs_type, rhs_type) {
996+
(Map(lhs_field, lhs_ordered), Map(rhs_field, rhs_ordered)) => {
997+
struct_coercion(lhs_field.data_type(), rhs_field.data_type()).map(
998+
|key_value_type| {
999+
Map(
1000+
Arc::new((**lhs_field).clone().with_data_type(key_value_type)),
1001+
*lhs_ordered && *rhs_ordered,
1002+
)
1003+
},
1004+
)
1005+
}
1006+
_ => None,
1007+
}
1008+
}
1009+
9901010
/// Returns the output type of applying mathematics operations such as
9911011
/// `+` to arguments of `lhs_type` and `rhs_type`.
9921012
fn mathematics_numerical_coercion(
@@ -2483,4 +2503,49 @@ mod tests {
24832503
);
24842504
Ok(())
24852505
}
2506+
2507+
#[test]
2508+
fn test_map_coercion() -> Result<()> {
2509+
let lhs = Field::new_map(
2510+
"lhs",
2511+
"entries",
2512+
Arc::new(Field::new("keys", DataType::Utf8, false)),
2513+
Arc::new(Field::new("values", DataType::LargeUtf8, false)),
2514+
true,
2515+
false,
2516+
);
2517+
let rhs = Field::new_map(
2518+
"rhs",
2519+
"kvp",
2520+
Arc::new(Field::new("k", DataType::Utf8, false)),
2521+
Arc::new(Field::new("v", DataType::Utf8, true)),
2522+
false,
2523+
true,
2524+
);
2525+
2526+
let expected = Field::new_map(
2527+
"expected",
2528+
"entries", // struct coercion takes lhs name
2529+
Arc::new(Field::new(
2530+
"keys", // struct coercion takes lhs name
2531+
DataType::Utf8,
2532+
false,
2533+
)),
2534+
Arc::new(Field::new(
2535+
"values", // struct coercion takes lhs name
2536+
DataType::LargeUtf8, // lhs is large string
2537+
true, // rhs is nullable
2538+
)),
2539+
false, // both sides must be sorted
2540+
true, // rhs is nullable
2541+
);
2542+
2543+
test_coercion_binary_rule!(
2544+
lhs.data_type(),
2545+
rhs.data_type(),
2546+
Operator::Eq,
2547+
expected.data_type().clone()
2548+
);
2549+
Ok(())
2550+
}
24862551
}

0 commit comments

Comments
 (0)