mirror of https://github.com/postgres/postgres
A transaction that conflicts against itself, for example INSERT INTO t(pk) VALUES (1),(1) ON CONFLICT DO NOTHING; should behave the same regardless of isolation level. It certainly shouldn't throw a serialization error, as retrying will not help. We got this wrong due to the ON CONFLICT logic not considering the case, as reported by Jason Dusek. Core of this patch is by Peter Geoghegan (based on an earlier patch by Thomas Munro), though I didn't take his proposed code refactoring for fear that it might have unexpected side-effects. Test cases by Thomas Munro and myself. Report: <CAO3NbwOycQjt2Oqy2VW-eLTq2M5uGMyHnGm=RNga4mjqcYD7gQ@mail.gmail.com> Related-Discussion: <57EE93C8.8080504@postgrespro.ru>pull/17/head
parent
6292c23391
commit
a6c0a5b6e8
@ -0,0 +1,105 @@ |
||||
Parsed test spec with 2 sessions |
||||
|
||||
starting permutation: beginrr1 beginrr2 donothing1 c1 donothing2 c2 show |
||||
step beginrr1: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step beginrr2: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; |
||||
step c1: COMMIT; |
||||
step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; |
||||
step c2: COMMIT; |
||||
step show: SELECT * FROM ints; |
||||
key val |
||||
|
||||
1 donothing1 |
||||
|
||||
starting permutation: beginrr1 beginrr2 donothing2 c2 donothing1 c1 show |
||||
step beginrr1: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step beginrr2: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; |
||||
step c2: COMMIT; |
||||
step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; |
||||
step c1: COMMIT; |
||||
step show: SELECT * FROM ints; |
||||
key val |
||||
|
||||
1 donothing2 |
||||
|
||||
starting permutation: beginrr1 beginrr2 donothing1 donothing2 c1 c2 show |
||||
step beginrr1: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step beginrr2: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; |
||||
step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; <waiting ...> |
||||
step c1: COMMIT; |
||||
step donothing2: <... completed> |
||||
error in steps c1 donothing2: ERROR: could not serialize access due to concurrent update |
||||
step c2: COMMIT; |
||||
step show: SELECT * FROM ints; |
||||
key val |
||||
|
||||
1 donothing1 |
||||
|
||||
starting permutation: beginrr1 beginrr2 donothing2 donothing1 c2 c1 show |
||||
step beginrr1: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step beginrr2: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; |
||||
step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; <waiting ...> |
||||
step c2: COMMIT; |
||||
step donothing1: <... completed> |
||||
error in steps c2 donothing1: ERROR: could not serialize access due to concurrent update |
||||
step c1: COMMIT; |
||||
step show: SELECT * FROM ints; |
||||
key val |
||||
|
||||
1 donothing2 |
||||
|
||||
starting permutation: begins1 begins2 donothing1 c1 donothing2 c2 show |
||||
step begins1: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||
step begins2: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||
step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; |
||||
step c1: COMMIT; |
||||
step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; |
||||
step c2: COMMIT; |
||||
step show: SELECT * FROM ints; |
||||
key val |
||||
|
||||
1 donothing1 |
||||
|
||||
starting permutation: begins1 begins2 donothing2 c2 donothing1 c1 show |
||||
step begins1: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||
step begins2: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||
step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; |
||||
step c2: COMMIT; |
||||
step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; |
||||
step c1: COMMIT; |
||||
step show: SELECT * FROM ints; |
||||
key val |
||||
|
||||
1 donothing2 |
||||
|
||||
starting permutation: begins1 begins2 donothing1 donothing2 c1 c2 show |
||||
step begins1: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||
step begins2: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||
step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; |
||||
step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; <waiting ...> |
||||
step c1: COMMIT; |
||||
step donothing2: <... completed> |
||||
error in steps c1 donothing2: ERROR: could not serialize access due to concurrent update |
||||
step c2: COMMIT; |
||||
step show: SELECT * FROM ints; |
||||
key val |
||||
|
||||
1 donothing1 |
||||
|
||||
starting permutation: begins1 begins2 donothing2 donothing1 c2 c1 show |
||||
step begins1: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||
step begins2: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||
step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; |
||||
step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; <waiting ...> |
||||
step c2: COMMIT; |
||||
step donothing1: <... completed> |
||||
error in steps c2 donothing1: ERROR: could not serialize access due to concurrent update |
||||
step c1: COMMIT; |
||||
step show: SELECT * FROM ints; |
||||
key val |
||||
|
||||
1 donothing2 |
||||
@ -0,0 +1,34 @@ |
||||
# INSERT...ON CONFLICT DO NOTHING test with multiple rows |
||||
# in higher isolation levels |
||||
|
||||
setup |
||||
{ |
||||
CREATE TABLE ints (key int primary key, val text); |
||||
} |
||||
|
||||
teardown |
||||
{ |
||||
DROP TABLE ints; |
||||
} |
||||
|
||||
session "s1" |
||||
step "beginrr1" { BEGIN ISOLATION LEVEL REPEATABLE READ; } |
||||
step "begins1" { BEGIN ISOLATION LEVEL SERIALIZABLE; } |
||||
step "donothing1" { INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; } |
||||
step "c1" { COMMIT; } |
||||
step "show" { SELECT * FROM ints; } |
||||
|
||||
session "s2" |
||||
step "beginrr2" { BEGIN ISOLATION LEVEL REPEATABLE READ; } |
||||
step "begins2" { BEGIN ISOLATION LEVEL SERIALIZABLE; } |
||||
step "donothing2" { INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; } |
||||
step "c2" { COMMIT; } |
||||
|
||||
permutation "beginrr1" "beginrr2" "donothing1" "c1" "donothing2" "c2" "show" |
||||
permutation "beginrr1" "beginrr2" "donothing2" "c2" "donothing1" "c1" "show" |
||||
permutation "beginrr1" "beginrr2" "donothing1" "donothing2" "c1" "c2" "show" |
||||
permutation "beginrr1" "beginrr2" "donothing2" "donothing1" "c2" "c1" "show" |
||||
permutation "begins1" "begins2" "donothing1" "c1" "donothing2" "c2" "show" |
||||
permutation "begins1" "begins2" "donothing2" "c2" "donothing1" "c1" "show" |
||||
permutation "begins1" "begins2" "donothing1" "donothing2" "c1" "c2" "show" |
||||
permutation "begins1" "begins2" "donothing2" "donothing1" "c2" "c1" "show" |
||||
Loading…
Reference in new issue