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 <jian.universality@gmail.com>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Reviewed-by: Paul A Jungwirth <pj@illuminatedcomputing.com>
Discussion: https://postgr.es/m/CACJufxHs1Hs00EqsZ4NbuAjmYzMzjJyP1sAj12Ne=cBsEVmQOA@mail.gmail.com
This commit is contained in:
Peter Eisentraut 2026-04-27 10:29:21 +02:00
parent 31b9d90f15
commit 33db6c4baf
3 changed files with 92 additions and 0 deletions

View file

@ -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:

View file

@ -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;

View file

@ -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;