--
-- 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;
UPDATE pxtest1 SET foobar = 'bbb' WHERE foobar = 'aaa';
SELECT * FROM pxtest1;
 foobar 
--------
 bbb
(1 row)

PREPARE TRANSACTION '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;
 gid 
-----
(0 rows)

-- Test ROLLBACK PREPARED
ROLLBACK PREPARED 'foo1';
ERROR:  prepared transaction with identifier "foo1" does not exist
SELECT * FROM pxtest1;
 foobar 
--------
 aaa
(1 row)

SELECT gid FROM pg_prepared_xacts;
 gid 
-----
(0 rows)

-- Test COMMIT PREPARED
BEGIN;
INSERT INTO pxtest1 VALUES ('ddd');
SELECT * FROM pxtest1;
 foobar 
--------
 aaa
 ddd
(2 rows)

PREPARE TRANSACTION 'foo2';
ERROR:  prepared transactions are disabled
HINT:  Set max_prepared_transactions to a nonzero value.
SELECT * FROM pxtest1;
 foobar 
--------
 aaa
(1 row)

COMMIT PREPARED 'foo2';
ERROR:  prepared transaction with identifier "foo2" does not exist
SELECT * FROM pxtest1;
 foobar 
--------
 aaa
(1 row)

-- Test duplicate gids
BEGIN;
UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd';
SELECT * FROM pxtest1;
 foobar 
--------
 aaa
(1 row)

PREPARE TRANSACTION 'foo3';
ERROR:  prepared transactions are disabled
HINT:  Set max_prepared_transactions to a nonzero value.
SELECT gid FROM pg_prepared_xacts;
 gid 
-----
(0 rows)

BEGIN;
INSERT INTO pxtest1 VALUES ('fff');
SELECT * FROM pxtest1;
 foobar 
--------
 aaa
 fff
(2 rows)

-- This should fail, because the gid foo3 is already in use
PREPARE TRANSACTION 'foo3';
ERROR:  prepared transactions are disabled
HINT:  Set max_prepared_transactions to a nonzero value.
SELECT * FROM pxtest1;
 foobar 
--------
 aaa
(1 row)

ROLLBACK PREPARED 'foo3';
ERROR:  prepared transaction with identifier "foo3" does not exist
SELECT * FROM pxtest1;
 foobar 
--------
 aaa
(1 row)

-- Clean up
DROP TABLE pxtest1;
-- Test subtransactions
BEGIN;
  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-one';
ERROR:  prepared transactions are disabled
HINT:  Set max_prepared_transactions to a nonzero value.
CREATE TABLE pxtest3(fff int);
-- Test shared invalidation
BEGIN;
  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-two';
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;
 gid 
-----
(0 rows)

-- pxtest3 should be locked because of the pending DROP
set statement_timeout to 2000;
SELECT * FROM pxtest3;
 fff 
-----
(0 rows)

reset statement_timeout;
-- Disconnect, we will continue testing in a different backend
\c -
-- There should still be two prepared transactions
SELECT gid FROM pg_prepared_xacts;
 gid 
-----
(0 rows)

-- pxtest3 should still be locked because of the pending DROP
set statement_timeout to 2000;
SELECT * FROM pxtest3;
 fff 
-----
(0 rows)

reset statement_timeout;
-- Commit table creation
COMMIT PREPARED 'regress-one';
ERROR:  prepared transaction with identifier "regress-one" 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;
 gid 
-----
(0 rows)

-- Commit table drop
COMMIT PREPARED 'regress-two';
ERROR:  prepared transaction with identifier "regress-two" does not exist
SELECT * FROM pxtest3;
 fff 
-----
(0 rows)

-- There should be no prepared transactions
SELECT gid FROM pg_prepared_xacts;
 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
