mirror of
https://github.com/postgres/postgres.git
synced 2025-06-18 00:02:37 -04:00
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 b1cb32fb6, this bug is reachable in cases we already support, so back-patch all the way.
This commit is contained in:
parent
11854dee01
commit
aea1a3f0eb
@ -8634,12 +8634,17 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
|
||||
* We strip any top-level FieldStore or assignment ArrayRef nodes that
|
||||
* appear in the input, and return the subexpression that's to be assigned.
|
||||
* If printit is true, we also print out the appropriate decoration for the
|
||||
* base column name (that the caller just printed).
|
||||
* base column name (that 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, bool printit)
|
||||
{
|
||||
StringInfo buf = context->buf;
|
||||
CoerceToDomain *cdomain = NULL;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@ -8689,10 +8694,28 @@ processIndirection(Node *node, deparse_context *context, bool printit)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -266,20 +266,48 @@ insert into dcomptable (d1[1].r, d1[1].i) values(100, 99); -- 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; -- 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
|
||||
Has OIDs: no
|
||||
|
||||
drop table dcomptable;
|
||||
drop type comptype cascade;
|
||||
NOTICE: drop cascades to type dcomptypea
|
||||
|
@ -150,9 +150,18 @@ insert into dcomptable (d1[1].r) values(99);
|
||||
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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user