mirror of
https://github.com/postgres/postgres.git
synced 2026-06-09 08:42:38 -04:00
Fix handling of updated tuples in the MERGE statement
This branch missed the IsolationUsesXactSnapshot() check. That led to EPQ on repeatable read and serializable isolation levels. This commit fixes the issue and provides a simple isolation check for that. Backpatch through v15 where MERGE statement was introduced. Reported-by: Tender Wang <tndrwang@gmail.com> Discussion: https://postgr.es/m/CAPpHfdvzZSaNYdj5ac-tYRi6MuuZnYHiUkZ3D-AoY-ny8v%2BS%2Bw%40mail.gmail.com Author: Tender Wang <tndrwang@gmail.com> Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com> Backpatch-through: 15
This commit is contained in:
parent
bffd7130e9
commit
177037341a
3 changed files with 40 additions and 0 deletions
|
|
@ -3547,6 +3547,11 @@ lmerge_matched:
|
|||
*inputslot;
|
||||
LockTupleMode lockmode;
|
||||
|
||||
if (IsolationUsesXactSnapshot())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
|
||||
errmsg("could not serialize access due to concurrent update")));
|
||||
|
||||
/*
|
||||
* The target tuple was concurrently updated by some other
|
||||
* transaction. If we are currently processing a MATCHED
|
||||
|
|
|
|||
|
|
@ -549,3 +549,36 @@ step c1: COMMIT;
|
|||
step pa_merge2c_dup: <... completed>
|
||||
ERROR: MERGE command cannot affect row a second time
|
||||
step a2: ABORT;
|
||||
|
||||
starting permutation: merge2a c1 s1beginrr merge1 c2
|
||||
step merge2a:
|
||||
MERGE INTO target t
|
||||
USING (SELECT 1 as key, 'merge2a' as val) s
|
||||
ON s.key = t.key
|
||||
WHEN NOT MATCHED THEN
|
||||
INSERT VALUES (s.key, s.val)
|
||||
WHEN MATCHED THEN
|
||||
UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val
|
||||
WHEN NOT MATCHED BY SOURCE THEN
|
||||
UPDATE set key = t.key + 1, val = t.val || ' source not matched by merge2a'
|
||||
RETURNING merge_action(), old, new, t.*;
|
||||
|
||||
merge_action|old |new |key|val
|
||||
------------+----------+-------------------------------+---+-------------------------
|
||||
UPDATE |(1,setup1)|(2,"setup1 updated by merge2a")| 2|setup1 updated by merge2a
|
||||
(1 row)
|
||||
|
||||
step c1: COMMIT;
|
||||
step s1beginrr: BEGIN ISOLATION LEVEL REPEATABLE READ;
|
||||
step merge1:
|
||||
MERGE INTO target t
|
||||
USING (SELECT 1 as key, 'merge1' as val) s
|
||||
ON s.key = t.key
|
||||
WHEN NOT MATCHED THEN
|
||||
INSERT VALUES (s.key, s.val)
|
||||
WHEN MATCHED THEN
|
||||
UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val;
|
||||
<waiting ...>
|
||||
step c2: COMMIT;
|
||||
step merge1: <... completed>
|
||||
ERROR: could not serialize access due to concurrent update
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ step "pa_merge3"
|
|||
}
|
||||
step "c1" { COMMIT; }
|
||||
step "a1" { ABORT; }
|
||||
step "s1beginrr" { BEGIN ISOLATION LEVEL REPEATABLE READ; }
|
||||
|
||||
session "s2"
|
||||
setup
|
||||
|
|
@ -223,3 +224,4 @@ permutation "pa_merge2" "c1" "pa_merge2a" "pa_select2" "c2" # succeeds
|
|||
permutation "pa_merge3" "pa_merge2b_when" "c1" "pa_select2" "c2" # WHEN not satisfied by updated tuple
|
||||
permutation "pa_merge1" "pa_merge2b_when" "c1" "pa_select2" "c2" # WHEN satisfied by updated tuple
|
||||
permutation "pa_merge1" "pa_merge2c_dup" "c1" "a2"
|
||||
permutation "merge2a" "c1" "s1beginrr" "merge1" "c2"
|
||||
|
|
|
|||
Loading…
Reference in a new issue