From: Peter Eisentraut Date: Mon, 27 Apr 2026 08:29:21 +0000 (+0200) Subject: Fix DELETE/UPDATE FOR PORTION OF with rules X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=33db6c4baf17e0fdf2ac08f7d050155985c0d7e3;p=thirdparty%2Fpostgresql.git Fix DELETE/UPDATE FOR PORTION OF with rules Previously, these test cases would give internal errors or crash. The fix is to add some missing fields of ForPortionOfExpr to expression_tree_walker. Author: jian he Reviewed-by: Kirill Reshke Reviewed-by: Paul A Jungwirth Discussion: https://postgr.es/m/CACJufxHs1Hs00EqsZ4NbuAjmYzMzjJyP1sAj12Ne=cBsEVmQOA@mail.gmail.com --- diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index c0b880ec233..7edbd5b7225 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -2583,6 +2583,8 @@ expression_tree_walker_impl(Node *node, { ForPortionOfExpr *forPortionOf = (ForPortionOfExpr *) node; + if (WALK(forPortionOf->rangeVar)) + return true; if (WALK(forPortionOf->targetFrom)) return true; if (WALK(forPortionOf->targetTo)) @@ -2591,6 +2593,8 @@ expression_tree_walker_impl(Node *node, return true; if (WALK(forPortionOf->overlapsExpr)) return true; + if (WALK(forPortionOf->rangeTargetList)) + return true; } break; case T_PartitionPruneStepOp: diff --git a/src/test/regress/expected/for_portion_of.out b/src/test/regress/expected/for_portion_of.out index 31f772c723d..0c0a205c44b 100644 --- a/src/test/regress/expected/for_portion_of.out +++ b/src/test/regress/expected/for_portion_of.out @@ -2097,4 +2097,59 @@ SELECT * FROM temporal_partitioned_5 ORDER BY id, valid_at; (4 rows) DROP TABLE temporal_partitioned; +-- UPDATE/DELETE FOR PORTION OF with RULEs +CREATE TABLE fpo_rule (f1 bigint, f2 int4range); +INSERT INTO fpo_rule VALUES (1, '[1, 11)'); +CREATE RULE fpo_rule1 AS ON INSERT TO fpo_rule + DO INSTEAD UPDATE fpo_rule FOR PORTION OF f2 FROM 1 TO 4 SET f1 = 2; +INSERT INTO fpo_rule VALUES (1, '[1, 11)'); +SELECT * FROM fpo_rule ORDER BY f1; + f1 | f2 +----+-------- + 1 | [4,11) + 2 | [1,4) +(2 rows) + +CREATE RULE fpo_rule2 AS ON INSERT TO fpo_rule + DO INSTEAD DELETE FROM fpo_rule FOR PORTION OF f2 FROM 1 TO 4; +INSERT INTO fpo_rule VALUES (1, '[1, 11)'); +SELECT * FROM fpo_rule ORDER BY f1; + f1 | f2 +----+-------- + 1 | [4,11) +(1 row) + +CREATE RULE fpo_rule3 AS ON DELETE TO fpo_rule + DO INSTEAD UPDATE fpo_rule FOR PORTION OF f2 FROM 1 TO 8 SET f1 = 2; +DELETE FROM fpo_rule FOR PORTION OF f2 FROM 1 TO 5; +SELECT * FROM fpo_rule ORDER BY f1; + f1 | f2 +----+-------- + 1 | [8,11) + 2 | [4,8) +(2 rows) + +DROP RULE fpo_rule3 ON fpo_rule; +CREATE RULE fpo_rule4 AS ON UPDATE TO fpo_rule + DO INSTEAD DELETE FROM fpo_rule FOR PORTION OF f2 FROM 6 TO 9; +UPDATE fpo_rule FOR PORTION OF f2 FROM 4 TO 9 SET f1 = 12; +SELECT * FROM fpo_rule ORDER BY f1; + f1 | f2 +----+-------- + 1 | [9,11) + 2 | [4,6) +(2 rows) + +DROP RULE fpo_rule4 ON fpo_rule; +CREATE RULE fpo_rule5 AS ON UPDATE TO fpo_rule + DO ALSO DELETE FROM fpo_rule FOR PORTION OF f2 FROM 4 TO 6; +UPDATE fpo_rule FOR PORTION OF f2 FROM 9 TO 10 SET f1 = 3; +SELECT * FROM fpo_rule ORDER BY f1; + f1 | f2 +----+--------- + 1 | [10,11) + 3 | [9,10) +(2 rows) + +DROP TABLE fpo_rule; RESET datestyle; diff --git a/src/test/regress/sql/for_portion_of.sql b/src/test/regress/sql/for_portion_of.sql index d4062acf1d1..fd79a9b78e7 100644 --- a/src/test/regress/sql/for_portion_of.sql +++ b/src/test/regress/sql/for_portion_of.sql @@ -1365,4 +1365,37 @@ SELECT * FROM temporal_partitioned_5 ORDER BY id, valid_at; DROP TABLE temporal_partitioned; +-- UPDATE/DELETE FOR PORTION OF with RULEs +CREATE TABLE fpo_rule (f1 bigint, f2 int4range); +INSERT INTO fpo_rule VALUES (1, '[1, 11)'); + +CREATE RULE fpo_rule1 AS ON INSERT TO fpo_rule + DO INSTEAD UPDATE fpo_rule FOR PORTION OF f2 FROM 1 TO 4 SET f1 = 2; +INSERT INTO fpo_rule VALUES (1, '[1, 11)'); +SELECT * FROM fpo_rule ORDER BY f1; + +CREATE RULE fpo_rule2 AS ON INSERT TO fpo_rule + DO INSTEAD DELETE FROM fpo_rule FOR PORTION OF f2 FROM 1 TO 4; +INSERT INTO fpo_rule VALUES (1, '[1, 11)'); +SELECT * FROM fpo_rule ORDER BY f1; + +CREATE RULE fpo_rule3 AS ON DELETE TO fpo_rule + DO INSTEAD UPDATE fpo_rule FOR PORTION OF f2 FROM 1 TO 8 SET f1 = 2; +DELETE FROM fpo_rule FOR PORTION OF f2 FROM 1 TO 5; +SELECT * FROM fpo_rule ORDER BY f1; + +DROP RULE fpo_rule3 ON fpo_rule; +CREATE RULE fpo_rule4 AS ON UPDATE TO fpo_rule + DO INSTEAD DELETE FROM fpo_rule FOR PORTION OF f2 FROM 6 TO 9; +UPDATE fpo_rule FOR PORTION OF f2 FROM 4 TO 9 SET f1 = 12; +SELECT * FROM fpo_rule ORDER BY f1; + +DROP RULE fpo_rule4 ON fpo_rule; +CREATE RULE fpo_rule5 AS ON UPDATE TO fpo_rule + DO ALSO DELETE FROM fpo_rule FOR PORTION OF f2 FROM 4 TO 6; +UPDATE fpo_rule FOR PORTION OF f2 FROM 9 TO 10 SET f1 = 3; +SELECT * FROM fpo_rule ORDER BY f1; + +DROP TABLE fpo_rule; + RESET datestyle;