Skip to content

Commit aea1a3f

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 11854de commit aea1a3f

File tree

3 files changed

+69
-9
lines changed

3 files changed

+69
-9
lines changed

src/backend/utils/adt/ruleutils.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8634,12 +8634,17 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
86348634
* We strip any top-level FieldStore or assignment ArrayRef nodes that
86358635
* appear in the input, and return the subexpression that's to be assigned.
86368636
* If printit is true, we also print out the appropriate decoration for the
8637-
* base column name (that the caller just printed).
8637+
* base column name (that the caller just printed). We might also need to
8638+
* strip CoerceToDomain nodes, but only ones that appear above assignment
8639+
* nodes.
8640+
*
8641+
* Returns the subexpression that's to be assigned.
86388642
*/
86398643
static Node *
86408644
processIndirection(Node *node, deparse_context *context, bool printit)
86418645
{
86428646
StringInfo buf = context->buf;
8647+
CoerceToDomain *cdomain = NULL;
86438648

86448649
for (;;)
86458650
{
@@ -8689,10 +8694,28 @@ processIndirection(Node *node, deparse_context *context, bool printit)
86898694
*/
86908695
node = (Node *) aref->refassgnexpr;
86918696
}
8697+
else if (IsA(node, CoerceToDomain))
8698+
{
8699+
cdomain = (CoerceToDomain *) node;
8700+
/* If it's an explicit domain coercion, we're done */
8701+
if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
8702+
break;
8703+
/* Tentatively descend past the CoerceToDomain */
8704+
node = (Node *) cdomain->arg;
8705+
}
86928706
else
86938707
break;
86948708
}
86958709

8710+
/*
8711+
* If we descended past a CoerceToDomain whose argument turned out not to
8712+
* be a FieldStore or array assignment, back up to the CoerceToDomain.
8713+
* (This is not enough to be fully correct if there are nested implicit
8714+
* CoerceToDomains, but such cases shouldn't ever occur.)
8715+
*/
8716+
if (cdomain && node == (Node *) cdomain->arg)
8717+
node = (Node *) cdomain;
8718+
86968719
return node;
86978720
}
86988721

src/test/regress/expected/domain.out

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -266,20 +266,48 @@ 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+
Has OIDs: no
310+
283311
drop table dcomptable;
284312
drop type comptype cascade;
285313
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)