BUG #17301: SELECT gets weird result while two transactions are submitted concurrently

Started by PG Bug reporting formover 4 years ago2 messagesbugs
Jump to latest
#1PG Bug reporting form
noreply@postgresql.org

The following bug has been logged on the website:

Bug reference: 17301
Logged by: Dinary Dai
Email address: dddinary@163.com
PostgreSQL version: 14.0
Operating system: Ubuntu
Description:

/* init */ create table t(a int primary key, b int);
/* init */ insert into t values (1, 2), (2, 3)

/* t1 */ begin;
/* t1 */ set transaction isolation level repeatable read;
/* t1 */ select * from t where a = 1;
/* t2 */ begin;
/* t2 */ set transaction isolation level repeatable read;
/* t2 */ delete from t where a = 2;
/* t2 */ commit;
/* t1 */ update t set a = 2 where a = 1;
/* t1 */ select * from t where a = 2; -- [(2, 3), (2, 2)]
/* t1 */ commit;

The final SELECT statement gets result [(2, 3), (2, 2)], which violates the
primary key constraint on column `a`.

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: PG Bug reporting form (#1)
Re: BUG #17301: SELECT gets weird result while two transactions are submitted concurrently

PG Bug reporting form <noreply@postgresql.org> writes:

/* init */ create table t(a int primary key, b int);
/* init */ insert into t values (1, 2), (2, 3)

/* t1 */ begin;
/* t1 */ set transaction isolation level repeatable read;
/* t1 */ select * from t where a = 1;
/* t2 */ begin;
/* t2 */ set transaction isolation level repeatable read;
/* t2 */ delete from t where a = 2;
/* t2 */ commit;
/* t1 */ update t set a = 2 where a = 1;
/* t1 */ select * from t where a = 2; -- [(2, 3), (2, 2)]
/* t1 */ commit;

The final SELECT statement gets result [(2, 3), (2, 2)], which violates the
primary key constraint on column `a`.

This is operating as designed. There are only three plausible behaviors
in this situation:

1. Fail t1's last SELECT (or, perhaps, its UPDATE). You'll get that
if you use SERIALIZABLE mode.

2. In t1's last SELECT, don't show the committed-dead (2,3) row.
This violates the premise of REPEATABLE READ: t1 could see that
row at the start of its run, and it hasn't modified it, so it
should still see it.

3. In t1's last SELECT, show both rows.

We choose #3. If you want #2, you should be using READ COMMITTED
mode, while if you want #1, you should be using SERIALIZABLE.

regards, tom lane