From: Dean Rasheed Date: Sat, 29 Mar 2025 09:58:40 +0000 (+0000) Subject: Fix MERGE with DO NOTHING actions into a partitioned table. X-Git-Tag: REL_18_BETA1~386 X-Git-Url: http://git.postgresql.org/gitweb/?a=commitdiff_plain;h=8b6a0e2392b9fc3f9b821da705797bb54c982dc1;p=postgresql.git Fix MERGE with DO NOTHING actions into a partitioned table. 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 Author: Tender Wang Reviewed-by: Gurjeet Singh Discussion: https://postgr.es/m/18871-b44e3c96de3bd2e8%40postgresql.org Backpatch-through: 15 --- diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 84ccd7d457d..0374476ffad 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -876,7 +876,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) @@ -956,6 +956,8 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate, NULL); break; case CMD_DELETE: + case CMD_NOTHING: + /* Nothing to do */ break; default: diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 87c820276a8..309e27f8b5f 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -3784,7 +3784,7 @@ ExecInitMerge(ModifyTableState *mtstate, EState *estate) case CMD_NOTHING: break; default: - elog(ERROR, "unknown operation"); + elog(ERROR, "unknown action in MERGE WHEN clause"); break; } } diff --git a/src/test/regress/expected/merge.out b/src/test/regress/expected/merge.out index c8ecc8b6b4a..bcd29668297 100644 --- a/src/test/regress/expected/merge.out +++ b/src/test/regress/expected/merge.out @@ -2060,6 +2060,23 @@ SELECT * FROM pa_target ORDER BY tid; 15 | 1500 | initial (8 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 diff --git a/src/test/regress/sql/merge.sql b/src/test/regress/sql/merge.sql index 07b6295b3ba..f7a19c0e7dd 100644 --- a/src/test/regress/sql/merge.sql +++ b/src/test/regress/sql/merge.sql @@ -1271,6 +1271,19 @@ MERGE INTO pa_target t 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