Skip to content

Commit 7b14e20

Browse files
committed
Fix MERGE command tag for actions blocked by BEFORE ROW triggers.
This ensures that the row count in the command tag for a MERGE is correctly computed in the case where UPDATEs or DELETEs are skipped due to a BEFORE ROW trigger returning NULL (the INSERT case was already handled correctly by ExecMergeNotMatched() calling ExecInsert()). Back-patch to v15, where MERGE was introduced. Discussion: https://postgr.es/m/CAEZATCU8XEmR0JWKDtyb7iZ%3DqCffxS9uyJt0iOZ4TV4RT%2Bow1w%40mail.gmail.com
1 parent 9321c79 commit 7b14e20

File tree

3 files changed

+34
-4
lines changed

3 files changed

+34
-4
lines changed

src/backend/executor/nodeModifyTable.c

+6-4
Original file line numberDiff line numberDiff line change
@@ -2883,8 +2883,9 @@ ExecMergeMatched(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
28832883
if (!ExecUpdatePrologue(context, resultRelInfo,
28842884
tupleid, NULL, newslot, &result))
28852885
{
2886-
/* Blocked by trigger, or concurrent update/delete */
2887-
break;
2886+
if (result == TM_Ok)
2887+
return true; /* "do nothing" */
2888+
break; /* concurrent update/delete */
28882889
}
28892890
result = ExecUpdateAct(context, resultRelInfo, tupleid, NULL,
28902891
newslot, false, &updateCxt);
@@ -2901,8 +2902,9 @@ ExecMergeMatched(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
29012902
if (!ExecDeletePrologue(context, resultRelInfo, tupleid,
29022903
NULL, NULL, &result))
29032904
{
2904-
/* Blocked by trigger, or concurrent update/delete */
2905-
break;
2905+
if (result == TM_Ok)
2906+
return true; /* "do nothing" */
2907+
break; /* concurrent update/delete */
29062908
}
29072909
result = ExecDeleteAct(context, resultRelInfo, tupleid, false);
29082910
if (result == TM_Ok)

src/test/regress/expected/merge.out

+15
Original file line numberDiff line numberDiff line change
@@ -942,12 +942,25 @@ SELECT * FROM target full outer join source on (sid = tid);
942942

943943
create trigger merge_skip BEFORE INSERT OR UPDATE or DELETE
944944
ON target FOR EACH ROW EXECUTE FUNCTION skip_merge_op();
945+
DO $$
946+
DECLARE
947+
result integer;
948+
BEGIN
945949
MERGE INTO target t
946950
USING source AS s
947951
ON t.tid = s.sid
948952
WHEN MATCHED AND s.sid = 3 THEN UPDATE SET balance = t.balance + s.delta
949953
WHEN MATCHED THEN DELETE
950954
WHEN NOT MATCHED THEN INSERT VALUES (sid, delta);
955+
IF FOUND THEN
956+
RAISE NOTICE 'Found';
957+
ELSE
958+
RAISE NOTICE 'Not found';
959+
END IF;
960+
GET DIAGNOSTICS result := ROW_COUNT;
961+
RAISE NOTICE 'ROW_COUNT = %', result;
962+
END;
963+
$$;
951964
NOTICE: BEFORE INSERT STATEMENT trigger
952965
NOTICE: BEFORE UPDATE STATEMENT trigger
953966
NOTICE: BEFORE DELETE STATEMENT trigger
@@ -957,6 +970,8 @@ NOTICE: BEFORE INSERT ROW trigger row: (4,40)
957970
NOTICE: AFTER DELETE STATEMENT trigger
958971
NOTICE: AFTER UPDATE STATEMENT trigger
959972
NOTICE: AFTER INSERT STATEMENT trigger
973+
NOTICE: Not found
974+
NOTICE: ROW_COUNT = 0
960975
SELECT * FROM target FULL OUTER JOIN source ON (sid = tid);
961976
tid | balance | sid | delta
962977
-----+---------+-----+-------

src/test/regress/sql/merge.sql

+13
Original file line numberDiff line numberDiff line change
@@ -636,12 +636,25 @@ $$;
636636
SELECT * FROM target full outer join source on (sid = tid);
637637
create trigger merge_skip BEFORE INSERT OR UPDATE or DELETE
638638
ON target FOR EACH ROW EXECUTE FUNCTION skip_merge_op();
639+
DO $$
640+
DECLARE
641+
result integer;
642+
BEGIN
639643
MERGE INTO target t
640644
USING source AS s
641645
ON t.tid = s.sid
642646
WHEN MATCHED AND s.sid = 3 THEN UPDATE SET balance = t.balance + s.delta
643647
WHEN MATCHED THEN DELETE
644648
WHEN NOT MATCHED THEN INSERT VALUES (sid, delta);
649+
IF FOUND THEN
650+
RAISE NOTICE 'Found';
651+
ELSE
652+
RAISE NOTICE 'Not found';
653+
END IF;
654+
GET DIAGNOSTICS result := ROW_COUNT;
655+
RAISE NOTICE 'ROW_COUNT = %', result;
656+
END;
657+
$$;
645658
SELECT * FROM target FULL OUTER JOIN source ON (sid = tid);
646659
DROP TRIGGER merge_skip ON target;
647660
DROP FUNCTION skip_merge_op();

0 commit comments

Comments
 (0)