1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-03 15:22:11 +03:00

Fix mishandling of OLD/NEW references in subqueries in rule actions.

If a rule action contains a subquery that refers to columns from OLD
or NEW, then those are really lateral references, and the planner will
complain if it sees such things in a subquery that isn't marked as
lateral. However, at rule-definition time, the user isn't required to
mark the subquery with LATERAL, and so it can fail when the rule is
used.

Fix this by marking such subqueries as lateral in the rewriter, at the
point where they're used.

Dean Rasheed and Tom Lane, per report from Alexander Lakhin.
Back-patch to all supported branches.

Discussion: https://postgr.es/m/5e09da43-aaba-7ea7-0a51-a2eb981b058b%40gmail.com
This commit is contained in:
Dean Rasheed
2023-02-25 14:44:49 +00:00
parent 0f78df719a
commit 27ff93d18c
3 changed files with 60 additions and 4 deletions

View File

@@ -3260,6 +3260,31 @@ Rules:
drop table rule_t1, rule_dest;
--
-- Test implicit LATERAL references to old/new in rules
--
CREATE TABLE rule_t1(a int, b text DEFAULT 'xxx', c int);
CREATE VIEW rule_v1 AS SELECT * FROM rule_t1;
CREATE RULE v1_ins AS ON INSERT TO rule_v1
DO ALSO INSERT INTO rule_t1
SELECT * FROM (SELECT a + 10 FROM rule_t1 WHERE a = NEW.a) tt;
CREATE RULE v1_upd AS ON UPDATE TO rule_v1
DO ALSO UPDATE rule_t1 t
SET c = tt.a * 10
FROM (SELECT a FROM rule_t1 WHERE a = OLD.a) tt WHERE t.a = tt.a;
INSERT INTO rule_v1 VALUES (1, 'a'), (2, 'b');
UPDATE rule_v1 SET b = upper(b);
SELECT * FROM rule_t1;
a | b | c
----+-----+-----
1 | A | 10
2 | B | 20
11 | XXX | 110
12 | XXX | 120
(4 rows)
DROP TABLE rule_t1 CASCADE;
NOTICE: drop cascades to view rule_v1
--
-- check alter rename rule
--
CREATE TABLE rule_t1 (a INT);

View File

@@ -1065,6 +1065,23 @@ create rule rr as on update to rule_t1 do instead UPDATE rule_dest trgt
\d+ rule_t1
drop table rule_t1, rule_dest;
--
-- Test implicit LATERAL references to old/new in rules
--
CREATE TABLE rule_t1(a int, b text DEFAULT 'xxx', c int);
CREATE VIEW rule_v1 AS SELECT * FROM rule_t1;
CREATE RULE v1_ins AS ON INSERT TO rule_v1
DO ALSO INSERT INTO rule_t1
SELECT * FROM (SELECT a + 10 FROM rule_t1 WHERE a = NEW.a) tt;
CREATE RULE v1_upd AS ON UPDATE TO rule_v1
DO ALSO UPDATE rule_t1 t
SET c = tt.a * 10
FROM (SELECT a FROM rule_t1 WHERE a = OLD.a) tt WHERE t.a = tt.a;
INSERT INTO rule_v1 VALUES (1, 'a'), (2, 'b');
UPDATE rule_v1 SET b = upper(b);
SELECT * FROM rule_t1;
DROP TABLE rule_t1 CASCADE;
--
-- check alter rename rule
--