diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/parser/analyze.c | 19 | ||||
-rw-r--r-- | src/backend/parser/parse_target.c | 18 | ||||
-rw-r--r-- | src/backend/rewrite/rewriteHandler.c | 6 |
3 files changed, 34 insertions, 9 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 2255314c519..7f23d18b370 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -1070,17 +1070,28 @@ transformInsertRow(ParseState *pstate, List *exprlist, if (strip_indirection) { + /* + * We need to remove top-level FieldStores and SubscriptingRefs, + * as well as any CoerceToDomain appearing above one of those --- + * but not a CoerceToDomain that isn't above one of those. + */ while (expr) { - if (IsA(expr, FieldStore)) + Expr *subexpr = expr; + + while (IsA(subexpr, CoerceToDomain)) + { + subexpr = ((CoerceToDomain *) subexpr)->arg; + } + if (IsA(subexpr, FieldStore)) { - FieldStore *fstore = (FieldStore *) expr; + FieldStore *fstore = (FieldStore *) subexpr; expr = (Expr *) linitial(fstore->newvals); } - else if (IsA(expr, SubscriptingRef)) + else if (IsA(subexpr, SubscriptingRef)) { - SubscriptingRef *sbsref = (SubscriptingRef *) expr; + SubscriptingRef *sbsref = (SubscriptingRef *) subexpr; if (sbsref->refassgnexpr == NULL) break; diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index f10fc420e60..5b92502b217 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -820,7 +820,16 @@ transformAssignmentIndirection(ParseState *pstate, fstore->fieldnums = list_make1_int(attnum); fstore->resulttype = baseTypeId; - /* If target is a domain, apply constraints */ + /* + * If target is a domain, apply constraints. Notice that this + * isn't totally right: the expression tree we build would check + * the domain's constraints on a composite value with only this + * one field populated or updated, possibly leading to an unwanted + * failure. The rewriter will merge together any subfield + * assignments to the same table column, resulting in the domain's + * constraints being checked only once after we've assigned to all + * the fields that the INSERT or UPDATE means to. + */ if (baseTypeId != targetTypeId) return coerce_to_domain((Node *) fstore, baseTypeId, baseTypeMod, @@ -966,7 +975,12 @@ transformAssignmentSubscripts(ParseState *pstate, result = (Node *) sbsref; - /* If target was a domain over container, need to coerce up to the domain */ + /* + * If target was a domain over container, need to coerce up to the domain. + * As in transformAssignmentIndirection, this coercion is premature if the + * query assigns to multiple elements of the container; but we'll fix that + * during query rewrite. + */ if (containerType != targetTypeId) { Oid resulttype = exprType(result); diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 89187d9af2e..7a46e8b3541 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -1086,9 +1086,9 @@ process_matched_tle(TargetEntry *src_tle, * resulting in each assignment containing a CoerceToDomain node over a * FieldStore or SubscriptingRef. These should have matching target * domains, so we strip them and reconstitute a single CoerceToDomain over - * the combined FieldStore/SubscriptingRef nodes. (Notice that this has the - * result that the domain's checks are applied only after we do all the - * field or element updates, not after each one. This is arguably desirable.) + * the combined FieldStore/SubscriptingRef nodes. (Notice that this has + * the result that the domain's checks are applied only after we do all + * the field or element updates, not after each one. This is desirable.) *---------- */ src_expr = (Node *) src_tle->expr; |