]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix DELETE/UPDATE FOR PORTION OF with rules
authorPeter Eisentraut <peter@eisentraut.org>
Mon, 27 Apr 2026 08:29:21 +0000 (10:29 +0200)
committerPeter Eisentraut <peter@eisentraut.org>
Mon, 27 Apr 2026 08:34:06 +0000 (10:34 +0200)
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

src/backend/nodes/nodeFuncs.c
src/test/regress/expected/for_portion_of.out
src/test/regress/sql/for_portion_of.sql

index c0b880ec233b222480f8a3fbd54524afca6fd601..7edbd5b72259d91309543828b3c60582c6c60c9c 100644 (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:
index 31f772c723d5b8df164b194d82e26c429b80b349..0c0a205c44b6ae6b93074f644727b5742dc7f5f9 100644 (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;
index d4062acf1d19fed0f3645aaf88a8d7eb437dc769..fd79a9b78e739252252bd3af7c7bb806fd9a64f8 100644 (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;