1--
2-- TRANSACTIONS
3--
4
5BEGIN;
6
7SELECT *
8   INTO TABLE xacttest
9   FROM aggtest;
10
11INSERT INTO xacttest (a, b) VALUES (777, 777.777);
12
13END;
14
15-- should retrieve one value--
16SELECT a FROM xacttest WHERE a > 100;
17
18
19BEGIN;
20
21CREATE TABLE disappear (a int4);
22
23DELETE FROM aggtest;
24
25-- should be empty
26SELECT * FROM aggtest;
27
28ABORT;
29
30-- should not exist
31SELECT oid FROM pg_class WHERE relname = 'disappear';
32
33-- should have members again
34SELECT * FROM aggtest;
35
36
37-- Read-only tests
38
39CREATE TABLE writetest (a int);
40CREATE TEMPORARY TABLE temptest (a int);
41
42BEGIN;
43SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY, DEFERRABLE; -- ok
44SELECT * FROM writetest; -- ok
45SET TRANSACTION READ WRITE; --fail
46COMMIT;
47
48BEGIN;
49SET TRANSACTION READ ONLY; -- ok
50SET TRANSACTION READ WRITE; -- ok
51SET TRANSACTION READ ONLY; -- ok
52SELECT * FROM writetest; -- ok
53SAVEPOINT x;
54SET TRANSACTION READ ONLY; -- ok
55SELECT * FROM writetest; -- ok
56SET TRANSACTION READ ONLY; -- ok
57SET TRANSACTION READ WRITE; --fail
58COMMIT;
59
60BEGIN;
61SET TRANSACTION READ WRITE; -- ok
62SAVEPOINT x;
63SET TRANSACTION READ WRITE; -- ok
64SET TRANSACTION READ ONLY; -- ok
65SELECT * FROM writetest; -- ok
66SET TRANSACTION READ ONLY; -- ok
67SET TRANSACTION READ WRITE; --fail
68COMMIT;
69
70BEGIN;
71SET TRANSACTION READ WRITE; -- ok
72SAVEPOINT x;
73SET TRANSACTION READ ONLY; -- ok
74SELECT * FROM writetest; -- ok
75ROLLBACK TO SAVEPOINT x;
76SHOW transaction_read_only;  -- off
77SAVEPOINT y;
78SET TRANSACTION READ ONLY; -- ok
79SELECT * FROM writetest; -- ok
80RELEASE SAVEPOINT y;
81SHOW transaction_read_only;  -- off
82COMMIT;
83
84SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY;
85
86DROP TABLE writetest; -- fail
87INSERT INTO writetest VALUES (1); -- fail
88SELECT * FROM writetest; -- ok
89DELETE FROM temptest; -- ok
90UPDATE temptest SET a = 0 FROM writetest WHERE temptest.a = 1 AND writetest.a = temptest.a; -- ok
91PREPARE test AS UPDATE writetest SET a = 0; -- ok
92EXECUTE test; -- fail
93SELECT * FROM writetest, temptest; -- ok
94CREATE TABLE test AS SELECT * FROM writetest; -- fail
95
96START TRANSACTION READ WRITE;
97DROP TABLE writetest; -- ok
98COMMIT;
99
100-- Subtransactions, basic tests
101-- create & drop tables
102SET SESSION CHARACTERISTICS AS TRANSACTION READ WRITE;
103CREATE TABLE foobar (a int);
104BEGIN;
105	CREATE TABLE foo (a int);
106	SAVEPOINT one;
107		DROP TABLE foo;
108		CREATE TABLE bar (a int);
109	ROLLBACK TO SAVEPOINT one;
110	RELEASE SAVEPOINT one;
111	SAVEPOINT two;
112		CREATE TABLE baz (a int);
113	RELEASE SAVEPOINT two;
114	drop TABLE foobar;
115	CREATE TABLE barbaz (a int);
116COMMIT;
117-- should exist: barbaz, baz, foo
118SELECT * FROM foo;		-- should be empty
119SELECT * FROM bar;		-- shouldn't exist
120SELECT * FROM barbaz;	-- should be empty
121SELECT * FROM baz;		-- should be empty
122
123-- inserts
124BEGIN;
125	INSERT INTO foo VALUES (1);
126	SAVEPOINT one;
127		INSERT into bar VALUES (1);
128	ROLLBACK TO one;
129	RELEASE SAVEPOINT one;
130	SAVEPOINT two;
131		INSERT into barbaz VALUES (1);
132	RELEASE two;
133	SAVEPOINT three;
134		SAVEPOINT four;
135			INSERT INTO foo VALUES (2);
136		RELEASE SAVEPOINT four;
137	ROLLBACK TO SAVEPOINT three;
138	RELEASE SAVEPOINT three;
139	INSERT INTO foo VALUES (3);
140COMMIT;
141SELECT * FROM foo;		-- should have 1 and 3
142SELECT * FROM barbaz;	-- should have 1
143
144-- test whole-tree commit
145BEGIN;
146	SAVEPOINT one;
147		SELECT foo;
148	ROLLBACK TO SAVEPOINT one;
149	RELEASE SAVEPOINT one;
150	SAVEPOINT two;
151		CREATE TABLE savepoints (a int);
152		SAVEPOINT three;
153			INSERT INTO savepoints VALUES (1);
154			SAVEPOINT four;
155				INSERT INTO savepoints VALUES (2);
156				SAVEPOINT five;
157					INSERT INTO savepoints VALUES (3);
158				ROLLBACK TO SAVEPOINT five;
159COMMIT;
160COMMIT;		-- should not be in a transaction block
161SELECT * FROM savepoints;
162
163-- test whole-tree rollback
164BEGIN;
165	SAVEPOINT one;
166		DELETE FROM savepoints WHERE a=1;
167	RELEASE SAVEPOINT one;
168	SAVEPOINT two;
169		DELETE FROM savepoints WHERE a=1;
170		SAVEPOINT three;
171			DELETE FROM savepoints WHERE a=2;
172ROLLBACK;
173COMMIT;		-- should not be in a transaction block
174
175SELECT * FROM savepoints;
176
177-- test whole-tree commit on an aborted subtransaction
178BEGIN;
179	INSERT INTO savepoints VALUES (4);
180	SAVEPOINT one;
181		INSERT INTO savepoints VALUES (5);
182		SELECT foo;
183COMMIT;
184SELECT * FROM savepoints;
185
186BEGIN;
187	INSERT INTO savepoints VALUES (6);
188	SAVEPOINT one;
189		INSERT INTO savepoints VALUES (7);
190	RELEASE SAVEPOINT one;
191	INSERT INTO savepoints VALUES (8);
192COMMIT;
193-- rows 6 and 8 should have been created by the same xact
194SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=6 AND b.a=8;
195-- rows 6 and 7 should have been created by different xacts
196SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=6 AND b.a=7;
197
198BEGIN;
199	INSERT INTO savepoints VALUES (9);
200	SAVEPOINT one;
201		INSERT INTO savepoints VALUES (10);
202	ROLLBACK TO SAVEPOINT one;
203		INSERT INTO savepoints VALUES (11);
204COMMIT;
205SELECT a FROM savepoints WHERE a in (9, 10, 11);
206-- rows 9 and 11 should have been created by different xacts
207SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=9 AND b.a=11;
208
209BEGIN;
210	INSERT INTO savepoints VALUES (12);
211	SAVEPOINT one;
212		INSERT INTO savepoints VALUES (13);
213		SAVEPOINT two;
214			INSERT INTO savepoints VALUES (14);
215	ROLLBACK TO SAVEPOINT one;
216		INSERT INTO savepoints VALUES (15);
217		SAVEPOINT two;
218			INSERT INTO savepoints VALUES (16);
219			SAVEPOINT three;
220				INSERT INTO savepoints VALUES (17);
221COMMIT;
222SELECT a FROM savepoints WHERE a BETWEEN 12 AND 17;
223
224BEGIN;
225	INSERT INTO savepoints VALUES (18);
226	SAVEPOINT one;
227		INSERT INTO savepoints VALUES (19);
228		SAVEPOINT two;
229			INSERT INTO savepoints VALUES (20);
230	ROLLBACK TO SAVEPOINT one;
231		INSERT INTO savepoints VALUES (21);
232	ROLLBACK TO SAVEPOINT one;
233		INSERT INTO savepoints VALUES (22);
234COMMIT;
235SELECT a FROM savepoints WHERE a BETWEEN 18 AND 22;
236
237DROP TABLE savepoints;
238
239-- only in a transaction block:
240SAVEPOINT one;
241ROLLBACK TO SAVEPOINT one;
242RELEASE SAVEPOINT one;
243
244-- Only "rollback to" allowed in aborted state
245BEGIN;
246  SAVEPOINT one;
247  SELECT 0/0;
248  SAVEPOINT two;    -- ignored till the end of ...
249  RELEASE SAVEPOINT one;      -- ignored till the end of ...
250  ROLLBACK TO SAVEPOINT one;
251  SELECT 1;
252COMMIT;
253SELECT 1;			-- this should work
254
255-- check non-transactional behavior of cursors
256BEGIN;
257	DECLARE c CURSOR FOR SELECT unique2 FROM tenk1 ORDER BY unique2;
258	SAVEPOINT one;
259		FETCH 10 FROM c;
260	ROLLBACK TO SAVEPOINT one;
261		FETCH 10 FROM c;
262	RELEASE SAVEPOINT one;
263	FETCH 10 FROM c;
264	CLOSE c;
265	DECLARE c CURSOR FOR SELECT unique2/0 FROM tenk1 ORDER BY unique2;
266	SAVEPOINT two;
267		FETCH 10 FROM c;
268	ROLLBACK TO SAVEPOINT two;
269	-- c is now dead to the world ...
270		FETCH 10 FROM c;
271	ROLLBACK TO SAVEPOINT two;
272	RELEASE SAVEPOINT two;
273	FETCH 10 FROM c;
274COMMIT;
275
276--
277-- Check that "stable" functions are really stable.  They should not be
278-- able to see the partial results of the calling query.  (Ideally we would
279-- also check that they don't see commits of concurrent transactions, but
280-- that's a mite hard to do within the limitations of pg_regress.)
281--
282select * from xacttest;
283
284create or replace function max_xacttest() returns smallint language sql as
285'select max(a) from xacttest' stable;
286
287begin;
288update xacttest set a = max_xacttest() + 10 where a > 0;
289select * from xacttest;
290rollback;
291
292-- But a volatile function can see the partial results of the calling query
293create or replace function max_xacttest() returns smallint language sql as
294'select max(a) from xacttest' volatile;
295
296begin;
297update xacttest set a = max_xacttest() + 10 where a > 0;
298select * from xacttest;
299rollback;
300
301-- Now the same test with plpgsql (since it depends on SPI which is different)
302create or replace function max_xacttest() returns smallint language plpgsql as
303'begin return max(a) from xacttest; end' stable;
304
305begin;
306update xacttest set a = max_xacttest() + 10 where a > 0;
307select * from xacttest;
308rollback;
309
310create or replace function max_xacttest() returns smallint language plpgsql as
311'begin return max(a) from xacttest; end' volatile;
312
313begin;
314update xacttest set a = max_xacttest() + 10 where a > 0;
315select * from xacttest;
316rollback;
317
318
319-- test case for problems with dropping an open relation during abort
320BEGIN;
321	savepoint x;
322		CREATE TABLE koju (a INT UNIQUE);
323		INSERT INTO koju VALUES (1);
324		INSERT INTO koju VALUES (1);
325	rollback to x;
326
327	CREATE TABLE koju (a INT UNIQUE);
328	INSERT INTO koju VALUES (1);
329	INSERT INTO koju VALUES (1);
330ROLLBACK;
331
332DROP TABLE foo;
333DROP TABLE baz;
334DROP TABLE barbaz;
335
336
337-- test case for problems with revalidating an open relation during abort
338create function inverse(int) returns float8 as
339$$
340begin
341  analyze revalidate_bug;
342  return 1::float8/$1;
343exception
344  when division_by_zero then return 0;
345end$$ language plpgsql volatile;
346
347create table revalidate_bug (c float8 unique);
348insert into revalidate_bug values (1);
349insert into revalidate_bug values (inverse(0));
350
351drop table revalidate_bug;
352drop function inverse(int);
353
354
355-- verify that cursors created during an aborted subtransaction are
356-- closed, but that we do not rollback the effect of any FETCHs
357-- performed in the aborted subtransaction
358begin;
359
360savepoint x;
361create table abc (a int);
362insert into abc values (5);
363insert into abc values (10);
364declare foo cursor for select * from abc;
365fetch from foo;
366rollback to x;
367
368-- should fail
369fetch from foo;
370commit;
371
372begin;
373
374create table abc (a int);
375insert into abc values (5);
376insert into abc values (10);
377insert into abc values (15);
378declare foo cursor for select * from abc;
379
380fetch from foo;
381
382savepoint x;
383fetch from foo;
384rollback to x;
385
386fetch from foo;
387
388abort;
389
390
391-- Test for proper cleanup after a failure in a cursor portal
392-- that was created in an outer subtransaction
393CREATE FUNCTION invert(x float8) RETURNS float8 LANGUAGE plpgsql AS
394$$ begin return 1/x; end $$;
395
396CREATE FUNCTION create_temp_tab() RETURNS text
397LANGUAGE plpgsql AS $$
398BEGIN
399  CREATE TEMP TABLE new_table (f1 float8);
400  -- case of interest is that we fail while holding an open
401  -- relcache reference to new_table
402  INSERT INTO new_table SELECT invert(0.0);
403  RETURN 'foo';
404END $$;
405
406BEGIN;
407DECLARE ok CURSOR FOR SELECT * FROM int8_tbl;
408DECLARE ctt CURSOR FOR SELECT create_temp_tab();
409FETCH ok;
410SAVEPOINT s1;
411FETCH ok;  -- should work
412FETCH ctt; -- error occurs here
413ROLLBACK TO s1;
414FETCH ok;  -- should work
415FETCH ctt; -- must be rejected
416COMMIT;
417
418DROP FUNCTION create_temp_tab();
419DROP FUNCTION invert(x float8);
420
421
422-- Test for successful cleanup of an aborted transaction at session exit.
423-- THIS MUST BE THE LAST TEST IN THIS FILE.
424
425begin;
426select 1/0;
427rollback to X;
428
429-- DO NOT ADD ANYTHING HERE.
430