]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix MERGE with DO NOTHING actions into a partitioned table.
authorDean Rasheed <dean.a.rasheed@gmail.com>
Sat, 29 Mar 2025 09:51:23 +0000 (09:51 +0000)
committerDean Rasheed <dean.a.rasheed@gmail.com>
Sat, 29 Mar 2025 09:51:23 +0000 (09:51 +0000)
ExecInitPartitionInfo() duplicates much of the logic in
ExecInitMerge(), except that it failed to handle DO NOTHING
actions. This would cause an "unknown action in MERGE WHEN clause"
error if a MERGE with any DO NOTHING actions attempted to insert into
a partition not already initialised by ExecInitModifyTable().

Bug: #18871
Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: Tender Wang <tndrwang@gmail.com>
Reviewed-by: Gurjeet Singh <gurjeet@singh.im>
Discussion: https://postgr.es/m/18871-b44e3c96de3bd2e8%40postgresql.org
Backpatch-through: 15

src/backend/executor/execPartition.c
src/backend/executor/nodeModifyTable.c
src/test/regress/expected/merge.out
src/test/regress/sql/merge.sql

index 6de40aacfa541a0ccd6dd55cf0256bf92066b1ce..f56117bbae8e7e68ce4836da36438abfced70ea6 100644 (file)
@@ -873,7 +873,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
         * reference and make copy for this relation, converting stuff that
         * references attribute numbers to match this relation's.
         *
-        * This duplicates much of the logic in ExecInitMerge(), so something
+        * This duplicates much of the logic in ExecInitMerge(), so if something
         * changes there, look here too.
         */
        if (node && node->operation == CMD_MERGE)
@@ -944,6 +944,8 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
                                                                                                  NULL);
                                        break;
                                case CMD_DELETE:
+                               case CMD_NOTHING:
+                                       /* Nothing to do */
                                        break;
 
                                default:
index b4cd02786954e1263904f9fffc7f98a18854deba..94d7117ad61dba23ae8a541394fbcff60533af1a 100644 (file)
@@ -3443,7 +3443,7 @@ ExecInitMerge(ModifyTableState *mtstate, EState *estate)
                                case CMD_NOTHING:
                                        break;
                                default:
-                                       elog(ERROR, "unknown operation");
+                                       elog(ERROR, "unknown action in MERGE WHEN clause");
                                        break;
                        }
                }
index bc9a59803fce5c496cdd53c7a944c4d3351b0339..5d1be9f6b24589df2a01b255cbf091dc0d002909 100644 (file)
@@ -1698,6 +1698,23 @@ SELECT * FROM pa_target ORDER BY tid;
   14 |     140 | inserted by merge
 (14 rows)
 
+ROLLBACK;
+-- bug #18871: ExecInitPartitionInfo()'s handling of DO NOTHING actions
+BEGIN;
+TRUNCATE pa_target;
+MERGE INTO pa_target t
+  USING (VALUES (10, 100)) AS s(sid, delta)
+  ON t.tid = s.sid
+  WHEN NOT MATCHED THEN
+    INSERT VALUES (1, 10, 'inserted by merge')
+  WHEN MATCHED THEN
+    DO NOTHING;
+SELECT * FROM pa_target ORDER BY tid, val;
+ tid | balance |        val        
+-----+---------+-------------------
+   1 |      10 | inserted by merge
+(1 row)
+
 ROLLBACK;
 DROP TABLE pa_target CASCADE;
 -- The target table is partitioned in the same way, but this time by attaching
index 2a220a248f1d05d217bcd1a3ae74240438eb73a1..4609241b2a580f138fe8a15d37ad77e2026a6433 100644 (file)
@@ -1060,6 +1060,19 @@ SELECT merge_func();
 SELECT * FROM pa_target ORDER BY tid;
 ROLLBACK;
 
+-- bug #18871: ExecInitPartitionInfo()'s handling of DO NOTHING actions
+BEGIN;
+TRUNCATE pa_target;
+MERGE INTO pa_target t
+  USING (VALUES (10, 100)) AS s(sid, delta)
+  ON t.tid = s.sid
+  WHEN NOT MATCHED THEN
+    INSERT VALUES (1, 10, 'inserted by merge')
+  WHEN MATCHED THEN
+    DO NOTHING;
+SELECT * FROM pa_target ORDER BY tid, val;
+ROLLBACK;
+
 DROP TABLE pa_target CASCADE;
 
 -- The target table is partitioned in the same way, but this time by attaching