Remove support for Python older than 2.6

Supporting very old Python versions is a maintenance burden,
especially with the several variant test files to maintain for Python
<2.6.

Since we have dropped support for older OpenSSL versions in
7b283d0e1d, RHEL 5 is now effectively
desupported, and that was also the only mainstream operating system
still using Python versions before 2.6, so it's a good time to drop
those as well.

Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/98b69261-298c-13d2-f34d-836fd9c29b21%402ndquadrant.com
This commit is contained in:
Peter Eisentraut 2020-01-08 21:48:44 +01:00
parent f5d28710c7
commit 37f21ed132
12 changed files with 7 additions and 1503 deletions

View File

@ -37,8 +37,8 @@ python_majorversion=`echo "$python_fullversion" | sed '[s/^\([0-9]*\).*/\1/]'`
python_minorversion=`echo "$python_fullversion" | sed '[s/^[0-9]*\.\([0-9]*\).*/\1/]'`
python_version=`echo "$python_fullversion" | sed '[s/^\([0-9]*\.[0-9]*\).*/\1/]'`
# Reject unsupported Python versions as soon as practical.
if test "$python_majorversion" -lt 3 -a "$python_minorversion" -lt 4; then
AC_MSG_ERROR([Python version $python_version is too old (version 2.4 or later is required)])
if test "$python_majorversion" -lt 3 -a "$python_minorversion" -lt 6; then
AC_MSG_ERROR([Python version $python_version is too old (version 2.6 or later is required)])
fi
AC_MSG_CHECKING([for Python distutils module])

4
configure vendored
View File

@ -9616,8 +9616,8 @@ python_majorversion=`echo "$python_fullversion" | sed 's/^\([0-9]*\).*/\1/'`
python_minorversion=`echo "$python_fullversion" | sed 's/^[0-9]*\.\([0-9]*\).*/\1/'`
python_version=`echo "$python_fullversion" | sed 's/^\([0-9]*\.[0-9]*\).*/\1/'`
# Reject unsupported Python versions as soon as practical.
if test "$python_majorversion" -lt 3 -a "$python_minorversion" -lt 4; then
as_fn_error $? "Python version $python_version is too old (version 2.4 or later is required)" "$LINENO" 5
if test "$python_majorversion" -lt 3 -a "$python_minorversion" -lt 6; then
as_fn_error $? "Python version $python_version is too old (version 2.6 or later is required)" "$LINENO" 5
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Python distutils module" >&5

View File

@ -196,7 +196,7 @@ su - postgres
language, you need a <productname>Python</productname>
installation with the header files and
the <application>distutils</application> module. The minimum
required version is <productname>Python</productname> 2.4.
required version is <productname>Python</productname> 2.6.
<productname>Python 3</productname> is supported if it's
version 3.1 or later; but see
<xref linkend="plpython-python23"/>

View File

@ -1335,9 +1335,8 @@ $$ LANGUAGE plpythonu;
<para>
Context managers syntax using the <literal>with</literal> keyword
is available by default in Python 2.6. If using PL/Python with an
older Python version, it is still possible to use explicit
subtransactions, although not as transparently. You can call the
is available by default in Python 2.6. For compatibility with
older Python versions, you can call the
subtransaction manager's <literal>__enter__</literal> and
<literal>__exit__</literal> functions using the
<literal>enter</literal> and <literal>exit</literal> convenience
@ -1367,17 +1366,6 @@ plpy.execute(plan, [result])
$$ LANGUAGE plpythonu;
</programlisting>
</para>
<note>
<para>
Although context managers were implemented in Python 2.5, to use
the <literal>with</literal> syntax in that version you need to
use a <ulink
url="https://docs.python.org/release/2.5/ref/future.html">future
statement</ulink>. Because of implementation details, however,
you cannot use future statements in PL/Python functions.
</para>
</note>
</sect2>
</sect1>

View File

@ -1,12 +1,8 @@
Guide to alternative expected files:
plpython_error_0.out Python 2.4 and older
plpython_error_5.out Python 3.5 and newer
plpython_unicode.out server encoding != SQL_ASCII
plpython_unicode_3.out server encoding == SQL_ASCII
plpython_subtransaction_0.out Python 2.4 and older (without with statement)
plpython_subtransaction_5.out Python 2.5 (without with statement)
plpython_types_3.out Python 3.x

View File

