I can't reproduce the described behaviour on PostgreSQL 9.2:
CREATE TABLE prep_test AS SELECT generate_series(1,10) AS x;
BEGIN;
UPDATE prep_test SET x = x*10;
PREPARE TRANSACTION 'test';
then in a second session:
UPDATE prep_test SET x = x*20;
blocks, as expected, until I either COMMIT PREPARED 'test'
or ROLLBACK PREPARED 'test'
I also got the expected results when testing serializable isolation:
A# BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
B# BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
A# INSERT INTO prep_test(x) VALUES (42);
B# INSERT INTO prep_test(x) VALUES (43);
A# SELECT count(x) FROM prep_test;
B# SELECT count(x) FROM prep_test;
A# PREPARE TRANSACTION 'test';
B# COMMIT;
B
fails with a serializability error, exactly as expected. The same happens if B tries to PREPARE TRANSACTION
too.
After question updated with test case:
Your test case looks fine to me, ie it should behave exactly as described and execute without error.
PREPARE TRANSACTION
isn't a commit. You can still ROLLBACK PREPARED
. So PostgreSQL can't show you the changed rows until you do the final COMMIT PREPARED
, otherwise you'd get a dirty read anomaly if you read the rows then did a ROLLBACK PREPARED
.
You'd get the same result from your test caes if you didn't PREPARE TRANSACTION
in the first session before you ran the second command. It has nothing to do with prepared transactions. You're just not seeing rows changed by an uncommitted transaction, which is perfectly normal.
If both transactions are SERIALIZABLE
then it's still fine. Serializability requires that there be a valid ordering in which the concurrent transactions could have occurred serially to produce the same results. Here, that's obvious: The SELECT
came first, then the UPDATE
. The transactions are still occurring concurrently with each other when the SELECT
occurs because a transaction prepared with PREPARE TRANSACTION
is still open until it's committed or rolled back.