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 7b283d0e1d1d79bf1c962d790c94d2a53f3bb38a, 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:
parent
f5d28710c7
commit
37f21ed132
@ -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
4
configure
vendored
@ -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
|
||||
|
@ -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"/>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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():
|
||||
|
@ -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.
|
@ -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.
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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():
|
||||
|
Loading…
x
Reference in New Issue
Block a user