/*
* We must dig down into the expr to see if it's a PARAM_MULTIEXPR
* Param. That could be buried under FieldStores and ArrayRefs
- * (cf processIndirection()), and underneath those there could be
- * an implicit type coercion.
+ * and CoerceToDomains (cf processIndirection()), and underneath
+ * those there could be an implicit type coercion. Because we
+ * would ignore implicit type coercions anyway, we don't need to
+ * be as careful as processIndirection() is about descending past
+ * implicit CoerceToDomains.
*/
expr = (Node *) tle->expr;
while (expr)
break;
expr = (Node *) aref->refassgnexpr;
}
+ else if (IsA(expr, CoerceToDomain))
+ {
+ CoerceToDomain *cdomain = (CoerceToDomain *) expr;
+
+ if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
+ break;
+ expr = (Node *) cdomain->arg;
+ }
else
break;
}
*
* We strip any top-level FieldStore or assignment ArrayRef nodes that
* appear in the input, printing them as decoration for the base column
- * name (which we assume the caller just printed). Return the subexpression
- * that's to be assigned.
+ * name (which we assume the caller just printed). We might also need to
+ * strip CoerceToDomain nodes, but only ones that appear above assignment
+ * nodes.
+ *
+ * Returns the subexpression that's to be assigned.
*/
static Node *
processIndirection(Node *node, deparse_context *context)
{
StringInfo buf = context->buf;
+ CoerceToDomain *cdomain = NULL;
for (;;)
{
*/
node = (Node *) aref->refassgnexpr;
}
+ else if (IsA(node, CoerceToDomain))
+ {
+ cdomain = (CoerceToDomain *) node;
+ /* If it's an explicit domain coercion, we're done */
+ if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
+ break;
+ /* Tentatively descend past the CoerceToDomain */
+ node = (Node *) cdomain->arg;
+ }
else
break;
}
+ /*
+ * If we descended past a CoerceToDomain whose argument turned out not to
+ * be a FieldStore or array assignment, back up to the CoerceToDomain.
+ * (This is not enough to be fully correct if there are nested implicit
+ * CoerceToDomains, but such cases shouldn't ever occur.)
+ */
+ if (cdomain && node == (Node *) cdomain->arg)
+ node = (Node *) cdomain;
+
return node;
}
ERROR: value for domain dcomptypea violates check constraint "c1"
update dcomptable set d1[1].r = d1[1].r + 1 where d1[1].i > 0; -- fail
ERROR: value for domain dcomptypea violates check constraint "c1"
-update dcomptable set d1[1].r = d1[1].r - 1 where d1[1].i > 0;
+update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
+ where d1[1].i > 0;
select * from dcomptable;
d1
--------------------
{"(11,)","(,)"}
{"(99,)"}
- {"(1,2)","(,)"}
- {"(3,4)","(6,5)"}
- {"(7,8)","(10,9)"}
- {"(9,10)","(,)"}
- {"(0,2)"}
- {"(98,100)"}
+ {"(1,3)","(,)"}
+ {"(3,5)","(6,5)"}
+ {"(7,9)","(10,9)"}
+ {"(9,11)","(,)"}
+ {"(0,3)"}
+ {"(98,101)"}
(8 rows)
+explain (verbose, costs off)
+ update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
+ where d1[1].i > 0;
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------------
+ Update on public.dcomptable
+ -> Seq Scan on public.dcomptable
+ Output: (d1[1].r := (d1[1].r - '1'::double precision))[1].i := (d1[1].i + '1'::double precision), ctid
+ Filter: (dcomptable.d1[1].i > '0'::double precision)
+(4 rows)
+
+create rule silly as on delete to dcomptable do instead
+ update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
+ where d1[1].i > 0;
+\d+ dcomptable
+ Table "public.dcomptable"
+ Column | Type | Modifiers | Storage | Stats target | Description
+--------+------------+-----------+----------+--------------+-------------
+ d1 | dcomptypea | | extended | |
+Indexes:
+ "dcomptable_d1_key" UNIQUE CONSTRAINT, btree (d1)
+Rules:
+ silly AS
+ ON DELETE TO dcomptable DO INSTEAD UPDATE dcomptable SET d1[1].r = dcomptable.d1[1].r - 1::double precision, d1[1].i = dcomptable.d1[1].i + 1::double precision
+ WHERE dcomptable.d1[1].i > 0::double precision
+
drop table dcomptable;
drop type comptype cascade;
NOTICE: drop cascades to type dcomptypea
insert into dcomptable (d1[1].r, d1[1].i) values(99, 100);
insert into dcomptable (d1[1].r, d1[1].i) values(100, 99); -- fail
update dcomptable set d1[1].r = d1[1].r + 1 where d1[1].i > 0; -- fail
-update dcomptable set d1[1].r = d1[1].r - 1 where d1[1].i > 0;
+update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
+ where d1[1].i > 0;
select * from dcomptable;
+explain (verbose, costs off)
+ update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
+ where d1[1].i > 0;
+create rule silly as on delete to dcomptable do instead
+ update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
+ where d1[1].i > 0;
+\d+ dcomptable
+
drop table dcomptable;
drop type comptype cascade;