@ -1,447 +0,0 @@
-- test error handling, i forgot to restore Warn_restart in
-- the trigger handler once. the errors and subsequent core dump were
-- interesting.
/* Flat out Python syntax error
*/
CREATE FUNCTION python_syntax_error() RETURNS text
AS
'.syntaxerror'
LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "python_syntax_error"
DETAIL: SyntaxError: invalid syntax (line 2)
/* With check_function_bodies = false the function should get defined
* and the error reported when called
*/
SET check_function_bodies = false;
CREATE FUNCTION python_syntax_error() RETURNS text
AS
'.syntaxerror'
LANGUAGE plpythonu;
SELECT python_syntax_error();
ERROR: could not compile PL/Python function "python_syntax_error"
DETAIL: SyntaxError: invalid syntax (line 2)
/* Run the function twice to check if the hashtable entry gets cleaned up */
SELECT python_syntax_error();
ERROR: could not compile PL/Python function "python_syntax_error"
DETAIL: SyntaxError: invalid syntax (line 2)
RESET check_function_bodies;
/* Flat out syntax error
*/
CREATE FUNCTION sql_syntax_error() RETURNS text
AS
'plpy.execute("syntax error")'
LANGUAGE plpythonu;
SELECT sql_syntax_error();
ERROR: spiexceptions.SyntaxError: syntax error at or near "syntax"
LINE 1: syntax error
^
QUERY: syntax error
CONTEXT: Traceback (most recent call last):
PL/Python function "sql_syntax_error", line 1, in <module>
plpy.execute("syntax error")
PL/Python function "sql_syntax_error"
/* check the handling of uncaught python exceptions
*/
CREATE FUNCTION exception_index_invalid(text) RETURNS text
AS
'return args[1]'
LANGUAGE plpythonu;
SELECT exception_index_invalid('test');
ERROR: IndexError: list index out of range
CONTEXT: Traceback (most recent call last):
PL/Python function "exception_index_invalid", line 1, in <module>
return args[1]
PL/Python function "exception_index_invalid"
/* check handling of nested exceptions
*/
CREATE FUNCTION exception_index_invalid_nested() RETURNS text
AS
'rv = plpy.execute("SELECT test5(''foo'')")
return rv[0]'
LANGUAGE plpythonu;
SELECT exception_index_invalid_nested();
ERROR: spiexceptions.UndefinedFunction: function test5(unknown) does not exist
LINE 1: SELECT test5('foo')
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
QUERY: SELECT test5('foo')
CONTEXT: Traceback (most recent call last):
PL/Python function "exception_index_invalid_nested", line 1, in <module>
rv = plpy.execute("SELECT test5('foo')")
PL/Python function "exception_index_invalid_nested"
/* a typo
*/
CREATE FUNCTION invalid_type_uncaught(a text) RETURNS text
AS
'if "plan" not in SD:
q = "SELECT fname FROM users WHERE lname = $1"
SD["plan"] = plpy.prepare(q, [ "test" ])
rv = plpy.execute(SD["plan"], [ a ])
if len(rv):
return rv[0]["fname"]
return None
'
LANGUAGE plpythonu;
SELECT invalid_type_uncaught('rick');
ERROR: spiexceptions.UndefinedObject: type "test" does not exist
CONTEXT: Traceback (most recent call last):
PL/Python function "invalid_type_uncaught", line 3, in <module>
SD["plan"] = plpy.prepare(q, [ "test" ])
PL/Python function "invalid_type_uncaught"
/* for what it's worth catch the exception generated by
* the typo, and return None
*/
CREATE FUNCTION invalid_type_caught(a text) RETURNS text
AS
'if "plan" not in SD:
q = "SELECT fname FROM users WHERE lname = $1"
try:
SD["plan"] = plpy.prepare(q, [ "test" ])
except plpy.SPIError, ex:
plpy.notice(str(ex))
return None
rv = plpy.execute(SD["plan"], [ a ])
if len(rv):
return rv[0]["fname"]
return None
'
LANGUAGE plpythonu;
SELECT invalid_type_caught('rick');
NOTICE: type "test" does not exist
invalid_type_caught
---------------------
(1 row)
/* for what it's worth catch the exception generated by
* the typo, and reraise it as a plain error
*/
CREATE FUNCTION invalid_type_reraised(a text) RETURNS text
AS
'if "plan" not in SD:
q = "SELECT fname FROM users WHERE lname = $1"
try:
SD["plan"] = plpy.prepare(q, [ "test" ])
except plpy.SPIError, ex:
plpy.error(str(ex))
rv = plpy.execute(SD["plan"], [ a ])
if len(rv):
return rv[0]["fname"]
return None
'
LANGUAGE plpythonu;
SELECT invalid_type_reraised('rick');
ERROR: plpy.Error: type "test" does not exist
CONTEXT: Traceback (most recent call last):
PL/Python function "invalid_type_reraised", line 6, in <module>
plpy.error(str(ex))
PL/Python function "invalid_type_reraised"
/* no typo no messing about
*/
CREATE FUNCTION valid_type(a text) RETURNS text
AS
'if "plan" not in SD:
SD["plan"] = plpy.prepare("SELECT fname FROM users WHERE lname = $1", [ "text" ])
rv = plpy.execute(SD["plan"], [ a ])
if len(rv):
return rv[0]["fname"]
return None
'
LANGUAGE plpythonu;
SELECT valid_type('rick');
valid_type
------------
(1 row)
/* error in nested functions to get a traceback
*/
CREATE FUNCTION nested_error() RETURNS text
AS
'def fun1():
plpy.error("boom")
def fun2():
fun1()
def fun3():
fun2()
fun3()
return "not reached"
'
LANGUAGE plpythonu;
SELECT nested_error();
ERROR: plpy.Error: boom
CONTEXT: Traceback (most recent call last):
PL/Python function "nested_error", line 10, in <module>
fun3()
PL/Python function "nested_error", line 8, in fun3
fun2()
PL/Python function "nested_error", line 5, in fun2
fun1()
PL/Python function "nested_error", line 2, in fun1
plpy.error("boom")
PL/Python function "nested_error"
/* raising plpy.Error is just like calling plpy.error
*/
CREATE FUNCTION nested_error_raise() RETURNS text
AS
'def fun1():
raise plpy.Error("boom")
def fun2():
fun1()
def fun3():
fun2()
fun3()
return "not reached"
'
LANGUAGE plpythonu;
SELECT nested_error_raise();
ERROR: plpy.Error: boom
CONTEXT: Traceback (most recent call last):
PL/Python function "nested_error_raise", line 10, in <module>
fun3()
PL/Python function "nested_error_raise", line 8, in fun3
fun2()
PL/Python function "nested_error_raise", line 5, in fun2
fun1()
PL/Python function "nested_error_raise", line 2, in fun1
raise plpy.Error("boom")
PL/Python function "nested_error_raise"
/* using plpy.warning should not produce a traceback
*/
CREATE FUNCTION nested_warning() RETURNS text
AS
'def fun1():
plpy.warning("boom")
def fun2():
fun1()
def fun3():
fun2()
fun3()
return "you''ve been warned"
'
LANGUAGE plpythonu;
SELECT nested_warning();
WARNING: boom
nested_warning
--------------------
you've been warned
(1 row)
/* AttributeError at toplevel used to give segfaults with the traceback
*/
CREATE FUNCTION toplevel_attribute_error() RETURNS void AS
$$
plpy.nonexistent
$$ LANGUAGE plpythonu;
SELECT toplevel_attribute_error();
ERROR: AttributeError: 'module' object has no attribute 'nonexistent'
CONTEXT: Traceback (most recent call last):
PL/Python function "toplevel_attribute_error", line 2, in <module>
plpy.nonexistent
PL/Python function "toplevel_attribute_error"
/* Calling PL/Python functions from SQL and vice versa should not lose context.
*/
CREATE OR REPLACE FUNCTION python_traceback() RETURNS void AS $$
def first():
second()
def second():
third()
def third():
plpy.execute("select sql_error()")
first()
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION sql_error() RETURNS void AS $$
begin
select 1/0;
end
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION python_from_sql_error() RETURNS void AS $$
begin
select python_traceback();
end
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION sql_from_python_error() RETURNS void AS $$
plpy.execute("select sql_error()")
$$ LANGUAGE plpythonu;
SELECT python_traceback();
ERROR: spiexceptions.DivisionByZero: division by zero
CONTEXT: Traceback (most recent call last):
PL/Python function "python_traceback", line 11, in <module>
first()
PL/Python function "python_traceback", line 3, in first
second()
PL/Python function "python_traceback", line 6, in second
third()
PL/Python function "python_traceback", line 9, in third
plpy.execute("select sql_error()")
PL/Python function "python_traceback"
SELECT sql_error();
ERROR: division by zero
CONTEXT: SQL statement "select 1/0"
PL/pgSQL function sql_error() line 3 at SQL statement
SELECT python_from_sql_error();
ERROR: spiexceptions.DivisionByZero: division by zero
CONTEXT: Traceback (most recent call last):
PL/Python function "python_traceback", line 11, in <module>
first()
PL/Python function "python_traceback", line 3, in first
second()
PL/Python function "python_traceback", line 6, in second
third()
PL/Python function "python_traceback", line 9, in third
plpy.execute("select sql_error()")
PL/Python function "python_traceback"
SQL statement "select python_traceback()"
PL/pgSQL function python_from_sql_error() line 3 at SQL statement
SELECT sql_from_python_error();
ERROR: spiexceptions.DivisionByZero: division by zero
CONTEXT: Traceback (most recent call last):
PL/Python function "sql_from_python_error", line 2, in <module>
plpy.execute("select sql_error()")
PL/Python function "sql_from_python_error"
/* check catching specific types of exceptions
*/
CREATE TABLE specific (
i integer PRIMARY KEY
);
CREATE FUNCTION specific_exception(i integer) RETURNS void AS
$$
from plpy import spiexceptions
try:
plpy.execute("insert into specific values (%s)" % (i or "NULL"));
except spiexceptions.NotNullViolation, e:
plpy.notice("Violated the NOT NULL constraint, sqlstate %s" % e.sqlstate)
except spiexceptions.UniqueViolation, e:
plpy.notice("Violated the UNIQUE constraint, sqlstate %s" % e.sqlstate)
$$ LANGUAGE plpythonu;
SELECT specific_exception(2);
specific_exception
--------------------
(1 row)
SELECT specific_exception(NULL);
NOTICE: Violated the NOT NULL constraint, sqlstate 23502
specific_exception
--------------------
(1 row)
SELECT specific_exception(2);
NOTICE: Violated the UNIQUE constraint, sqlstate 23505
specific_exception
--------------------
(1 row)
/* SPI errors in PL/Python functions should preserve the SQLSTATE value
*/
CREATE FUNCTION python_unique_violation() RETURNS void AS $$
plpy.execute("insert into specific values (1)")
plpy.execute("insert into specific values (1)")
$$ LANGUAGE plpythonu;
CREATE FUNCTION catch_python_unique_violation() RETURNS text AS $$
begin
begin
perform python_unique_violation();
exception when unique_violation then
return 'ok';
end;
return 'not reached';
end;
$$ language plpgsql;
SELECT catch_python_unique_violation();
catch_python_unique_violation
-------------------------------
ok
(1 row)
/* manually starting subtransactions - a bad idea
*/
CREATE FUNCTION manual_subxact() RETURNS void AS $$
plpy.execute("savepoint save")
plpy.execute("create table foo(x integer)")
plpy.execute("rollback to save")
$$ LANGUAGE plpythonu;
SELECT manual_subxact();
ERROR: plpy.SPIError: SPI_execute failed: SPI_ERROR_TRANSACTION
CONTEXT: Traceback (most recent call last):
PL/Python function "manual_subxact", line 2, in <module>
plpy.execute("savepoint save")
PL/Python function "manual_subxact"
/* same for prepared plans
*/
CREATE FUNCTION manual_subxact_prepared() RETURNS void AS $$
save = plpy.prepare("savepoint save")
rollback = plpy.prepare("rollback to save")
plpy.execute(save)
plpy.execute("create table foo(x integer)")
plpy.execute(rollback)
$$ LANGUAGE plpythonu;
SELECT manual_subxact_prepared();
ERROR: plpy.SPIError: SPI_execute_plan failed: SPI_ERROR_TRANSACTION
CONTEXT: Traceback (most recent call last):
PL/Python function "manual_subxact_prepared", line 4, in <module>
plpy.execute(save)
PL/Python function "manual_subxact_prepared"
/* raising plpy.spiexception.* from python code should preserve sqlstate
*/
CREATE FUNCTION plpy_raise_spiexception() RETURNS void AS $$
raise plpy.spiexceptions.DivisionByZero()
$$ LANGUAGE plpythonu;
DO $$
BEGIN
SELECT plpy_raise_spiexception();
EXCEPTION WHEN division_by_zero THEN
-- NOOP
END
$$ LANGUAGE plpgsql;
/* setting a custom sqlstate should be handled
*/
CREATE FUNCTION plpy_raise_spiexception_override() RETURNS void AS $$
exc = plpy.spiexceptions.DivisionByZero()
exc.sqlstate = 'SILLY'
raise exc
$$ LANGUAGE plpythonu;
DO $$
BEGIN
SELECT plpy_raise_spiexception_override();
EXCEPTION WHEN SQLSTATE 'SILLY' THEN
-- NOOP
END
$$ LANGUAGE plpgsql;
/* test the context stack trace for nested execution levels
*/
CREATE FUNCTION notice_innerfunc() RETURNS int AS $$
plpy.execute("DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$")
return 1
$$ LANGUAGE plpythonu;
CREATE FUNCTION notice_outerfunc() RETURNS int AS $$
plpy.execute("SELECT notice_innerfunc()")
return 1
$$ LANGUAGE plpythonu;
\set SHOW_CONTEXT always
SELECT notice_outerfunc();
NOTICE: inside DO
CONTEXT: PL/Python anonymous code block
SQL statement "DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$"
PL/Python function "notice_innerfunc"
SQL statement "SELECT notice_innerfunc()"
PL/Python function "notice_outerfunc"
notice_outerfunc
------------------
1
(1 row)

