-- -- PREPARED TRANSACTIONS (two-phase commit) -- -- We can't readily test persistence of prepared xacts within the -- regression script framework, unfortunately. Note that a crash -- isn't really needed ... stopping and starting the postmaster would -- be enough, but we can't even do that here. -- create a simple table that we'll use in the tests CREATE TABLE pxtest1 (foobar VARCHAR(10)); INSERT INTO pxtest1 VALUES ('aaa'); -- Test PREPARE TRANSACTION BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; UPDATE pxtest1 SET foobar = 'bbb' WHERE foobar = 'aaa'; SELECT * FROM pxtest1; foobar -------- bbb (1 row) PREPARE TRANSACTION 'regress_foo1'; ERROR: prepared transactions are disabled HINT: Set max_prepared_transactions to a nonzero value. SELECT * FROM pxtest1; foobar -------- aaa (1 row) -- Test pg_prepared_xacts system view SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; gid ----- (0 rows) -- Test ROLLBACK PREPARED ROLLBACK PREPARED 'regress_foo1'; ERROR: prepared transaction with identifier "regress_foo1" does not exist SELECT * FROM pxtest1; foobar -------- aaa (1 row) SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; gid ----- (0 rows) -- Test COMMIT PREPARED BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; INSERT INTO pxtest1 VALUES ('ddd'); SELECT * FROM pxtest1; foobar -------- aaa ddd (2 rows) PREPARE TRANSACTION 'regress_foo2'; ERROR: prepared transactions are disabled HINT: Set max_prepared_transactions to a nonzero value. SELECT * FROM pxtest1; foobar -------- aaa (1 row) COMMIT PREPARED 'regress_foo2'; ERROR: prepared transaction with identifier "regress_foo2" does not exist SELECT * FROM pxtest1; foobar -------- aaa (1 row) -- Test duplicate gids BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd'; SELECT * FROM pxtest1; foobar -------- aaa (1 row) PREPARE TRANSACTION 'regress_foo3'; ERROR: prepared transactions are disabled HINT: Set max_prepared_transactions to a nonzero value. SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; gid ----- (0 rows) BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; INSERT INTO pxtest1 VALUES ('fff'); -- This should fail, because the gid foo3 is already in use PREPARE TRANSACTION 'regress_foo3'; ERROR: prepared transactions are disabled HINT: Set max_prepared_transactions to a nonzero value. SELECT * FROM pxtest1; foobar -------- aaa (1 row) ROLLBACK PREPARED 'regress_foo3'; ERROR: prepared transaction with identifier "regress_foo3" does not exist SELECT * FROM pxtest1; foobar -------- aaa (1 row) -- Test serialization failure (SSI) BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd'; SELECT * FROM pxtest1; foobar -------- aaa (1 row) PREPARE TRANSACTION 'regress_foo4'; ERROR: prepared transactions are disabled HINT: Set max_prepared_transactions to a nonzero value. SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; gid ----- (0 rows) BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; SELECT * FROM pxtest1; foobar -------- aaa (1 row) -- This should fail, because the two transactions have a write-skew anomaly INSERT INTO pxtest1 VALUES ('fff'); PREPARE TRANSACTION 'regress_foo5'; ERROR: prepared transactions are disabled HINT: Set max_prepared_transactions to a nonzero value. SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; gid ----- (0 rows) ROLLBACK PREPARED 'regress_foo4'; ERROR: prepared transaction with identifier "regress_foo4" does not exist SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; gid ----- (0 rows) -- Clean up DROP TABLE pxtest1; -- Test detection of session-level and xact-level locks on same object BEGIN; SELECT pg_advisory_lock(1); pg_advisory_lock ------------------ (1 row) SELECT pg_advisory_xact_lock_shared(1); pg_advisory_xact_lock_shared ------------------------------ (1 row) PREPARE TRANSACTION 'regress_foo6'; -- fails ERROR: prepared transactions are disabled HINT: Set max_prepared_transactions to a nonzero value. -- Test subtransactions BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; CREATE TABLE pxtest2 (a int); INSERT INTO pxtest2 VALUES (1); SAVEPOINT a; INSERT INTO pxtest2 VALUES (2); ROLLBACK TO a; SAVEPOINT b; INSERT INTO pxtest2 VALUES (3); PREPARE TRANSACTION 'regress_sub1'; ERROR: prepared transactions are disabled HINT: Set max_prepared_transactions to a nonzero value. CREATE TABLE pxtest3(fff int); -- Test shared invalidation BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; DROP TABLE pxtest3; CREATE TABLE pxtest4 (a int); INSERT INTO pxtest4 VALUES (1); INSERT INTO pxtest4 VALUES (2); DECLARE foo CURSOR FOR SELECT * FROM pxtest4; -- Fetch 1 tuple, keeping the cursor open FETCH 1 FROM foo; a --- 1 (1 row) PREPARE TRANSACTION 'regress_sub2'; ERROR: prepared transactions are disabled HINT: Set max_prepared_transactions to a nonzero value. -- No such cursor FETCH 1 FROM foo; ERROR: cursor "foo" does not exist -- Table doesn't exist, the creation hasn't been committed yet SELECT * FROM pxtest2; ERROR: relation "pxtest2" does not exist LINE 1: SELECT * FROM pxtest2; ^ -- There should be two prepared transactions SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; gid ----- (0 rows) -- pxtest3 should be locked because of the pending DROP begin; lock table pxtest3 in access share mode nowait; rollback; -- Disconnect, we will continue testing in a different backend \c - -- There should still be two prepared transactions SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; gid ----- (0 rows) -- pxtest3 should still be locked because of the pending DROP begin; lock table pxtest3 in access share mode nowait; rollback; -- Commit table creation COMMIT PREPARED 'regress_sub1'; ERROR: prepared transaction with identifier "regress_sub1" does not exist \d pxtest2 SELECT * FROM pxtest2; ERROR: relation "pxtest2" does not exist LINE 1: SELECT * FROM pxtest2; ^ -- There should be one prepared transaction SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; gid ----- (0 rows) -- Commit table drop COMMIT PREPARED 'regress_sub2'; ERROR: prepared transaction with identifier "regress_sub2" does not exist SELECT * FROM pxtest3; fff ----- (0 rows) -- There should be no prepared transactions SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; gid ----- (0 rows) -- Clean up DROP TABLE pxtest2; ERROR: table "pxtest2" does not exist DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled DROP TABLE pxtest4; ERROR: table "pxtest4" does not exist