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
This commit is contained in:
parent
9321c79c86
commit
7b14e20b12
@ -2883,8 +2883,9 @@ lmerge_matched:
|
||||
if (!ExecUpdatePrologue(context, resultRelInfo,
|
||||
tupleid, NULL, newslot, &result))
|
||||
{
|
||||
/* Blocked by trigger, or concurrent update/delete */
|
||||
break;
|
||||
if (result == TM_Ok)
|
||||
return true; /* "do nothing" */
|
||||
break; /* concurrent update/delete */
|
||||
}
|
||||
result = ExecUpdateAct(context, resultRelInfo, tupleid, NULL,
|
||||
newslot, false, &updateCxt);
|
||||
@ -2901,8 +2902,9 @@ lmerge_matched:
|
||||
if (!ExecDeletePrologue(context, resultRelInfo, tupleid,
|
||||
NULL, NULL, &result))
|
||||
{
|
||||
/* Blocked by trigger, or concurrent update/delete */
|
||||
break;
|
||||
if (result == TM_Ok)
|
||||
return true; /* "do nothing" */
|
||||
break; /* concurrent update/delete */
|
||||
}
|
||||
result = ExecDeleteAct(context, resultRelInfo, tupleid, false);
|
||||
if (result == TM_Ok)
|
||||
|
@ -942,12 +942,25 @@ SELECT * FROM target full outer join source on (sid = tid);
|
||||
|
||||
create trigger merge_skip BEFORE INSERT OR UPDATE or DELETE
|
||||
ON target FOR EACH ROW EXECUTE FUNCTION skip_merge_op();
|
||||
DO $$
|
||||
DECLARE
|
||||
result integer;
|
||||
BEGIN
|
||||
MERGE INTO target t
|
||||
USING source AS s
|
||||
ON t.tid = s.sid
|
||||
WHEN MATCHED AND s.sid = 3 THEN UPDATE SET balance = t.balance + s.delta
|
||||
WHEN MATCHED THEN DELETE
|
||||
WHEN NOT MATCHED THEN INSERT VALUES (sid, delta);
|
||||
IF FOUND THEN
|
||||
RAISE NOTICE 'Found';
|
||||
ELSE
|
||||
RAISE NOTICE 'Not found';
|
||||
END IF;
|
||||
GET DIAGNOSTICS result := ROW_COUNT;
|
||||
RAISE NOTICE 'ROW_COUNT = %', result;
|
||||
END;
|
||||
$$;
|
||||
NOTICE: BEFORE INSERT STATEMENT trigger
|
||||
NOTICE: BEFORE UPDATE STATEMENT trigger
|
||||
NOTICE: BEFORE DELETE STATEMENT trigger
|
||||
@ -957,6 +970,8 @@ NOTICE: BEFORE INSERT ROW trigger row: (4,40)
|
||||
NOTICE: AFTER DELETE STATEMENT trigger
|
||||
NOTICE: AFTER UPDATE STATEMENT trigger
|
||||
NOTICE: AFTER INSERT STATEMENT trigger
|
||||
NOTICE: Not found
|
||||
NOTICE: ROW_COUNT = 0
|
||||
SELECT * FROM target FULL OUTER JOIN source ON (sid = tid);
|
||||
tid | balance | sid | delta
|
||||
-----+---------+-----+-------
|
||||
|
@ -636,12 +636,25 @@ $$;
|
||||
SELECT * FROM target full outer join source on (sid = tid);
|
||||
create trigger merge_skip BEFORE INSERT OR UPDATE or DELETE
|
||||
ON target FOR EACH ROW EXECUTE FUNCTION skip_merge_op();
|
||||
DO $$
|
||||
DECLARE
|
||||
result integer;
|
||||
BEGIN
|
||||
MERGE INTO target t
|
||||
USING source AS s
|
||||
ON t.tid = s.sid
|
||||
WHEN MATCHED AND s.sid = 3 THEN UPDATE SET balance = t.balance + s.delta
|
||||
WHEN MATCHED THEN DELETE
|
||||
WHEN NOT MATCHED THEN INSERT VALUES (sid, delta);
|
||||
IF FOUND THEN
|
||||
RAISE NOTICE 'Found';
|
||||
ELSE
|
||||
RAISE NOTICE 'Not found';
|
||||
END IF;
|
||||
GET DIAGNOSTICS result := ROW_COUNT;
|
||||
RAISE NOTICE 'ROW_COUNT = %', result;
|
||||
END;
|
||||
$$;
|
||||
SELECT * FROM target FULL OUTER JOIN source ON (sid = tid);
|
||||
DROP TRIGGER merge_skip ON target;
|
||||
DROP FUNCTION skip_merge_op();
|
||||
|
Loading…
x
Reference in New Issue
Block a user