Skip to content

Commit a2320b3

Browse files
committed
Fix ruleutils.c for domain-over-array cases, too.
Further investigation shows that ruleutils isn't quite up to speed either for cases where we have a domain-over-array: it needs to be prepared to look past a CoerceToDomain at the top level of field and element assignments, else it decompiles them incorrectly. Potentially this would result in failure to dump/reload a rule, if it looked like the one in the new test case. (I also added a test for EXPLAIN; that output isn't broken, but clearly we need more test coverage here.) Like commit b1cb32f, this bug is reachable in cases we already support, so back-patch all the way.
1 parent 8529028 commit a2320b3

File tree

3 files changed

+68
-9
lines changed

3 files changed

+68
-9
lines changed

src/backend/utils/adt/ruleutils.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8910,12 +8910,17 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
89108910
* We strip any top-level FieldStore or assignment ArrayRef nodes that
89118911
* appear in the input, and return the subexpression that's to be assigned.
89128912
* If printit is true, we also print out the appropriate decoration for the
8913-
* base column name (that the caller just printed).
8913+
* base column name (that the caller just printed). We might also need to
8914+
* strip CoerceToDomain nodes, but only ones that appear above assignment
8915+
* nodes.
8916+
*
8917+
* Returns the subexpression that's to be assigned.
89148918
*/
89158919
static Node *
89168920
processIndirection(Node *node, deparse_context *context, bool printit)
89178921
{
89188922
StringInfo buf = context->buf;
8923+
CoerceToDomain *cdomain = NULL;
89198924

89208925
for (;;)
89218926
{
@@ -8965,10 +8970,28 @@ processIndirection(Node *node, deparse_context *context, bool printit)
89658970
*/
89668971
node = (Node *) aref->refassgnexpr;
89678972
}
8973+
else if (IsA(node, CoerceToDomain))
8974+
{
8975+
cdomain = (CoerceToDomain *) node;
8976+
/* If it's an explicit domain coercion, we're done */
8977+
if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
8978+
break;
8979+
/* Tentatively descend past the CoerceToDomain */
8980+
node = (Node *) cdomain->arg;
8981+
}
89688982
else
89698983
break;
89708984
}
89718985

8986+
/*
8987+
* If we descended past a CoerceToDomain whose argument turned out not to
8988+
* be a FieldStore or array assignment, back up to the CoerceToDomain.
8989+
* (This is not enough to be fully correct if there are nested implicit
8990+
* CoerceToDomains, but such cases shouldn't ever occur.)
8991+
*/
8992+
if (cdomain && node == (Node *) cdomain->arg)
8993+
node = (Node *) cdomain;
8994+
89728995
return node;
89738996
}
89748997

src/test/regress/expected/domain.out

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -266,20 +266,47 @@ insert into dcomptable (d1[1].r, d1[1].i) values(100, 99); -- fail
266266
ERROR: value for domain dcomptypea violates check constraint "c1"
267267
update dcomptable set d1[1].r = d1[1].r + 1 where d1[1].i > 0; -- fail
268268
ERROR: value for domain dcomptypea violates check constraint "c1"
269-
update dcomptable set d1[1].r = d1[1].r - 1 where d1[1].i > 0;
269+
update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
270+
where d1[1].i > 0;
270271
select * from dcomptable;
271272
d1
272273
--------------------
273274
{"(11,)","(,)"}
274275
{"(99,)"}
275-
{"(1,2)","(,)"}
276-
{"(3,4)","(6,5)"}
277-
{"(7,8)","(10,9)"}
278-
{"(9,10)","(,)"}
279-
{"(0,2)"}
280-
{"(98,100)"}
276+
{"(1,3)","(,)"}
277+
{"(3,5)","(6,5)"}
278+
{"(7,9)","(10,9)"}
279+
{"(9,11)","(,)"}
280+
{"(0,3)"}
281+
{"(98,101)"}
281282
(8 rows)
282283

284+
explain (verbose, costs off)
285+
update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
286+
where d1[1].i > 0;
287+
QUERY PLAN
288+
------------------------------------------------------------------------------------------------------------
289+
Update on public.dcomptable
290+
-> Seq Scan on public.dcomptable
291+
Output: (d1[1].r := (d1[1].r - 1::double precision))[1].i := (d1[1].i + 1::double precision), ctid
292+
Filter: (dcomptable.d1[1].i > 0::double precision)
293+
(4 rows)
294+
295+
create rule silly as on delete to dcomptable do instead
296+
update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
297+
where d1[1].i > 0;
298+
\d+ dcomptable
299+
Table "public.dcomptable"
300+
Column | Type | Modifiers | Storage | Stats target | Description
301+
--------+------------+-----------+----------+--------------+-------------
302+
d1 | dcomptypea | | extended | |
303+
Indexes:
304+
"dcomptable_d1_key" UNIQUE CONSTRAINT, btree (d1)
305+
Rules:
306+
silly AS
307+
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
308+
WHERE dcomptable.d1[1].i > 0::double precision
309+
283310
drop table dcomptable;
284311
drop type comptype cascade;
285312
NOTICE: drop cascades to type dcomptypea

src/test/regress/sql/domain.sql

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,18 @@ insert into dcomptable (d1[1].r) values(99);
150150
insert into dcomptable (d1[1].r, d1[1].i) values(99, 100);
151151
insert into dcomptable (d1[1].r, d1[1].i) values(100, 99); -- fail
152152
update dcomptable set d1[1].r = d1[1].r + 1 where d1[1].i > 0; -- fail
153-
update dcomptable set d1[1].r = d1[1].r - 1 where d1[1].i > 0;
153+
update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
154+
where d1[1].i > 0;
154155
select * from dcomptable;
155156

157+
explain (verbose, costs off)
158+
update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
159+
where d1[1].i > 0;
160+
create rule silly as on delete to dcomptable do instead
161+
update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
162+
where d1[1].i > 0;
163+
\d+ dcomptable
164+
156165
drop table dcomptable;
157166
drop type comptype cascade;
158167

0 commit comments

Comments
 (0)