View File

@ -5,71 +5,6 @@
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":
raise Exception("Python exception")
except:
exc = False
subxact.__exit__(*sys.exc_info())
raise
finally:
if exc:
subxact.__exit__(None, None, None)
$$ LANGUAGE plpythonu;
SELECT subtransaction_test();
subtransaction_test
---------------------
(1 row)
SELECT * FROM subtransaction_tbl;
i
---
1
2
(2 rows)
TRUNCATE subtransaction_tbl;
SELECT subtransaction_test('SPI');
ERROR: spiexceptions.InvalidTextRepresentation: invalid input syntax for type integer: "oops"
LINE 1: INSERT INTO subtransaction_tbl VALUES ('oops')
^
QUERY: INSERT INTO subtransaction_tbl VALUES ('oops')
CONTEXT: Traceback (most recent call last):
PL/Python function "subtransaction_test", line 11, in <module>
plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')")
PL/Python function "subtransaction_test"
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
TRUNCATE subtransaction_tbl;
SELECT subtransaction_test('Python');
ERROR: Exception: Python exception
CONTEXT: Traceback (most recent call last):
PL/Python function "subtransaction_test", line 13, in <module>
raise Exception("Python exception")
PL/Python function "subtransaction_test"
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
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():

View File

@ -1,448 +0,0 @@
--
-- 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":
raise Exception("Python exception")
except:
exc = False
subxact.__exit__(*sys.exc_info())
raise
finally:
if exc:
subxact.__exit__(None, None, None)
$$ LANGUAGE plpythonu;
SELECT subtransaction_test();
subtransaction_test
---------------------
(1 row)
SELECT * FROM subtransaction_tbl;
i
---
1
2
(2 rows)
TRUNCATE subtransaction_tbl;
SELECT subtransaction_test('SPI');
ERROR: spiexceptions.InvalidTextRepresentation: invalid input syntax for type integer: "oops"
LINE 1: INSERT INTO subtransaction_tbl VALUES ('oops')
^
QUERY: INSERT INTO subtransaction_tbl VALUES ('oops')
CONTEXT: Traceback (most recent call last):
PL/Python function "subtransaction_test", line 11, in <module>
plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')")
PL/Python function "subtransaction_test"
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
TRUNCATE subtransaction_tbl;
SELECT subtransaction_test('Python');
ERROR: Exception: Python exception
CONTEXT: Traceback (most recent call last):
PL/Python function "subtransaction_test", line 13, in <module>
raise Exception("Python exception")
PL/Python function "subtransaction_test"
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
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":
raise Exception("Python exception")
$$ LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "subtransaction_ctx_test"
DETAIL: SyntaxError: invalid syntax (line 3)
SELECT subtransaction_ctx_test();
ERROR: function subtransaction_ctx_test() does not exist
LINE 1: SELECT subtransaction_ctx_test();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
TRUNCATE subtransaction_tbl;
SELECT subtransaction_ctx_test('SPI');
ERROR: function subtransaction_ctx_test(unknown) does not exist
LINE 1: SELECT subtransaction_ctx_test('SPI');
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
TRUNCATE subtransaction_tbl;
SELECT subtransaction_ctx_test('Python');
ERROR: function subtransaction_ctx_test(unknown) does not exist
LINE 1: SELECT subtransaction_ctx_test('Python');
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
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 %s(%r)" % (e.__class__.__name__, e.args[0]))
return "ok"
$$ LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "subtransaction_nested_test"
DETAIL: SyntaxError: invalid syntax (line 4)
SELECT subtransaction_nested_test();
ERROR: function subtransaction_nested_test() does not exist
LINE 1: SELECT subtransaction_nested_test();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
TRUNCATE subtransaction_tbl;
SELECT subtransaction_nested_test('t');
ERROR: function subtransaction_nested_test(unknown) does not exist
LINE 1: SELECT subtransaction_nested_test('t');
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
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;
ERROR: could not compile PL/Python function "subtransaction_deeply_nested_test"
DETAIL: SyntaxError: invalid syntax (line 4)
SELECT subtransaction_deeply_nested_test();
ERROR: function subtransaction_deeply_nested_test() does not exist
LINE 1: SELECT subtransaction_deeply_nested_test();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
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;
ERROR: could not compile PL/Python function "subtransaction_enter_subtransaction_in_with"
DETAIL: SyntaxError: invalid syntax (line 3)
CREATE FUNCTION subtransaction_exit_subtransaction_in_with() RETURNS void
AS $$
with plpy.subtransaction() as s:
s.__exit__(None, None, None)
$$ LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "subtransaction_exit_subtransaction_in_with"
DETAIL: SyntaxError: invalid syntax (line 3)
SELECT subtransaction_exit_without_enter();
ERROR: ValueError: this subtransaction has not been entered
CONTEXT: Traceback (most recent call last):
PL/Python function "subtransaction_exit_without_enter", line 2, in <module>
plpy.subtransaction().__exit__(None, None, None)
PL/Python function "subtransaction_exit_without_enter"
SELECT subtransaction_enter_without_exit();
WARNING: forcibly aborting a subtransaction that has not been exited
subtransaction_enter_without_exit
-----------------------------------
(1 row)
SELECT subtransaction_exit_twice();
WARNING: forcibly aborting a subtransaction that has not been exited
ERROR: ValueError: this subtransaction has not been entered
CONTEXT: Traceback (most recent call last):
PL/Python function "subtransaction_exit_twice", line 3, in <module>
plpy.subtransaction().__exit__(None, None, None)
PL/Python function "subtransaction_exit_twice"
SELECT subtransaction_enter_twice();
WARNING: forcibly aborting a subtransaction that has not been exited
WARNING: forcibly aborting a subtransaction that has not been exited
subtransaction_enter_twice
----------------------------
(1 row)
SELECT subtransaction_exit_same_subtransaction_twice();
ERROR: ValueError: this subtransaction has already been exited
CONTEXT: Traceback (most recent call last):
PL/Python function "subtransaction_exit_same_subtransaction_twice", line 5, in <module>
s.__exit__(None, None, None)
PL/Python function "subtransaction_exit_same_subtransaction_twice"
SELECT subtransaction_enter_same_subtransaction_twice();
WARNING: forcibly aborting a subtransaction that has not been exited
ERROR: ValueError: this subtransaction has already been entered
CONTEXT: Traceback (most recent call last):
PL/Python function "subtransaction_enter_same_subtransaction_twice", line 4, in <module>
s.__enter__()
PL/Python function "subtransaction_enter_same_subtransaction_twice"
SELECT subtransaction_enter_subtransaction_in_with();
ERROR: function subtransaction_enter_subtransaction_in_with() does not exist
LINE 1: SELECT subtransaction_enter_subtransaction_in_with();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT subtransaction_exit_subtransaction_in_with();
ERROR: function subtransaction_exit_subtransaction_in_with() does not exist
LINE 1: SELECT subtransaction_exit_subtransaction_in_with();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- Make sure we don't get a "current transaction is aborted" error
SELECT 1 as test;
test
------
1
(1 row)
-- 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;
ERROR: could not compile PL/Python function "subtransaction_mix_explicit_and_implicit"
DETAIL: SyntaxError: invalid syntax (line 5)
SELECT subtransaction_mix_explicit_and_implicit();
ERROR: function subtransaction_mix_explicit_and_implicit() does not exist
LINE 1: SELECT subtransaction_mix_explicit_and_implicit();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
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();
subtransaction_alternative_names
----------------------------------
(1 row)
-- 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;
ERROR: could not compile PL/Python function "try_catch_inside_subtransaction"
DETAIL: SyntaxError: invalid syntax (line 3)
SELECT try_catch_inside_subtransaction();
ERROR: function try_catch_inside_subtransaction() does not exist
LINE 1: SELECT try_catch_inside_subtransaction();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
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;
ERROR: could not compile PL/Python function "pk_violation_inside_subtransaction"
DETAIL: SyntaxError: invalid syntax (line 3)
SELECT pk_violation_inside_subtransaction();
ERROR: function pk_violation_inside_subtransaction() does not exist
LINE 1: SELECT pk_violation_inside_subtransaction();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
DROP TABLE subtransaction_tbl;
-- cursor/subtransactions interactions
CREATE FUNCTION cursor_in_subxact() RETURNS int AS $$
with plpy.subtransaction():
cur = plpy.cursor("select * from generate_series(1, 20) as gen(i)")
cur.fetch(10)
fetched = cur.fetch(10);
return int(fetched[5]["i"])
$$ LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "cursor_in_subxact"
DETAIL: SyntaxError: invalid syntax (line 3)
CREATE FUNCTION cursor_aborted_subxact() RETURNS int AS $$
try:
with plpy.subtransaction():
cur = plpy.cursor("select * from generate_series(1, 20) as gen(i)")
cur.fetch(10);
plpy.execute("select no_such_function()")
except plpy.SPIError:
fetched = cur.fetch(10)
return int(fetched[5]["i"])
return 0 # not reached
$$ LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "cursor_aborted_subxact"
DETAIL: SyntaxError: invalid syntax (line 4)
CREATE FUNCTION cursor_plan_aborted_subxact() RETURNS int AS $$
try:
with plpy.subtransaction():
plpy.execute('create temporary table tmp(i) '
'as select generate_series(1, 10)')
plan = plpy.prepare("select i from tmp")
cur = plpy.cursor(plan)
plpy.execute("select no_such_function()")
except plpy.SPIError:
fetched = cur.fetch(5)
return fetched[2]["i"]
return 0 # not reached
$$ LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "cursor_plan_aborted_subxact"
DETAIL: SyntaxError: invalid syntax (line 4)
CREATE FUNCTION cursor_close_aborted_subxact() RETURNS boolean AS $$
try:
with plpy.subtransaction():
cur = plpy.cursor('select 1')
plpy.execute("select no_such_function()")
except plpy.SPIError:
cur.close()
return True
return False # not reached
$$ LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "cursor_close_aborted_subxact"
DETAIL: SyntaxError: invalid syntax (line 4)
SELECT cursor_in_subxact();
ERROR: function cursor_in_subxact() does not exist
LINE 1: SELECT cursor_in_subxact();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT cursor_aborted_subxact();
ERROR: function cursor_aborted_subxact() does not exist
LINE 1: SELECT cursor_aborted_subxact();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT cursor_plan_aborted_subxact();
ERROR: function cursor_plan_aborted_subxact() does not exist
LINE 1: SELECT cursor_plan_aborted_subxact();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT cursor_close_aborted_subxact();
ERROR: function cursor_close_aborted_subxact() does not exist
LINE 1: SELECT cursor_close_aborted_subxact();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.

