summaryrefslogtreecommitdiff
path: root/src/pl/plpython/sql/plpython_subtransaction.sql
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2011-02-27 17:09:56 +0200
committerPeter Eisentraut <peter_e@gmx.net>2011-02-27 21:15:35 +0200
commit22690719ea5a89ccbcd04deb58c83d8d5f138df8 (patch)
treeda9e49d59849631b4af9536cb414e31a825cb571 /src/pl/plpython/sql/plpython_subtransaction.sql
parent438cdf6e4893311df4e94dc55b961a691908a530 (diff)
downloadpostgresql-22690719ea5a89ccbcd04deb58c83d8d5f138df8.tar.gz
PL/Python explicit subtransactions
Adds a context manager, obtainable by plpy.subtransaction(), to run a group of statements in a subtransaction. Jan UrbaƄski, reviewed by Steve Singer, additional scribbling by me
Diffstat (limited to 'src/pl/plpython/sql/plpython_subtransaction.sql')
-rw-r--r--src/pl/plpython/sql/plpython_subtransaction.sql244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/pl/plpython/sql/plpython_subtransaction.sql b/src/pl/plpython/sql/plpython_subtransaction.sql
new file mode 100644
index 0000000000..a19cad5104
--- /dev/null
+++ b/src/pl/plpython/sql/plpython_subtransaction.sql
@@ -0,0 +1,244 @@
+--
+-- Test explicit subtransactions
+--
+
+-- Test table to see if transactions get properly rolled back
+
+CREATE TABLE subtransaction_tbl (
+ i integer
+);
+
+-- Explicit case for Python <2.6
+
+CREATE FUNCTION subtransaction_test(what_error text = NULL) RETURNS text
+AS $$
+import sys
+subxact = plpy.subtransaction()
+subxact.__enter__()
+exc = True
+try:
+ try:
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES (2)")
+ if what_error == "SPI":
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')")
+ elif what_error == "Python":
+ plpy.attribute_error
+ except:
+ exc = False
+ subxact.__exit__(*sys.exc_info())
+ raise
+finally:
+ if exc:
+ subxact.__exit__(None, None, None)
+$$ LANGUAGE plpythonu;
+
+SELECT subtransaction_test();
+SELECT * FROM subtransaction_tbl;
+TRUNCATE subtransaction_tbl;
+SELECT subtransaction_test('SPI');
+SELECT * FROM subtransaction_tbl;
+TRUNCATE subtransaction_tbl;
+SELECT subtransaction_test('Python');
+SELECT * FROM subtransaction_tbl;
+TRUNCATE subtransaction_tbl;
+
+-- Context manager case for Python >=2.6
+
+CREATE FUNCTION subtransaction_ctx_test(what_error text = NULL) RETURNS text
+AS $$
+with plpy.subtransaction():
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES (2)")
+ if what_error == "SPI":
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')")
+ elif what_error == "Python":
+ plpy.attribute_error
+$$ LANGUAGE plpythonu;
+
+SELECT subtransaction_ctx_test();
+SELECT * FROM subtransaction_tbl;
+TRUNCATE subtransaction_tbl;
+SELECT subtransaction_ctx_test('SPI');
+SELECT * FROM subtransaction_tbl;
+TRUNCATE subtransaction_tbl;
+SELECT subtransaction_ctx_test('Python');
+SELECT * FROM subtransaction_tbl;
+TRUNCATE subtransaction_tbl;
+
+-- Nested subtransactions
+
+CREATE FUNCTION subtransaction_nested_test(swallow boolean = 'f') RETURNS text
+AS $$
+plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
+with plpy.subtransaction():
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES (2)")
+ try:
+ with plpy.subtransaction():
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES (3)")
+ plpy.execute("error")
+ except plpy.SPIError, e:
+ if not swallow:
+ raise
+ plpy.notice("Swallowed %r" % e)
+return "ok"
+$$ LANGUAGE plpythonu;
+
+SELECT subtransaction_nested_test();
+SELECT * FROM subtransaction_tbl;
+TRUNCATE subtransaction_tbl;
+
+SELECT subtransaction_nested_test('t');
+SELECT * FROM subtransaction_tbl;
+TRUNCATE subtransaction_tbl;
+
+-- Nested subtransactions that recursively call code dealing with
+-- subtransactions
+
+CREATE FUNCTION subtransaction_deeply_nested_test() RETURNS text
+AS $$
+plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
+with plpy.subtransaction():
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES (2)")
+ plpy.execute("SELECT subtransaction_nested_test('t')")
+return "ok"
+$$ LANGUAGE plpythonu;
+
+SELECT subtransaction_deeply_nested_test();
+SELECT * FROM subtransaction_tbl;
+TRUNCATE subtransaction_tbl;
+
+-- Error conditions from not opening/closing subtransactions
+
+CREATE FUNCTION subtransaction_exit_without_enter() RETURNS void
+AS $$
+plpy.subtransaction().__exit__(None, None, None)
+$$ LANGUAGE plpythonu;
+
+CREATE FUNCTION subtransaction_enter_without_exit() RETURNS void
+AS $$
+plpy.subtransaction().__enter__()
+$$ LANGUAGE plpythonu;
+
+CREATE FUNCTION subtransaction_exit_twice() RETURNS void
+AS $$
+plpy.subtransaction().__enter__()
+plpy.subtransaction().__exit__(None, None, None)
+plpy.subtransaction().__exit__(None, None, None)
+$$ LANGUAGE plpythonu;
+
+CREATE FUNCTION subtransaction_enter_twice() RETURNS void
+AS $$
+plpy.subtransaction().__enter__()
+plpy.subtransaction().__enter__()
+$$ LANGUAGE plpythonu;
+
+CREATE FUNCTION subtransaction_exit_same_subtransaction_twice() RETURNS void
+AS $$
+s = plpy.subtransaction()
+s.__enter__()
+s.__exit__(None, None, None)
+s.__exit__(None, None, None)
+$$ LANGUAGE plpythonu;
+
+CREATE FUNCTION subtransaction_enter_same_subtransaction_twice() RETURNS void
+AS $$
+s = plpy.subtransaction()
+s.__enter__()
+s.__enter__()
+s.__exit__(None, None, None)
+$$ LANGUAGE plpythonu;
+
+-- No warnings here, as the subtransaction gets indeed closed
+CREATE FUNCTION subtransaction_enter_subtransaction_in_with() RETURNS void
+AS $$
+with plpy.subtransaction() as s:
+ s.__enter__()
+$$ LANGUAGE plpythonu;
+
+CREATE FUNCTION subtransaction_exit_subtransaction_in_with() RETURNS void
+AS $$
+with plpy.subtransaction() as s:
+ s.__exit__(None, None, None)
+$$ LANGUAGE plpythonu;
+
+SELECT subtransaction_exit_without_enter();
+SELECT subtransaction_enter_without_exit();
+SELECT subtransaction_exit_twice();
+SELECT subtransaction_enter_twice();
+SELECT subtransaction_exit_same_subtransaction_twice();
+SELECT subtransaction_enter_same_subtransaction_twice();
+SELECT subtransaction_enter_subtransaction_in_with();
+SELECT subtransaction_exit_subtransaction_in_with();
+
+-- Make sure we don't get a "current transaction is aborted" error
+SELECT 1 as test;
+
+-- Mix explicit subtransactions and normal SPI calls
+
+CREATE FUNCTION subtransaction_mix_explicit_and_implicit() RETURNS void
+AS $$
+p = plpy.prepare("INSERT INTO subtransaction_tbl VALUES ($1)", ["integer"])
+try:
+ with plpy.subtransaction():
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
+ plpy.execute(p, [2])
+ plpy.execute(p, ["wrong"])
+except plpy.SPIError:
+ plpy.warning("Caught a SPI error from an explicit subtransaction")
+
+try:
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
+ plpy.execute(p, [2])
+ plpy.execute(p, ["wrong"])
+except plpy.SPIError:
+ plpy.warning("Caught a SPI error")
+$$ LANGUAGE plpythonu;
+
+SELECT subtransaction_mix_explicit_and_implicit();
+SELECT * FROM subtransaction_tbl;
+TRUNCATE subtransaction_tbl;
+
+-- Alternative method names for Python <2.6
+
+CREATE FUNCTION subtransaction_alternative_names() RETURNS void
+AS $$
+s = plpy.subtransaction()
+s.enter()
+s.exit(None, None, None)
+$$ LANGUAGE plpythonu;
+
+SELECT subtransaction_alternative_names();
+
+-- try/catch inside a subtransaction block
+
+CREATE FUNCTION try_catch_inside_subtransaction() RETURNS void
+AS $$
+with plpy.subtransaction():
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
+ try:
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES ('a')")
+ except plpy.SPIError:
+ plpy.notice("caught")
+$$ LANGUAGE plpythonu;
+
+SELECT try_catch_inside_subtransaction();
+SELECT * FROM subtransaction_tbl;
+TRUNCATE subtransaction_tbl;
+
+ALTER TABLE subtransaction_tbl ADD PRIMARY KEY (i);
+
+CREATE FUNCTION pk_violation_inside_subtransaction() RETURNS void
+AS $$
+with plpy.subtransaction():
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
+ try:
+ plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
+ except plpy.SPIError:
+ plpy.notice("caught")
+$$ LANGUAGE plpythonu;
+
+SELECT pk_violation_inside_subtransaction();
+SELECT * FROM subtransaction_tbl;
+
+DROP TABLE subtransaction_tbl;