* Convert a matched TLE from the original tlist into a correct new TLE. * * This routine detects and handles multiple assignments to the same target * attribute. (The attribute name is needed only for error messages.) */
| 1066 | * attribute. (The attribute name is needed only for error messages.) |
| 1067 | */ |
| 1068 | static TargetEntry * |
| 1069 | process_matched_tle(TargetEntry *src_tle, |
| 1070 | TargetEntry *prior_tle, |
| 1071 | const char *attrName) |
| 1072 | { |
| 1073 | TargetEntry *result; |
| 1074 | CoerceToDomain *coerce_expr = NULL; |
| 1075 | Node *src_expr; |
| 1076 | Node *prior_expr; |
| 1077 | Node *src_input; |
| 1078 | Node *prior_input; |
| 1079 | Node *priorbottom; |
| 1080 | Node *newexpr; |
| 1081 | |
| 1082 | if (prior_tle == NULL) |
| 1083 | { |
| 1084 | /* |
| 1085 | * Normal case where this is the first assignment to the attribute. |
| 1086 | */ |
| 1087 | return src_tle; |
| 1088 | } |
| 1089 | |
| 1090 | /*---------- |
| 1091 | * Multiple assignments to same attribute. Allow only if all are |
| 1092 | * FieldStore or SubscriptingRef assignment operations. This is a bit |
| 1093 | * tricky because what we may actually be looking at is a nest of |
| 1094 | * such nodes; consider |
| 1095 | * UPDATE tab SET col.fld1.subfld1 = x, col.fld2.subfld2 = y |
| 1096 | * The two expressions produced by the parser will look like |
| 1097 | * FieldStore(col, fld1, FieldStore(placeholder, subfld1, x)) |
| 1098 | * FieldStore(col, fld2, FieldStore(placeholder, subfld2, y)) |
| 1099 | * However, we can ignore the substructure and just consider the top |
| 1100 | * FieldStore or SubscriptingRef from each assignment, because it works to |
| 1101 | * combine these as |
| 1102 | * FieldStore(FieldStore(col, fld1, |
| 1103 | * FieldStore(placeholder, subfld1, x)), |
| 1104 | * fld2, FieldStore(placeholder, subfld2, y)) |
| 1105 | * Note the leftmost expression goes on the inside so that the |
| 1106 | * assignments appear to occur left-to-right. |
| 1107 | * |
| 1108 | * For FieldStore, instead of nesting we can generate a single |
| 1109 | * FieldStore with multiple target fields. We must nest when |
| 1110 | * SubscriptingRefs are involved though. |
| 1111 | * |
| 1112 | * As a further complication, the destination column might be a domain, |
| 1113 | * resulting in each assignment containing a CoerceToDomain node over a |
| 1114 | * FieldStore or SubscriptingRef. These should have matching target |
| 1115 | * domains, so we strip them and reconstitute a single CoerceToDomain over |
| 1116 | * the combined FieldStore/SubscriptingRef nodes. (Notice that this has the |
| 1117 | * result that the domain's checks are applied only after we do all the |
| 1118 | * field or element updates, not after each one. This is arguably desirable.) |
| 1119 | *---------- |
| 1120 | */ |
| 1121 | src_expr = (Node *) src_tle->expr; |
| 1122 | prior_expr = (Node *) prior_tle->expr; |
| 1123 | |
| 1124 | if (src_expr && IsA(src_expr, CoerceToDomain) && |
| 1125 | prior_expr && IsA(prior_expr, CoerceToDomain) && |
no test coverage detected