2 -- Test explicit subtransactions
4 -- Test table to see if transactions get properly rolled back
5 CREATE TABLE subtransaction_tbl (
8 CREATE FUNCTION subtransaction_ctx_test(what_error text = NULL) RETURNS text
10 with plpy.subtransaction():
11 plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
12 plpy.execute("INSERT INTO subtransaction_tbl VALUES (2)")
13 if what_error == "SPI":
14 plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')")
15 elif what_error == "Python":
16 raise Exception("Python exception")
17 $$ LANGUAGE plpythonu;
18 SELECT subtransaction_ctx_test();
19 subtransaction_ctx_test
20 -------------------------
24 SELECT * FROM subtransaction_tbl;
31 TRUNCATE subtransaction_tbl;
32 SELECT subtransaction_ctx_test('SPI');
33 ERROR: spiexceptions.InvalidTextRepresentation: invalid input syntax for type integer: "oops"
34 LINE 1: INSERT INTO subtransaction_tbl VALUES ('oops')
36 QUERY: INSERT INTO subtransaction_tbl VALUES ('oops')
37 CONTEXT: Traceback (most recent call last):
38 PL/Python function "subtransaction_ctx_test", line 6, in <module>
39 plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')")
40 PL/Python function "subtransaction_ctx_test"
41 SELECT * FROM subtransaction_tbl;
46 TRUNCATE subtransaction_tbl;
47 SELECT subtransaction_ctx_test('Python');
48 ERROR: Exception: Python exception
49 CONTEXT: Traceback (most recent call last):
50 PL/Python function "subtransaction_ctx_test", line 8, in <module>
51 raise Exception("Python exception")
52 PL/Python function "subtransaction_ctx_test"
53 SELECT * FROM subtransaction_tbl;
58 TRUNCATE subtransaction_tbl;
59 -- Nested subtransactions
60 CREATE FUNCTION subtransaction_nested_test(swallow boolean = 'f') RETURNS text
62 plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
63 with plpy.subtransaction():
64 plpy.execute("INSERT INTO subtransaction_tbl VALUES (2)")
66 with plpy.subtransaction():
67 plpy.execute("INSERT INTO subtransaction_tbl VALUES (3)")
69 except plpy.SPIError as e:
72 plpy.notice("Swallowed %s(%r)" % (e.__class__.__name__, e.args[0]))
74 $$ LANGUAGE plpythonu;
75 SELECT subtransaction_nested_test();
76 ERROR: spiexceptions.SyntaxError: syntax error at or near "error"
80 CONTEXT: Traceback (most recent call last):
81 PL/Python function "subtransaction_nested_test", line 8, in <module>
83 PL/Python function "subtransaction_nested_test"
84 SELECT * FROM subtransaction_tbl;
89 TRUNCATE subtransaction_tbl;
90 SELECT subtransaction_nested_test('t');
91 NOTICE: Swallowed SyntaxError('syntax error at or near "error"')
92 subtransaction_nested_test
93 ----------------------------
97 SELECT * FROM subtransaction_tbl;
104 TRUNCATE subtransaction_tbl;
105 -- Nested subtransactions that recursively call code dealing with
107 CREATE FUNCTION subtransaction_deeply_nested_test() RETURNS text
109 plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
110 with plpy.subtransaction():
111 plpy.execute("INSERT INTO subtransaction_tbl VALUES (2)")
112 plpy.execute("SELECT subtransaction_nested_test('t')")
114 $$ LANGUAGE plpythonu;
115 SELECT subtransaction_deeply_nested_test();
116 NOTICE: Swallowed SyntaxError('syntax error at or near "error"')
117 subtransaction_deeply_nested_test
118 -----------------------------------
122 SELECT * FROM subtransaction_tbl;
131 TRUNCATE subtransaction_tbl;
132 -- Error conditions from not opening/closing subtransactions
133 CREATE FUNCTION subtransaction_exit_without_enter() RETURNS void
135 plpy.subtransaction().__exit__(None, None, None)
136 $$ LANGUAGE plpythonu;
137 CREATE FUNCTION subtransaction_enter_without_exit() RETURNS void
139 plpy.subtransaction().__enter__()
140 $$ LANGUAGE plpythonu;
141 CREATE FUNCTION subtransaction_exit_twice() RETURNS void
143 plpy.subtransaction().__enter__()
144 plpy.subtransaction().__exit__(None, None, None)
145 plpy.subtransaction().__exit__(None, None, None)
146 $$ LANGUAGE plpythonu;
147 CREATE FUNCTION subtransaction_enter_twice() RETURNS void
149 plpy.subtransaction().__enter__()
150 plpy.subtransaction().__enter__()
151 $$ LANGUAGE plpythonu;
152 CREATE FUNCTION subtransaction_exit_same_subtransaction_twice() RETURNS void
154 s = plpy.subtransaction()
156 s.__exit__(None, None, None)
157 s.__exit__(None, None, None)
158 $$ LANGUAGE plpythonu;
159 CREATE FUNCTION subtransaction_enter_same_subtransaction_twice() RETURNS void
161 s = plpy.subtransaction()
164 s.__exit__(None, None, None)
165 $$ LANGUAGE plpythonu;
166 -- No warnings here, as the subtransaction gets indeed closed
167 CREATE FUNCTION subtransaction_enter_subtransaction_in_with() RETURNS void
169 with plpy.subtransaction() as s:
171 $$ LANGUAGE plpythonu;
172 CREATE FUNCTION subtransaction_exit_subtransaction_in_with() RETURNS void
175 with plpy.subtransaction() as s:
176 s.__exit__(None, None, None)
177 except ValueError as e:
179 $$ LANGUAGE plpythonu;
180 SELECT subtransaction_exit_without_enter();
181 ERROR: ValueError: this subtransaction has not been entered
182 CONTEXT: Traceback (most recent call last):
183 PL/Python function "subtransaction_exit_without_enter", line 2, in <module>
184 plpy.subtransaction().__exit__(None, None, None)
185 PL/Python function "subtransaction_exit_without_enter"
186 SELECT subtransaction_enter_without_exit();
187 WARNING: forcibly aborting a subtransaction that has not been exited
188 subtransaction_enter_without_exit
189 -----------------------------------
193 SELECT subtransaction_exit_twice();
194 WARNING: forcibly aborting a subtransaction that has not been exited
195 ERROR: ValueError: this subtransaction has not been entered
196 CONTEXT: Traceback (most recent call last):
197 PL/Python function "subtransaction_exit_twice", line 3, in <module>
198 plpy.subtransaction().__exit__(None, None, None)
199 PL/Python function "subtransaction_exit_twice"
200 SELECT subtransaction_enter_twice();
201 WARNING: forcibly aborting a subtransaction that has not been exited
202 WARNING: forcibly aborting a subtransaction that has not been exited
203 subtransaction_enter_twice
204 ----------------------------
208 SELECT subtransaction_exit_same_subtransaction_twice();
209 ERROR: ValueError: this subtransaction has already been exited
210 CONTEXT: Traceback (most recent call last):
211 PL/Python function "subtransaction_exit_same_subtransaction_twice", line 5, in <module>
212 s.__exit__(None, None, None)
213 PL/Python function "subtransaction_exit_same_subtransaction_twice"
214 SELECT subtransaction_enter_same_subtransaction_twice();
215 WARNING: forcibly aborting a subtransaction that has not been exited
216 ERROR: ValueError: this subtransaction has already been entered
217 CONTEXT: Traceback (most recent call last):
218 PL/Python function "subtransaction_enter_same_subtransaction_twice", line 4, in <module>
220 PL/Python function "subtransaction_enter_same_subtransaction_twice"
221 SELECT subtransaction_enter_subtransaction_in_with();
222 ERROR: ValueError: this subtransaction has already been entered
223 CONTEXT: Traceback (most recent call last):
224 PL/Python function "subtransaction_enter_subtransaction_in_with", line 3, in <module>
226 PL/Python function "subtransaction_enter_subtransaction_in_with"
227 SELECT subtransaction_exit_subtransaction_in_with();
228 ERROR: ValueError: this subtransaction has already been exited
229 CONTEXT: Traceback (most recent call last):
230 PL/Python function "subtransaction_exit_subtransaction_in_with", line 6, in <module>
232 PL/Python function "subtransaction_exit_subtransaction_in_with"
233 -- Make sure we don't get a "current transaction is aborted" error
240 -- Mix explicit subtransactions and normal SPI calls
241 CREATE FUNCTION subtransaction_mix_explicit_and_implicit() RETURNS void
243 p = plpy.prepare("INSERT INTO subtransaction_tbl VALUES ($1)", ["integer"])
245 with plpy.subtransaction():
246 plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
248 plpy.execute(p, ["wrong"])
249 except plpy.SPIError:
250 plpy.warning("Caught a SPI error from an explicit subtransaction")
253 plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
255 plpy.execute(p, ["wrong"])
256 except plpy.SPIError:
257 plpy.warning("Caught a SPI error")
258 $$ LANGUAGE plpythonu;
259 SELECT subtransaction_mix_explicit_and_implicit();
260 WARNING: Caught a SPI error from an explicit subtransaction
261 WARNING: Caught a SPI error
262 subtransaction_mix_explicit_and_implicit
263 ------------------------------------------
267 SELECT * FROM subtransaction_tbl;
274 TRUNCATE subtransaction_tbl;
275 -- Alternative method names for Python <2.6
276 CREATE FUNCTION subtransaction_alternative_names() RETURNS void
278 s = plpy.subtransaction()
280 s.exit(None, None, None)
281 $$ LANGUAGE plpythonu;
282 SELECT subtransaction_alternative_names();
283 subtransaction_alternative_names
284 ----------------------------------
288 -- try/catch inside a subtransaction block
289 CREATE FUNCTION try_catch_inside_subtransaction() RETURNS void
291 with plpy.subtransaction():
292 plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
294 plpy.execute("INSERT INTO subtransaction_tbl VALUES ('a')")
295 except plpy.SPIError:
296 plpy.notice("caught")
297 $$ LANGUAGE plpythonu;
298 SELECT try_catch_inside_subtransaction();
300 try_catch_inside_subtransaction
301 ---------------------------------
305 SELECT * FROM subtransaction_tbl;
311 TRUNCATE subtransaction_tbl;
312 ALTER TABLE subtransaction_tbl ADD PRIMARY KEY (i);
313 CREATE FUNCTION pk_violation_inside_subtransaction() RETURNS void
315 with plpy.subtransaction():
316 plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
318 plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
319 except plpy.SPIError:
320 plpy.notice("caught")
321 $$ LANGUAGE plpythonu;
322 SELECT pk_violation_inside_subtransaction();
324 pk_violation_inside_subtransaction
325 ------------------------------------
329 SELECT * FROM subtransaction_tbl;
335 DROP TABLE subtransaction_tbl;
336 -- cursor/subtransactions interactions
337 CREATE FUNCTION cursor_in_subxact() RETURNS int AS $$
338 with plpy.subtransaction():
339 cur = plpy.cursor("select * from generate_series(1, 20) as gen(i)")
341 fetched = cur.fetch(10);
342 return int(fetched[5]["i"])
343 $$ LANGUAGE plpythonu;
344 CREATE FUNCTION cursor_aborted_subxact() RETURNS int AS $$
346 with plpy.subtransaction():
347 cur = plpy.cursor("select * from generate_series(1, 20) as gen(i)")
349 plpy.execute("select no_such_function()")
350 except plpy.SPIError:
351 fetched = cur.fetch(10)
352 return int(fetched[5]["i"])
353 return 0 # not reached
354 $$ LANGUAGE plpythonu;
355 CREATE FUNCTION cursor_plan_aborted_subxact() RETURNS int AS $$
357 with plpy.subtransaction():
358 plpy.execute('create temporary table tmp(i) '
359 'as select generate_series(1, 10)')
360 plan = plpy.prepare("select i from tmp")
361 cur = plpy.cursor(plan)
362 plpy.execute("select no_such_function()")
363 except plpy.SPIError:
364 fetched = cur.fetch(5)
365 return fetched[2]["i"]
366 return 0 # not reached
367 $$ LANGUAGE plpythonu;
368 CREATE FUNCTION cursor_close_aborted_subxact() RETURNS boolean AS $$
370 with plpy.subtransaction():
371 cur = plpy.cursor('select 1')
372 plpy.execute("select no_such_function()")
373 except plpy.SPIError:
376 return False # not reached
377 $$ LANGUAGE plpythonu;
378 SELECT cursor_in_subxact();
384 SELECT cursor_aborted_subxact();
385 ERROR: ValueError: iterating a cursor in an aborted subtransaction
386 CONTEXT: Traceback (most recent call last):
387 PL/Python function "cursor_aborted_subxact", line 8, in <module>
388 fetched = cur.fetch(10)
389 PL/Python function "cursor_aborted_subxact"
390 SELECT cursor_plan_aborted_subxact();
391 ERROR: ValueError: iterating a cursor in an aborted subtransaction
392 CONTEXT: Traceback (most recent call last):
393 PL/Python function "cursor_plan_aborted_subxact", line 10, in <module>
394 fetched = cur.fetch(5)
395 PL/Python function "cursor_plan_aborted_subxact"
396 SELECT cursor_close_aborted_subxact();
397 ERROR: ValueError: closing a cursor in an aborted subtransaction
398 CONTEXT: Traceback (most recent call last):
399 PL/Python function "cursor_close_aborted_subxact", line 7, in <module>
401 PL/Python function "cursor_close_aborted_subxact"