View File

@ -1,448 +0,0 @@
--
-- 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":
raise Exception("Python exception")
except:
exc = False
subxact.__exit__(*sys.exc_info())
raise
finally:
if exc:
subxact.__exit__(None, None, None)
$$ LANGUAGE plpythonu;
SELECT subtransaction_test();
subtransaction_test
---------------------
(1 row)
SELECT * FROM subtransaction_tbl;
i
---
1
2
(2 rows)
TRUNCATE subtransaction_tbl;
SELECT subtransaction_test('SPI');
ERROR: spiexceptions.InvalidTextRepresentation: invalid input syntax for type integer: "oops"
LINE 1: INSERT INTO subtransaction_tbl VALUES ('oops')
^
QUERY: INSERT INTO subtransaction_tbl VALUES ('oops')
CONTEXT: Traceback (most recent call last):
PL/Python function "subtransaction_test", line 11, in <module>
plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')")
PL/Python function "subtransaction_test"
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
TRUNCATE subtransaction_tbl;
SELECT subtransaction_test('Python');
ERROR: Exception: Python exception
CONTEXT: Traceback (most recent call last):
PL/Python function "subtransaction_test", line 13, in <module>
raise Exception("Python exception")
PL/Python function "subtransaction_test"
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
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":
raise Exception("Python exception")
$$ LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "subtransaction_ctx_test"
DETAIL: SyntaxError: invalid syntax (<string>, line 3)
SELECT subtransaction_ctx_test();
ERROR: function subtransaction_ctx_test() does not exist
LINE 1: SELECT subtransaction_ctx_test();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
TRUNCATE subtransaction_tbl;
SELECT subtransaction_ctx_test('SPI');
ERROR: function subtransaction_ctx_test(unknown) does not exist
LINE 1: SELECT subtransaction_ctx_test('SPI');
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
TRUNCATE subtransaction_tbl;
SELECT subtransaction_ctx_test('Python');
ERROR: function subtransaction_ctx_test(unknown) does not exist
LINE 1: SELECT subtransaction_ctx_test('Python');
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
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 %s(%r)" % (e.__class__.__name__, e.args[0]))
return "ok"
$$ LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "subtransaction_nested_test"
DETAIL: SyntaxError: invalid syntax (<string>, line 4)
SELECT subtransaction_nested_test();
ERROR: function subtransaction_nested_test() does not exist
LINE 1: SELECT subtransaction_nested_test();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
TRUNCATE subtransaction_tbl;
SELECT subtransaction_nested_test('t');
ERROR: function subtransaction_nested_test(unknown) does not exist
LINE 1: SELECT subtransaction_nested_test('t');
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
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;
ERROR: could not compile PL/Python function "subtransaction_deeply_nested_test"
DETAIL: SyntaxError: invalid syntax (<string>, line 4)
SELECT subtransaction_deeply_nested_test();
ERROR: function subtransaction_deeply_nested_test() does not exist
LINE 1: SELECT subtransaction_deeply_nested_test();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
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;
ERROR: could not compile PL/Python function "subtransaction_enter_subtransaction_in_with"
DETAIL: SyntaxError: invalid syntax (<string>, line 3)
CREATE FUNCTION subtransaction_exit_subtransaction_in_with() RETURNS void
AS $$
with plpy.subtransaction() as s:
s.__exit__(None, None, None)
$$ LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "subtransaction_exit_subtransaction_in_with"
DETAIL: SyntaxError: invalid syntax (<string>, line 3)
SELECT subtransaction_exit_without_enter();
ERROR: ValueError: this subtransaction has not been entered
CONTEXT: Traceback (most recent call last):
PL/Python function "subtransaction_exit_without_enter", line 2, in <module>
plpy.subtransaction().__exit__(None, None, None)
PL/Python function "subtransaction_exit_without_enter"
SELECT subtransaction_enter_without_exit();
WARNING: forcibly aborting a subtransaction that has not been exited
subtransaction_enter_without_exit
-----------------------------------
(1 row)
SELECT subtransaction_exit_twice();
WARNING: forcibly aborting a subtransaction that has not been exited
ERROR: ValueError: this subtransaction has not been entered
CONTEXT: Traceback (most recent call last):
PL/Python function "subtransaction_exit_twice", line 3, in <module>
plpy.subtransaction().__exit__(None, None, None)
PL/Python function "subtransaction_exit_twice"
SELECT subtransaction_enter_twice();
WARNING: forcibly aborting a subtransaction that has not been exited
WARNING: forcibly aborting a subtransaction that has not been exited
subtransaction_enter_twice
----------------------------
(1 row)
SELECT subtransaction_exit_same_subtransaction_twice();
ERROR: ValueError: this subtransaction has already been exited
CONTEXT: Traceback (most recent call last):
PL/Python function "subtransaction_exit_same_subtransaction_twice", line 5, in <module>
s.__exit__(None, None, None)
PL/Python function "subtransaction_exit_same_subtransaction_twice"
SELECT subtransaction_enter_same_subtransaction_twice();
WARNING: forcibly aborting a subtransaction that has not been exited
ERROR: ValueError: this subtransaction has already been entered
CONTEXT: Traceback (most recent call last):
PL/Python function "subtransaction_enter_same_subtransaction_twice", line 4, in <module>
s.__enter__()
PL/Python function "subtransaction_enter_same_subtransaction_twice"
SELECT subtransaction_enter_subtransaction_in_with();
ERROR: function subtransaction_enter_subtransaction_in_with() does not exist
LINE 1: SELECT subtransaction_enter_subtransaction_in_with();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT subtransaction_exit_subtransaction_in_with();
ERROR: function subtransaction_exit_subtransaction_in_with() does not exist
LINE 1: SELECT subtransaction_exit_subtransaction_in_with();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- Make sure we don't get a "current transaction is aborted" error
SELECT 1 as test;
test
------
1
(1 row)
-- 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;
ERROR: could not compile PL/Python function "subtransaction_mix_explicit_and_implicit"
DETAIL: SyntaxError: invalid syntax (<string>, line 5)
SELECT subtransaction_mix_explicit_and_implicit();
ERROR: function subtransaction_mix_explicit_and_implicit() does not exist
LINE 1: SELECT subtransaction_mix_explicit_and_implicit();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
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();
subtransaction_alternative_names
----------------------------------
(1 row)
-- 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;
ERROR: could not compile PL/Python function "try_catch_inside_subtransaction"
DETAIL: SyntaxError: invalid syntax (<string>, line 3)
SELECT try_catch_inside_subtransaction();
ERROR: function try_catch_inside_subtransaction() does not exist
LINE 1: SELECT try_catch_inside_subtransaction();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
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;
ERROR: could not compile PL/Python function "pk_violation_inside_subtransaction"
DETAIL: SyntaxError: invalid syntax (<string>, line 3)
SELECT pk_violation_inside_subtransaction();
ERROR: function pk_violation_inside_subtransaction() does not exist
LINE 1: SELECT pk_violation_inside_subtransaction();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM subtransaction_tbl;
i
---
(0 rows)
DROP TABLE subtransaction_tbl;
-- cursor/subtransactions interactions
CREATE FUNCTION cursor_in_subxact() RETURNS int AS $$
with plpy.subtransaction():
cur = plpy.cursor("select * from generate_series(1, 20) as gen(i)")
cur.fetch(10)
fetched = cur.fetch(10);
return int(fetched[5]["i"])
$$ LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "cursor_in_subxact"
DETAIL: SyntaxError: invalid syntax (<string>, line 3)
CREATE FUNCTION cursor_aborted_subxact() RETURNS int AS $$
try:
with plpy.subtransaction():
cur = plpy.cursor("select * from generate_series(1, 20) as gen(i)")
cur.fetch(10);
plpy.execute("select no_such_function()")
except plpy.SPIError:
fetched = cur.fetch(10)
return int(fetched[5]["i"])
return 0 # not reached
$$ LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "cursor_aborted_subxact"
DETAIL: SyntaxError: invalid syntax (<string>, line 4)
CREATE FUNCTION cursor_plan_aborted_subxact() RETURNS int AS $$
try:
with plpy.subtransaction():
plpy.execute('create temporary table tmp(i) '
'as select generate_series(1, 10)')
plan = plpy.prepare("select i from tmp")
cur = plpy.cursor(plan)
plpy.execute("select no_such_function()")
except plpy.SPIError:
fetched = cur.fetch(5)
return fetched[2]["i"]
return 0 # not reached
$$ LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "cursor_plan_aborted_subxact"
DETAIL: SyntaxError: invalid syntax (<string>, line 4)
CREATE FUNCTION cursor_close_aborted_subxact() RETURNS boolean AS $$
try:
with plpy.subtransaction():
cur = plpy.cursor('select 1')
plpy.execute("select no_such_function()")
except plpy.SPIError:
cur.close()
return True
return False # not reached
$$ LANGUAGE plpythonu;
ERROR: could not compile PL/Python function "cursor_close_aborted_subxact"
DETAIL: SyntaxError: invalid syntax (<string>, line 4)
SELECT cursor_in_subxact();
ERROR: function cursor_in_subxact() does not exist
LINE 1: SELECT cursor_in_subxact();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT cursor_aborted_subxact();
ERROR: function cursor_aborted_subxact() does not exist
LINE 1: SELECT cursor_aborted_subxact();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT cursor_plan_aborted_subxact();
ERROR: function cursor_plan_aborted_subxact() does not exist
LINE 1: SELECT cursor_plan_aborted_subxact();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT cursor_close_aborted_subxact();
ERROR: function cursor_close_aborted_subxact() does not exist
LINE 1: SELECT cursor_close_aborted_subxact();
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.

