Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit ff2d537

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 bbeec3c commit ff2d537

File tree

3 files changed

+81
-12
lines changed

3 files changed

+81
-12
lines changed

src/backend/utils/adt/ruleutils.c

+37-4
Original file line numberDiff line numberDiff line change
@@ -5832,8 +5832,11 @@ get_update_query_targetlist_def(Query *query, List *targetList,
58325832
/*
58335833
* We must dig down into the expr to see if it's a PARAM_MULTIEXPR
58345834
* Param. That could be buried under FieldStores and ArrayRefs
5835-
* (cf processIndirection()), and underneath those there could be
5836-
* an implicit type coercion.
5835+
* and CoerceToDomains (cf processIndirection()), and underneath
5836+
* those there could be an implicit type coercion. Because we
5837+
* would ignore implicit type coercions anyway, we don't need to
5838+
* be as careful as processIndirection() is about descending past
5839+
* implicit CoerceToDomains.
58375840
*/
58385841
expr = (Node *) tle->expr;
58395842
while (expr)
@@ -5852,6 +5855,14 @@ get_update_query_targetlist_def(Query *query, List *targetList,
58525855
break;
58535856
expr = (Node *) aref->refassgnexpr;
58545857
}
5858+
else if (IsA(expr, CoerceToDomain))
5859+
{
5860+
CoerceToDomain *cdomain = (CoerceToDomain *) expr;
5861+
5862+
if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
5863+
break;
5864+
expr = (Node *) cdomain->arg;
5865+
}
58555866
else
58565867
break;
58575868
}
@@ -9553,13 +9564,17 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
95539564
*
95549565
* We strip any top-level FieldStore or assignment ArrayRef nodes that
95559566
* appear in the input, printing them as decoration for the base column
9556-
* name (which we assume the caller just printed). Return the subexpression
9557-
* that's to be assigned.
9567+
* name (which we assume the caller just printed). We might also need to
9568+
* strip CoerceToDomain nodes, but only ones that appear above assignment
9569+
* nodes.
9570+
*
9571+
* Returns the subexpression that's to be assigned.
95589572
*/
95599573
static Node *
95609574
processIndirection(Node *node, deparse_context *context)
95619575
{
95629576
StringInfo buf = context->buf;
9577+
CoerceToDomain *cdomain = NULL;
95639578

95649579
for (;;)
95659580
{
@@ -9607,10 +9622,28 @@ processIndirection(Node *node, deparse_context *context)
96079622
*/
96089623
node = (Node *) aref->refassgnexpr;
96099624
}
9625+
else if (IsA(node, CoerceToDomain))
9626+
{
9627+
cdomain = (CoerceToDomain *) node;
9628+
/* If it's an explicit domain coercion, we're done */
9629+
if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
9630+
break;
9631+
/* Tentatively descend past the CoerceToDomain */
9632+
node = (Node *) cdomain->arg;
9633+
}
96109634
else
96119635
break;
96129636
}
96139637

9638+
/*
9639+
* If we descended past a CoerceToDomain whose argument turned out not to
9640+
* be a FieldStore or array assignment, back up to the CoerceToDomain.
9641+
* (This is not enough to be fully correct if there are nested implicit
9642+
* CoerceToDomains, but such cases shouldn't ever occur.)
9643+
*/
9644+
if (cdomain && node == (Node *) cdomain->arg)
9645+
node = (Node *) cdomain;
9646+
96149647
return node;
96159648
}
96169649

src/test/regress/expected/domain.out

+34-7
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

+10-1
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)