@@ -988,6 +988,72 @@ static bool CombineUnequalTypes(const LogicalType &left, const LogicalType &righ
988
988
return false ;
989
989
}
990
990
991
+ template <class OP >
992
+ static bool CombineStructTypes (const LogicalType &left, const LogicalType &right, LogicalType &result) {
993
+ auto &left_children = StructType::GetChildTypes (left);
994
+ auto &right_children = StructType::GetChildTypes (right);
995
+
996
+ auto left_unnamed = StructType::IsUnnamed (left);
997
+ auto is_unnamed = left_unnamed || StructType::IsUnnamed (right);
998
+ child_list_t <LogicalType> child_types;
999
+
1000
+ // At least one side is unnamed, so we attempt positional casting.
1001
+ if (is_unnamed) {
1002
+ if (left_children.size () != right_children.size ()) {
1003
+ // We can't cast, or create the super-set.
1004
+ return false ;
1005
+ }
1006
+
1007
+ for (idx_t i = 0 ; i < left_children.size (); i++) {
1008
+ LogicalType child_type;
1009
+ if (!OP::Operation (left_children[i].second , right_children[i].second , child_type)) {
1010
+ return false ;
1011
+ }
1012
+ auto &child_name = left_unnamed ? right_children[i].first : left_children[i].first ;
1013
+ child_types.emplace_back (child_name, std::move (child_type));
1014
+ }
1015
+ result = LogicalType::STRUCT (child_types);
1016
+ return true ;
1017
+ }
1018
+
1019
+ // Create a super-set of the STRUCT fields.
1020
+ // First, create a name->index map of the right children.
1021
+ case_insensitive_map_t <idx_t > right_children_map;
1022
+ for (idx_t i = 0 ; i < right_children.size (); i++) {
1023
+ auto &name = right_children[i].first ;
1024
+ right_children_map[name] = i;
1025
+ }
1026
+
1027
+ for (idx_t i = 0 ; i < left_children.size (); i++) {
1028
+ auto &left_child = left_children[i];
1029
+ auto right_child_it = right_children_map.find (left_child.first );
1030
+
1031
+ if (right_child_it == right_children_map.end ()) {
1032
+ // We can directly put the left child.
1033
+ child_types.emplace_back (left_child.first , left_child.second );
1034
+ continue ;
1035
+ }
1036
+
1037
+ // We need to recurse to ensure the children have a maximum logical type.
1038
+ LogicalType child_type;
1039
+ auto &right_child = right_children[right_child_it->second ];
1040
+ if (!OP::Operation (left_child.second , right_child.second , child_type)) {
1041
+ return false ;
1042
+ }
1043
+ child_types.emplace_back (left_child.first , std::move (child_type));
1044
+ right_children_map.erase (right_child_it);
1045
+ }
1046
+
1047
+ // Add all remaining right children.
1048
+ for (const auto &right_child_it : right_children_map) {
1049
+ auto &right_child = right_children[right_child_it.second ];
1050
+ child_types.emplace_back (right_child.first , right_child.second );
1051
+ }
1052
+
1053
+ result = LogicalType::STRUCT (child_types);
1054
+ return true ;
1055
+ }
1056
+
991
1057
template <class OP >
992
1058
static bool CombineEqualTypes (const LogicalType &left, const LogicalType &right, LogicalType &result) {
993
1059
// Since both left and right are equal we get the left type as our type_id for checks
@@ -1059,31 +1125,7 @@ static bool CombineEqualTypes(const LogicalType &left, const LogicalType &right,
1059
1125
return true ;
1060
1126
}
1061
1127
case LogicalTypeId::STRUCT: {
1062
- // struct: perform recursively on each child
1063
- auto &left_child_types = StructType::GetChildTypes (left);
1064
- auto &right_child_types = StructType::GetChildTypes (right);
1065
- bool left_unnamed = StructType::IsUnnamed (left);
1066
- auto any_unnamed = left_unnamed || StructType::IsUnnamed (right);
1067
- if (left_child_types.size () != right_child_types.size ()) {
1068
- // child types are not of equal size, we can't cast
1069
- // return false
1070
- return false ;
1071
- }
1072
- child_list_t <LogicalType> child_types;
1073
- for (idx_t i = 0 ; i < left_child_types.size (); i++) {
1074
- LogicalType child_type;
1075
- // Child names must be in the same order OR either one of the structs must be unnamed
1076
- if (!any_unnamed && !StringUtil::CIEquals (left_child_types[i].first , right_child_types[i].first )) {
1077
- return false ;
1078
- }
1079
- if (!OP::Operation (left_child_types[i].second , right_child_types[i].second , child_type)) {
1080
- return false ;
1081
- }
1082
- auto &child_name = left_unnamed ? right_child_types[i].first : left_child_types[i].first ;
1083
- child_types.emplace_back (child_name, std::move (child_type));
1084
- }
1085
- result = LogicalType::STRUCT (child_types);
1086
- return true ;
1128
+ return CombineStructTypes<OP>(left, right, result);
1087
1129
}
1088
1130
case LogicalTypeId::UNION: {
1089
1131
auto left_member_count = UnionType::GetMemberCount (left);
0 commit comments