Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
summaryrefslogtreecommitdiff
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 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;