-- -- TRANSACTIONS -- BEGIN; SELECT * INTO TABLE xacttest FROM aggtest; INSERT INTO xacttest (a, b) VALUES (777, 777.777); END; -- should retrieve one value-- SELECT a FROM xacttest WHERE a > 100; a ----- 777 (1 row) BEGIN; CREATE TABLE disappear (a int4); DELETE FROM aggtest; -- should be empty SELECT * FROM aggtest; a | b ---+--- (0 rows) ABORT; -- should not exist SELECT oid FROM pg_class WHERE relname = 'disappear'; oid ----- (0 rows) -- should have members again SELECT * FROM aggtest; a | b -----+--------- 56 | 7.8 100 | 99.097 0 | 0.09561 42 | 324.78 (4 rows) -- Read-only tests CREATE TABLE writetest (a int); CREATE TEMPORARY TABLE temptest (a int); BEGIN; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY, DEFERRABLE; -- ok SELECT * FROM writetest; -- ok a --- (0 rows) SET TRANSACTION READ WRITE; --fail ERROR: transaction read-write mode must be set before any query COMMIT; BEGIN; SET TRANSACTION READ ONLY; -- ok SET TRANSACTION READ WRITE; -- ok SET TRANSACTION READ ONLY; -- ok SELECT * FROM writetest; -- ok a --- (0 rows) SAVEPOINT x; SET TRANSACTION READ ONLY; -- ok SELECT * FROM writetest; -- ok a --- (0 rows) SET TRANSACTION READ ONLY; -- ok SET TRANSACTION READ WRITE; --fail ERROR: cannot set transaction read-write mode inside a read-only transaction COMMIT; BEGIN; SET TRANSACTION READ WRITE; -- ok SAVEPOINT x; SET TRANSACTION READ WRITE; -- ok SET TRANSACTION READ ONLY; -- ok SELECT * FROM writetest; -- ok a --- (0 rows) SET TRANSACTION READ ONLY; -- ok SET TRANSACTION READ WRITE; --fail ERROR: cannot set transaction read-write mode inside a read-only transaction COMMIT; BEGIN; SET TRANSACTION READ WRITE; -- ok SAVEPOINT x; SET TRANSACTION READ ONLY; -- ok SELECT * FROM writetest; -- ok a --- (0 rows) ROLLBACK TO SAVEPOINT x; SHOW transaction_read_only; -- off transaction_read_only ----------------------- off (1 row) SAVEPOINT y; SET TRANSACTION READ ONLY; -- ok SELECT * FROM writetest; -- ok a --- (0 rows) RELEASE SAVEPOINT y; SHOW transaction_read_only; -- off transaction_read_only ----------------------- off (1 row) COMMIT; SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY; DROP TABLE writetest; -- fail ERROR: cannot execute DROP TABLE in a read-only transaction INSERT INTO writetest VALUES (1); -- fail ERROR: cannot execute INSERT in a read-only transaction SELECT * FROM writetest; -- ok a --- (0 rows) DELETE FROM temptest; -- ok UPDATE temptest SET a = 0 FROM writetest WHERE temptest.a = 1 AND writetest.a = temptest.a; -- ok PREPARE test AS UPDATE writetest SET a = 0; -- ok EXECUTE test; -- fail ERROR: cannot execute UPDATE in a read-only transaction SELECT * FROM writetest, temptest; -- ok a | a ---+--- (0 rows) CREATE TABLE test AS SELECT * FROM writetest; -- fail ERROR: cannot execute CREATE TABLE AS in a read-only transaction START TRANSACTION READ WRITE; DROP TABLE writetest; -- ok COMMIT; -- Subtransactions, basic tests -- create & drop tables SET SESSION CHARACTERISTICS AS TRANSACTION READ WRITE; CREATE TABLE trans_foobar (a int); BEGIN; CREATE TABLE trans_foo (a int); SAVEPOINT one; DROP TABLE trans_foo; CREATE TABLE trans_bar (a int); ROLLBACK TO SAVEPOINT one; RELEASE SAVEPOINT one; SAVEPOINT two; CREATE TABLE trans_baz (a int); RELEASE SAVEPOINT two; drop TABLE trans_foobar; CREATE TABLE trans_barbaz (a int); COMMIT; -- should exist: trans_barbaz, trans_baz, trans_foo SELECT * FROM trans_foo; -- should be empty a --- (0 rows) SELECT * FROM trans_bar; -- shouldn't exist ERROR: relation "trans_bar" does not exist LINE 1: SELECT * FROM trans_bar; ^ SELECT * FROM trans_barbaz; -- should be empty a --- (0 rows) SELECT * FROM trans_baz; -- should be empty a --- (0 rows) -- inserts BEGIN; INSERT INTO trans_foo VALUES (1); SAVEPOINT one; INSERT into trans_bar VALUES (1); ERROR: relation "trans_bar" does not exist LINE 1: INSERT into trans_bar VALUES (1); ^ ROLLBACK TO one; RELEASE SAVEPOINT one; SAVEPOINT two; INSERT into trans_barbaz VALUES (1); RELEASE two; SAVEPOINT three; SAVEPOINT four; INSERT INTO trans_foo VALUES (2); RELEASE SAVEPOINT four; ROLLBACK TO SAVEPOINT three; RELEASE SAVEPOINT three; INSERT INTO trans_foo VALUES (3); COMMIT; SELECT * FROM trans_foo; -- should have 1 and 3 a --- 1 3 (2 rows) SELECT * FROM trans_barbaz; -- should have 1 a --- 1 (1 row) -- test whole-tree commit BEGIN; SAVEPOINT one; SELECT trans_foo; ERROR: column "trans_foo" does not exist LINE 1: SELECT trans_foo; ^ ROLLBACK TO SAVEPOINT one; RELEASE SAVEPOINT one; SAVEPOINT two; CREATE TABLE savepoints (a int); SAVEPOINT three; INSERT INTO savepoints VALUES (1); SAVEPOINT four; INSERT INTO savepoints VALUES (2); SAVEPOINT five; INSERT INTO savepoints VALUES (3); ROLLBACK TO SAVEPOINT five; COMMIT; COMMIT; -- should not be in a transaction block WARNING: there is no transaction in progress SELECT * FROM savepoints; a --- 1 2 (2 rows) -- test whole-tree rollback BEGIN; SAVEPOINT one; DELETE FROM savepoints WHERE a=1; RELEASE SAVEPOINT one; SAVEPOINT two; DELETE FROM savepoints WHERE a=1; SAVEPOINT three; DELETE FROM savepoints WHERE a=2; ROLLBACK; COMMIT; -- should not be in a transaction block WARNING: there is no transaction in progress SELECT * FROM savepoints; a --- 1 2 (2 rows) -- test whole-tree commit on an aborted subtransaction BEGIN; INSERT INTO savepoints VALUES (4); SAVEPOINT one; INSERT INTO savepoints VALUES (5); SELECT trans_foo; ERROR: column "trans_foo" does not exist LINE 1: SELECT trans_foo; ^ COMMIT; SELECT * FROM savepoints; a --- 1 2 (2 rows) BEGIN; INSERT INTO savepoints VALUES (6); SAVEPOINT one; INSERT INTO savepoints VALUES (7); RELEASE SAVEPOINT one; INSERT INTO savepoints VALUES (8); COMMIT; -- rows 6 and 8 should have been created by the same xact SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=6 AND b.a=8; ?column? ---------- t (1 row) -- rows 6 and 7 should have been created by different xacts SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=6 AND b.a=7; ?column? ---------- f (1 row) BEGIN; INSERT INTO savepoints VALUES (9); SAVEPOINT one; INSERT INTO savepoints VALUES (10); ROLLBACK TO SAVEPOINT one; INSERT INTO savepoints VALUES (11); COMMIT; SELECT a FROM savepoints WHERE a in (9, 10, 11); a ---- 9 11 (2 rows) -- rows 9 and 11 should have been created by different xacts SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=9 AND b.a=11; ?column? ---------- f (1 row) BEGIN; INSERT INTO savepoints VALUES (12); SAVEPOINT one; INSERT INTO savepoints VALUES (13); SAVEPOINT two; INSERT INTO savepoints VALUES (14); ROLLBACK TO SAVEPOINT one; INSERT INTO savepoints VALUES (15); SAVEPOINT two; INSERT INTO savepoints VALUES (16); SAVEPOINT three; INSERT INTO savepoints VALUES (17); COMMIT; SELECT a FROM savepoints WHERE a BETWEEN 12 AND 17; a ---- 12 15 16 17 (4 rows) BEGIN; INSERT INTO savepoints VALUES (18); SAVEPOINT one; INSERT INTO savepoints VALUES (19); SAVEPOINT two; INSERT INTO savepoints VALUES (20); ROLLBACK TO SAVEPOINT one; INSERT INTO savepoints VALUES (21); ROLLBACK TO SAVEPOINT one; INSERT INTO savepoints VALUES (22); COMMIT; SELECT a FROM savepoints WHERE a BETWEEN 18 AND 22; a ---- 18 22 (2 rows) DROP TABLE savepoints; -- only in a transaction block: SAVEPOINT one; ERROR: SAVEPOINT can only be used in transaction blocks ROLLBACK TO SAVEPOINT one; ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks RELEASE SAVEPOINT one; ERROR: RELEASE SAVEPOINT can only be used in transaction blocks -- Only "rollback to" allowed in aborted state BEGIN; SAVEPOINT one; SELECT 0/0; ERROR: division by zero SAVEPOINT two; -- ignored till the end of ... ERROR: current transaction is aborted, commands ignored until end of transaction block RELEASE SAVEPOINT one; -- ignored till the end of ... ERROR: current transaction is aborted, commands ignored until end of transaction block ROLLBACK TO SAVEPOINT one; SELECT 1; ?column? ---------- 1 (1 row) COMMIT; SELECT 1; -- this should work ?column? ---------- 1 (1 row) -- check non-transactional behavior of cursors BEGIN; DECLARE c CURSOR FOR SELECT unique2 FROM tenk1 ORDER BY unique2; SAVEPOINT one; FETCH 10 FROM c; unique2 --------- 0 1 2 3 4 5 6 7 8 9 (10 rows) ROLLBACK TO SAVEPOINT one; FETCH 10 FROM c; unique2 --------- 10 11 12 13 14 15 16 17 18 19 (10 rows) RELEASE SAVEPOINT one; FETCH 10 FROM c; unique2 --------- 20 21 22 23 24 25 26 27 28 29 (10 rows) CLOSE c; DECLARE c CURSOR FOR SELECT unique2/0 FROM tenk1 ORDER BY unique2; SAVEPOINT two; FETCH 10 FROM c; ERROR: division by zero ROLLBACK TO SAVEPOINT two; -- c is now dead to the world ... FETCH 10 FROM c; ERROR: portal "c" cannot be run ROLLBACK TO SAVEPOINT two; RELEASE SAVEPOINT two; FETCH 10 FROM c; ERROR: portal "c" cannot be run COMMIT; -- -- Check that "stable" functions are really stable. They should not be -- able to see the partial results of the calling query. (Ideally we would -- also check that they don't see commits of concurrent transactions, but -- that's a mite hard to do within the limitations of pg_regress.) -- select * from xacttest; a | b -----+--------- 56 | 7.8 100 | 99.097 0 | 0.09561 42 | 324.78 777 | 777.777 (5 rows) create or replace function max_xacttest() returns smallint language sql as 'select max(a) from xacttest' stable; begin; update xacttest set a = max_xacttest() + 10 where a > 0; select * from xacttest; a | b -----+--------- 0 | 0.09561 787 | 7.8 787 | 99.097 787 | 324.78 787 | 777.777 (5 rows) rollback; -- But a volatile function can see the partial results of the calling query create or replace function max_xacttest() returns smallint language sql as 'select max(a) from xacttest' volatile; begin; update xacttest set a = max_xacttest() + 10 where a > 0; select * from xacttest; a | b -----+--------- 0 | 0.09561 787 | 7.8 797 | 99.097 807 | 324.78 817 | 777.777 (5 rows) rollback; -- Now the same test with plpgsql (since it depends on SPI which is different) create or replace function max_xacttest() returns smallint language plpgsql as 'begin return max(a) from xacttest; end' stable; begin; update xacttest set a = max_xacttest() + 10 where a > 0; select * from xacttest; a | b -----+--------- 0 | 0.09561 787 | 7.8 787 | 99.097 787 | 324.78 787 | 777.777 (5 rows) rollback; create or replace function max_xacttest() returns smallint language plpgsql as 'begin return max(a) from xacttest; end' volatile; begin; update xacttest set a = max_xacttest() + 10 where a > 0; select * from xacttest; a | b -----+--------- 0 | 0.09561 787 | 7.8 797 | 99.097 807 | 324.78 817 | 777.777 (5 rows) rollback; -- test case for problems with dropping an open relation during abort BEGIN; savepoint x; CREATE TABLE koju (a INT UNIQUE); INSERT INTO koju VALUES (1); INSERT INTO koju VALUES (1); ERROR: duplicate key value violates unique constraint "koju_a_key" DETAIL: Key (a)=(1) already exists. rollback to x; CREATE TABLE koju (a INT UNIQUE); INSERT INTO koju VALUES (1); INSERT INTO koju VALUES (1); ERROR: duplicate key value violates unique constraint "koju_a_key" DETAIL: Key (a)=(1) already exists. ROLLBACK; DROP TABLE trans_foo; DROP TABLE trans_baz; DROP TABLE trans_barbaz; -- test case for problems with revalidating an open relation during abort create function inverse(int) returns float8 as $$ begin analyze revalidate_bug; return 1::float8/$1; exception when division_by_zero then return 0; end$$ language plpgsql volatile; create table revalidate_bug (c float8 unique); insert into revalidate_bug values (1); insert into revalidate_bug values (inverse(0)); drop table revalidate_bug; drop function inverse(int); -- verify that cursors created during an aborted subtransaction are -- closed, but that we do not rollback the effect of any FETCHs -- performed in the aborted subtransaction begin; savepoint x; create table abc (a int); insert into abc values (5); insert into abc values (10); declare foo cursor for select * from abc; fetch from foo; a --- 5 (1 row) rollback to x; -- should fail fetch from foo; ERROR: cursor "foo" does not exist commit; begin; create table abc (a int); insert into abc values (5); insert into abc values (10); insert into abc values (15); declare foo cursor for select * from abc; fetch from foo; a --- 5 (1 row) savepoint x; fetch from foo; a ---- 10 (1 row) rollback to x; fetch from foo; a ---- 15 (1 row) abort; -- Test for proper cleanup after a failure in a cursor portal -- that was created in an outer subtransaction CREATE FUNCTION invert(x float8) RETURNS float8 LANGUAGE plpgsql AS $$ begin return 1/x; end $$; CREATE FUNCTION create_temp_tab() RETURNS text LANGUAGE plpgsql AS $$ BEGIN CREATE TEMP TABLE new_table (f1 float8); -- case of interest is that we fail while holding an open -- relcache reference to new_table INSERT INTO new_table SELECT invert(0.0); RETURN 'foo'; END $$; BEGIN; DECLARE ok CURSOR FOR SELECT * FROM int8_tbl; DECLARE ctt CURSOR FOR SELECT create_temp_tab(); FETCH ok; q1 | q2 -----+----- 123 | 456 (1 row) SAVEPOINT s1; FETCH ok; -- should work q1 | q2 -----+------------------ 123 | 4567890123456789 (1 row) FETCH ctt; -- error occurs here ERROR: division by zero CONTEXT: PL/pgSQL function invert(double precision) line 1 at RETURN SQL statement "INSERT INTO new_table SELECT invert(0.0)" PL/pgSQL function create_temp_tab() line 6 at SQL statement ROLLBACK TO s1; FETCH ok; -- should work q1 | q2 ------------------+----- 4567890123456789 | 123 (1 row) FETCH ctt; -- must be rejected ERROR: portal "ctt" cannot be run COMMIT; DROP FUNCTION create_temp_tab(); DROP FUNCTION invert(x float8); -- Tests for AND CHAIN CREATE TABLE abc (a int); -- set nondefault value so we have something to override below SET default_transaction_read_only = on; START TRANSACTION ISOLATION LEVEL REPEATABLE READ, READ WRITE, DEFERRABLE; SHOW transaction_isolation; transaction_isolation ----------------------- repeatable read (1 row) SHOW transaction_read_only; transaction_read_only ----------------------- off (1 row) SHOW transaction_deferrable; transaction_deferrable ------------------------ on (1 row) INSERT INTO abc VALUES (1); INSERT INTO abc VALUES (2); COMMIT AND CHAIN; -- TBLOCK_END SHOW transaction_isolation; transaction_isolation ----------------------- repeatable read (1 row) SHOW transaction_read_only; transaction_read_only ----------------------- off (1 row) SHOW transaction_deferrable; transaction_deferrable ------------------------ on (1 row) INSERT INTO abc VALUES ('error'); ERROR: invalid input syntax for type integer: "error" LINE 1: INSERT INTO abc VALUES ('error'); ^ INSERT INTO abc VALUES (3); -- check it's really aborted ERROR: current transaction is aborted, commands ignored until end of transaction block COMMIT AND CHAIN; -- TBLOCK_ABORT_END SHOW transaction_isolation; transaction_isolation ----------------------- repeatable read (1 row) SHOW transaction_read_only; transaction_read_only ----------------------- off (1 row) SHOW transaction_deferrable; transaction_deferrable ------------------------ on (1 row) INSERT INTO abc VALUES (4); COMMIT; START TRANSACTION ISOLATION LEVEL REPEATABLE READ, READ WRITE, DEFERRABLE; SHOW transaction_isolation; transaction_isolation ----------------------- repeatable read (1 row) SHOW transaction_read_only; transaction_read_only ----------------------- off (1 row) SHOW transaction_deferrable; transaction_deferrable ------------------------ on (1 row) SAVEPOINT x; INSERT INTO abc VALUES ('error'); ERROR: invalid input syntax for type integer: "error" LINE 1: INSERT INTO abc VALUES ('error'); ^ COMMIT AND CHAIN; -- TBLOCK_ABORT_PENDING SHOW transaction_isolation; transaction_isolation ----------------------- repeatable read (1 row) SHOW transaction_read_only; transaction_read_only ----------------------- off (1 row) SHOW transaction_deferrable; transaction_deferrable ------------------------ on (1 row) INSERT INTO abc VALUES (5); COMMIT; START TRANSACTION ISOLATION LEVEL REPEATABLE READ, READ WRITE, DEFERRABLE; SHOW transaction_isolation; transaction_isolation ----------------------- repeatable read (1 row) SHOW transaction_read_only; transaction_read_only ----------------------- off (1 row) SHOW transaction_deferrable; transaction_deferrable ------------------------ on (1 row) SAVEPOINT x; COMMIT AND CHAIN; -- TBLOCK_SUBCOMMIT SHOW transaction_isolation; transaction_isolation ----------------------- repeatable read (1 row) SHOW transaction_read_only; transaction_read_only ----------------------- off (1 row) SHOW transaction_deferrable; transaction_deferrable ------------------------ on (1 row) COMMIT; -- different mix of options just for fun START TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ WRITE, NOT DEFERRABLE; SHOW transaction_isolation; transaction_isolation ----------------------- serializable (1 row) SHOW transaction_read_only; transaction_read_only ----------------------- off (1 row) SHOW transaction_deferrable; transaction_deferrable ------------------------ off (1 row) INSERT INTO abc VALUES (6); ROLLBACK AND CHAIN; -- TBLOCK_ABORT_PENDING SHOW transaction_isolation; transaction_isolation ----------------------- serializable (1 row) SHOW transaction_read_only; transaction_read_only ----------------------- off (1 row) SHOW transaction_deferrable; transaction_deferrable ------------------------ off (1 row) INSERT INTO abc VALUES ('error'); ERROR: invalid input syntax for type integer: "error" LINE 1: INSERT INTO abc VALUES ('error'); ^ ROLLBACK AND CHAIN; -- TBLOCK_ABORT_END SHOW transaction_isolation; transaction_isolation ----------------------- serializable (1 row) SHOW transaction_read_only; transaction_read_only ----------------------- off (1 row) SHOW transaction_deferrable; transaction_deferrable ------------------------ off (1 row) ROLLBACK; -- not allowed outside a transaction block COMMIT AND CHAIN; -- error ERROR: COMMIT AND CHAIN can only be used in transaction blocks ROLLBACK AND CHAIN; -- error ERROR: ROLLBACK AND CHAIN can only be used in transaction blocks SELECT * FROM abc ORDER BY 1; a --- 1 2 4 5 (4 rows) RESET default_transaction_read_only; DROP TABLE abc; -- Test assorted behaviors around the implicit transaction block created -- when multiple SQL commands are sent in a single Query message. These -- tests rely on the fact that psql will not break SQL commands apart at a -- backslash-quoted semicolon, but will send them as one Query. create temp table i_table (f1 int); -- psql will show only the last result in a multi-statement Query SELECT 1\; SELECT 2\; SELECT 3; ?column? ---------- 3 (1 row) -- this implicitly commits: insert into i_table values(1)\; select * from i_table; f1 ---- 1 (1 row) -- 1/0 error will cause rolling back the whole implicit transaction insert into i_table values(2)\; select * from i_table\; select 1/0; ERROR: division by zero select * from i_table; f1 ---- 1 (1 row) rollback; -- we are not in a transaction at this point WARNING: there is no transaction in progress -- can use regular begin/commit/rollback within a single Query begin\; insert into i_table values(3)\; commit; rollback; -- we are not in a transaction at this point WARNING: there is no transaction in progress begin\; insert into i_table values(4)\; rollback; rollback; -- we are not in a transaction at this point WARNING: there is no transaction in progress -- begin converts implicit transaction into a regular one that -- can extend past the end of the Query select 1\; begin\; insert into i_table values(5); commit; select 1\; begin\; insert into i_table values(6); rollback; -- commit in implicit-transaction state commits but issues a warning. insert into i_table values(7)\; commit\; insert into i_table values(8)\; select 1/0; WARNING: there is no transaction in progress ERROR: division by zero -- similarly, rollback aborts but issues a warning. insert into i_table values(9)\; rollback\; select 2; WARNING: there is no transaction in progress ?column? ---------- 2 (1 row) select * from i_table; f1 ---- 1 3 5 7 (4 rows) rollback; -- we are not in a transaction at this point WARNING: there is no transaction in progress -- implicit transaction block is still a transaction block, for e.g. VACUUM SELECT 1\; VACUUM; ERROR: VACUUM cannot run inside a transaction block SELECT 1\; COMMIT\; VACUUM; WARNING: there is no transaction in progress ERROR: VACUUM cannot run inside a transaction block -- we disallow savepoint-related commands in implicit-transaction state SELECT 1\; SAVEPOINT sp; ERROR: SAVEPOINT can only be used in transaction blocks SELECT 1\; COMMIT\; SAVEPOINT sp; WARNING: there is no transaction in progress ERROR: SAVEPOINT can only be used in transaction blocks ROLLBACK TO SAVEPOINT sp\; SELECT 2; ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks SELECT 2\; RELEASE SAVEPOINT sp\; SELECT 3; ERROR: RELEASE SAVEPOINT can only be used in transaction blocks -- but this is OK, because the BEGIN converts it to a regular xact SELECT 1\; BEGIN\; SAVEPOINT sp\; ROLLBACK TO SAVEPOINT sp\; COMMIT; -- Tests for AND CHAIN in implicit transaction blocks SET TRANSACTION READ ONLY\; COMMIT AND CHAIN; -- error ERROR: COMMIT AND CHAIN can only be used in transaction blocks SHOW transaction_read_only; transaction_read_only ----------------------- off (1 row) SET TRANSACTION READ ONLY\; ROLLBACK AND CHAIN; -- error ERROR: ROLLBACK AND CHAIN can only be used in transaction blocks SHOW transaction_read_only; transaction_read_only ----------------------- off (1 row) CREATE TABLE abc (a int); -- COMMIT/ROLLBACK + COMMIT/ROLLBACK AND CHAIN INSERT INTO abc VALUES (7)\; COMMIT\; INSERT INTO abc VALUES (8)\; COMMIT AND CHAIN; -- 7 commit, 8 error WARNING: there is no transaction in progress ERROR: COMMIT AND CHAIN can only be used in transaction blocks INSERT INTO abc VALUES (9)\; ROLLBACK\; INSERT INTO abc VALUES (10)\; ROLLBACK AND CHAIN; -- 9 rollback, 10 error WARNING: there is no transaction in progress ERROR: ROLLBACK AND CHAIN can only be used in transaction blocks -- COMMIT/ROLLBACK AND CHAIN + COMMIT/ROLLBACK INSERT INTO abc VALUES (11)\; COMMIT AND CHAIN\; INSERT INTO abc VALUES (12)\; COMMIT; -- 11 error, 12 not reached ERROR: COMMIT AND CHAIN can only be used in transaction blocks INSERT INTO abc VALUES (13)\; ROLLBACK AND CHAIN\; INSERT INTO abc VALUES (14)\; ROLLBACK; -- 13 error, 14 not reached ERROR: ROLLBACK AND CHAIN can only be used in transaction blocks -- START TRANSACTION + COMMIT/ROLLBACK AND CHAIN START TRANSACTION ISOLATION LEVEL REPEATABLE READ\; INSERT INTO abc VALUES (15)\; COMMIT AND CHAIN; -- 15 ok SHOW transaction_isolation; -- transaction is active at this point transaction_isolation ----------------------- repeatable read (1 row) COMMIT; START TRANSACTION ISOLATION LEVEL REPEATABLE READ\; INSERT INTO abc VALUES (16)\; ROLLBACK AND CHAIN; -- 16 ok SHOW transaction_isolation; -- transaction is active at this point transaction_isolation ----------------------- repeatable read (1 row) ROLLBACK; -- START TRANSACTION + COMMIT/ROLLBACK + COMMIT/ROLLBACK AND CHAIN START TRANSACTION ISOLATION LEVEL REPEATABLE READ\; INSERT INTO abc VALUES (17)\; COMMIT\; INSERT INTO abc VALUES (18)\; COMMIT AND CHAIN; -- 17 commit, 18 error ERROR: COMMIT AND CHAIN can only be used in transaction blocks SHOW transaction_isolation; -- out of transaction block transaction_isolation ----------------------- read committed (1 row) START TRANSACTION ISOLATION LEVEL REPEATABLE READ\; INSERT INTO abc VALUES (19)\; ROLLBACK\; INSERT INTO abc VALUES (20)\; ROLLBACK AND CHAIN; -- 19 rollback, 20 error ERROR: ROLLBACK AND CHAIN can only be used in transaction blocks SHOW transaction_isolation; -- out of transaction block transaction_isolation ----------------------- read committed (1 row) SELECT * FROM abc ORDER BY 1; a ---- 7 15 17 (3 rows) DROP TABLE abc; -- Test for successful cleanup of an aborted transaction at session exit. -- THIS MUST BE THE LAST TEST IN THIS FILE. begin; select 1/0; ERROR: division by zero rollback to X; ERROR: savepoint "x" does not exist -- DO NOT ADD ANYTHING HERE.