View File

@ -242,12 +242,6 @@ PLy_traceback(PyObject *e, PyObject *v, PyObject *tb,
PG_TRY();
{
/*
* Ancient versions of Python (circa 2.3) contain a bug whereby
* the fetches below can fail if the error indicator is set.
*/
PyErr_Clear();
lineno = PyObject_GetAttrString(tb, "tb_lineno");
if (lineno == NULL)
elog(ERROR, "could not get line number from Python traceback");

View File

@ -59,16 +59,6 @@
#include <Python.h>
#endif
/*
* Py_ssize_t compat for Python <= 2.4
*/
#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
typedef int Py_ssize_t;
#define PY_SSIZE_T_MAX INT_MAX
#define PY_SSIZE_T_MIN INT_MIN
#endif
/*
* Python 2/3 strings/unicode/bytes handling. Python 2 has strings
* and unicode, Python 3 has strings, which are unicode on the C
@ -80,15 +70,6 @@ typedef int Py_ssize_t;
* string to a Python string it converts the C string from the
* PostgreSQL server encoding to a Python Unicode object.
*/
#if PY_VERSION_HEX < 0x02060000
/* This is exactly the compatibility layer that Python 2.6 uses. */
#define PyBytes_AsString PyString_AsString
#define PyBytes_FromStringAndSize PyString_FromStringAndSize
#define PyBytes_Size PyString_Size
#define PyObject_Bytes PyObject_Str
#endif
#if PY_MAJOR_VERSION >= 3
#define PyString_Check(x) 0
#define PyString_AsString(x) PLyUnicode_AsString(x)
@ -104,16 +85,6 @@ typedef int Py_ssize_t;
#define PyInt_AsLong(x) PyLong_AsLong(x)
#endif
/*
* PyVarObject_HEAD_INIT was added in Python 2.6. Its use is
* necessary to handle both Python 2 and 3. This replacement
* definition is for Python <=2.5
*/
#ifndef PyVarObject_HEAD_INIT
#define PyVarObject_HEAD_INIT(type, size) \
PyObject_HEAD_INIT(type) size,
#endif
/* Python 3 removed the Py_TPFLAGS_HAVE_ITER flag */
#if PY_MAJOR_VERSION >= 3
#define Py_TPFLAGS_HAVE_ITER 0

View File

@ -8,43 +8,6 @@ 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":
raise Exception("Python exception")
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():