2 -- PREPARED TRANSACTIONS (two-phase commit)
4 -- We can't readily test persistence of prepared xacts within the
5 -- regression script framework, unfortunately. Note that a crash
6 -- isn't really needed ... stopping and starting the postmaster would
7 -- be enough, but we can't even do that here.
8 -- create a simple table that we'll use in the tests
9 CREATE TABLE pxtest1 (foobar VARCHAR(10));
10 INSERT INTO pxtest1 VALUES ('aaa');
11 -- Test PREPARE TRANSACTION
12 BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
13 UPDATE pxtest1 SET foobar = 'bbb' WHERE foobar = 'aaa';
14 SELECT * FROM pxtest1;
20 PREPARE TRANSACTION 'regress_foo1';
21 SELECT * FROM pxtest1;
27 -- Test pg_prepared_xacts system view
28 SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid;
34 -- Test ROLLBACK PREPARED
35 ROLLBACK PREPARED 'regress_foo1';
36 SELECT * FROM pxtest1;
42 SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid;
47 -- Test COMMIT PREPARED
48 BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
49 INSERT INTO pxtest1 VALUES ('ddd');
50 SELECT * FROM pxtest1;
57 PREPARE TRANSACTION 'regress_foo2';
58 SELECT * FROM pxtest1;
64 COMMIT PREPARED 'regress_foo2';
65 SELECT * FROM pxtest1;
72 -- Test duplicate gids
73 BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
74 UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd';
75 SELECT * FROM pxtest1;
82 PREPARE TRANSACTION 'regress_foo3';
83 SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid;
89 BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
90 INSERT INTO pxtest1 VALUES ('fff');
91 -- This should fail, because the gid foo3 is already in use
92 PREPARE TRANSACTION 'regress_foo3';
93 ERROR: transaction identifier "regress_foo3" is already in use
94 SELECT * FROM pxtest1;
101 ROLLBACK PREPARED 'regress_foo3';
102 SELECT * FROM pxtest1;
109 -- Test serialization failure (SSI)
110 BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
111 UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd';
112 SELECT * FROM pxtest1;
119 PREPARE TRANSACTION 'regress_foo4';
120 SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid;
126 BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
127 SELECT * FROM pxtest1;
134 -- This should fail, because the two transactions have a write-skew anomaly
135 INSERT INTO pxtest1 VALUES ('fff');
136 ERROR: could not serialize access due to read/write dependencies among transactions
137 DETAIL: Reason code: Canceled on identification as a pivot, during write.
138 HINT: The transaction might succeed if retried.
139 PREPARE TRANSACTION 'regress_foo5';
140 SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid;
146 ROLLBACK PREPARED 'regress_foo4';
147 SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid;
154 -- Test detection of session-level and xact-level locks on same object
156 SELECT pg_advisory_lock(1);
162 SELECT pg_advisory_xact_lock_shared(1);
163 pg_advisory_xact_lock_shared
164 ------------------------------
168 PREPARE TRANSACTION 'regress_foo6'; -- fails
169 ERROR: cannot PREPARE while holding both session-level and transaction-level locks on the same object
170 -- Test subtransactions
171 BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
172 CREATE TABLE pxtest2 (a int);
173 INSERT INTO pxtest2 VALUES (1);
175 INSERT INTO pxtest2 VALUES (2);
178 INSERT INTO pxtest2 VALUES (3);
179 PREPARE TRANSACTION 'regress_sub1';
180 CREATE TABLE pxtest3(fff int);
181 -- Test shared invalidation
182 BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
184 CREATE TABLE pxtest4 (a int);
185 INSERT INTO pxtest4 VALUES (1);
186 INSERT INTO pxtest4 VALUES (2);
187 DECLARE foo CURSOR FOR SELECT * FROM pxtest4;
188 -- Fetch 1 tuple, keeping the cursor open
195 PREPARE TRANSACTION 'regress_sub2';
198 ERROR: cursor "foo" does not exist
199 -- Table doesn't exist, the creation hasn't been committed yet
200 SELECT * FROM pxtest2;
201 ERROR: relation "pxtest2" does not exist
202 LINE 1: SELECT * FROM pxtest2;
204 -- There should be two prepared transactions
205 SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid;
212 -- pxtest3 should be locked because of the pending DROP
214 lock table pxtest3 in access share mode nowait;
215 ERROR: could not obtain lock on relation "pxtest3"
217 -- Disconnect, we will continue testing in a different backend
219 -- There should still be two prepared transactions
220 SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid;
227 -- pxtest3 should still be locked because of the pending DROP
229 lock table pxtest3 in access share mode nowait;
230 ERROR: could not obtain lock on relation "pxtest3"
232 -- Commit table creation
233 COMMIT PREPARED 'regress_sub1';
235 Table "public.pxtest2"
236 Column | Type | Collation | Nullable | Default
237 --------+---------+-----------+----------+---------
240 SELECT * FROM pxtest2;
247 -- There should be one prepared transaction
248 SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid;
255 COMMIT PREPARED 'regress_sub2';
256 SELECT * FROM pxtest3;
257 ERROR: relation "pxtest3" does not exist
258 LINE 1: SELECT * FROM pxtest3;
260 -- There should be no prepared transactions
261 SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid;
268 DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled
269 ERROR: table "pxtest3" does not exist