aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/parser/analyze.c19
-rw-r--r--src/backend/parser/parse_target.c18
-rw-r--r--src/backend/rewrite/rewriteHandler.c6
3 files changed, 34 insertions, 9 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 912aab1a6f7..4b238b91951 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -995,17 +995,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 43a7efeebed..9841894d78c 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -813,7 +813,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,
@@ -943,7 +952,12 @@ transformAssignmentSubscripts(ParseState *pstate,
subscripts,
rhs);
- /* 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 50948d180d0..b16cbd236c1 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -1029,9 +1029,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;