diff --git a/config/python.m4 b/config/python.m4
index c51aa4e332..d41aeb2876 100644
--- a/config/python.m4
+++ b/config/python.m4
@@ -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])
diff --git a/configure b/configure
index d2d63f2e55..25cfbcb2cd 100755
--- a/configure
+++ b/configure
@@ -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
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index d4904bf5a0..f1adcc3c55 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -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"/>
diff --git a/doc/src/sgml/plpython.sgml b/doc/src/sgml/plpython.sgml
index c421092571..7bdaf76bba 100644
--- a/doc/src/sgml/plpython.sgml
+++ b/doc/src/sgml/plpython.sgml
@@ -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>
 
diff --git a/src/pl/plpython/expected/README b/src/pl/plpython/expected/README
index b890563377..d735ae989b 100644
--- a/src/pl/plpython/expected/README
+++ b/src/pl/plpython/expected/README
@@ -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
diff --git a/src/pl/plpython/expected/plpython_error_0.out b/src/pl/plpython/expected/plpython_error_0.out
deleted file mode 100644
index 290902b182..0000000000
--- a/src/pl/plpython/expected/plpython_error_0.out
+++ /dev/null
@@ -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)
-
diff --git a/src/pl/plpython/expected/plpython_subtransaction.out b/src/pl/plpython/expected/plpython_subtransaction.out
index 069f0992ab..8df64e7619 100644
--- a/src/pl/plpython/expected/plpython_subtransaction.out
+++ b/src/pl/plpython/expected/plpython_subtransaction.out
@@ -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():
diff --git a/src/pl/plpython/expected/plpython_subtransaction_0.out b/src/pl/plpython/expected/plpython_subtransaction_0.out
deleted file mode 100644
index 97ee42b5a9..0000000000
--- a/src/pl/plpython/expected/plpython_subtransaction_0.out
+++ /dev/null
@@ -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.
diff --git a/src/pl/plpython/expected/plpython_subtransaction_5.out b/src/pl/plpython/expected/plpython_subtransaction_5.out
deleted file mode 100644
index e172e98f86..0000000000
--- a/src/pl/plpython/expected/plpython_subtransaction_5.out
+++ /dev/null
@@ -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.
diff --git a/src/pl/plpython/plpy_elog.c b/src/pl/plpython/plpy_elog.c
index eb562821a2..71b433ef26 100644
--- a/src/pl/plpython/plpy_elog.c
+++ b/src/pl/plpython/plpy_elog.c
@@ -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");
diff --git a/src/pl/plpython/plpython.h b/src/pl/plpython/plpython.h
index 4a1df3ee7e..6d981a0a06 100644
--- a/src/pl/plpython/plpython.h
+++ b/src/pl/plpython/plpython.h
@@ -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
diff --git a/src/pl/plpython/sql/plpython_subtransaction.sql b/src/pl/plpython/sql/plpython_subtransaction.sql
index 398c65720c..38c8617828 100644
--- a/src/pl/plpython/sql/plpython_subtransaction.sql
+++ b/src/pl/plpython/sql/plpython_subtransaction.sql
@@ -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():