diff --git a/configure b/configure
index 37aa82d..4887dee 100755
--- a/configure
+++ b/configure
@@ -714,6 +714,7 @@ with_ldap
with_krb_srvnam
krb_srvtab
with_gssapi
+with_python_stub
with_python
with_perl
with_tcl
@@ -847,6 +848,7 @@ with_tcl
with_tclconfig
with_perl
with_python
+with_python_stub
with_gssapi
with_krb_srvnam
with_pam
@@ -1546,6 +1548,7 @@ Optional Packages:
--with-tclconfig=DIR tclConfig.sh is in DIR
--with-perl build Perl modules (PL/Perl)
--with-python build Python modules (PL/Python)
+ --with-python-stub build Python 2 compatibility stub
--with-gssapi build with GSSAPI support
--with-krb-srvnam=NAME default service principal name in Kerberos (GSSAPI)
[postgres]
@@ -7644,6 +7647,32 @@ fi
$as_echo "$with_python" >&6; }
+
+
+
+# Check whether --with-python-stub was given.
+if test "${with_python_stub+set}" = set; then :
+ withval=$with_python_stub;
+ case $withval in
+ yes)
+ :
+ ;;
+ no)
+ :
+ ;;
+ *)
+ as_fn_error $? "no argument expected for --with-python-stub option" "$LINENO" 5
+ ;;
+ esac
+
+else
+ with_python_stub=no
+
+fi
+
+
+
+
#
# GSSAPI
#
@@ -9745,6 +9774,12 @@ $as_echo "${python_libspec} ${python_additional_libs}" >&6; }
+ # Disable building Python 2 stub if primary version isn't Python 3
+ if test "$python_majorversion" -lt 3; then
+ with_python_stub=no
+ fi
+else
+ with_python_stub=no
fi
if test "$cross_compiling" = yes && test -z "$with_system_tzdata"; then
diff --git a/configure.in b/configure.in
index 8adb409..ba2ff2d 100644
--- a/configure.in
+++ b/configure.in
@@ -766,6 +766,9 @@ PGAC_ARG_BOOL(with, python, no, [build Python modules (PL/Python)])
AC_MSG_RESULT([$with_python])
AC_SUBST(with_python)
+PGAC_ARG_BOOL(with, python-stub, no, [build Python 2 compatibility stub])
+AC_SUBST(with_python_stub)
+
#
# GSSAPI
#
@@ -1042,6 +1045,12 @@ fi
if test "$with_python" = yes; then
PGAC_PATH_PYTHON
PGAC_CHECK_PYTHON_EMBED_SETUP
+ # Disable building Python 2 stub if primary version isn't Python 3
+ if test "$python_majorversion" -lt 3; then
+ with_python_stub=no
+ fi
+else
+ with_python_stub=no
fi
if test "$cross_compiling" = yes && test -z "$with_system_tzdata"; then
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index f1adcc3..2cf34d2 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -877,6 +877,23 @@ build-postgresql:
+
+
+
+ Build a stub version of the Python
+ 2 PL/Python language, to aid in
+ transitioning old PL/Python code.
+ This option is recommended if you are
+ building PL/Python for Python 3
+ and do not intend to also build a version for Python 2.
+ This option is ignored if you do not also
+ specify , or if the selected Python
+ implementation is Python 2.
+
+
+
+
+
diff --git a/doc/src/sgml/plpython.sgml b/doc/src/sgml/plpython.sgml
index 1921915..14b9a4b 100644
--- a/doc/src/sgml/plpython.sgml
+++ b/doc/src/sgml/plpython.sgml
@@ -77,13 +77,7 @@
The language named plpythonu implements
PL/Python based on the default Python language variant, which is
- currently Python 2. (This default is independent of what any
- local Python installations might consider to be
- their default, for example,
- what /usr/bin/python might be.) The
- default will probably be changed to Python 3 in a distant future
- release of PostgreSQL, depending on the progress of the
- migration to Python 3 in the Python community.
+ determined by the person who builds and installs PostgreSQL.
@@ -103,9 +97,22 @@
The built variant depends on which Python version was found during
the installation or which version was explicitly set using
the PYTHON environment variable;
- see . To make both variants of
- PL/Python available in one installation, the source tree has to be
- configured and built twice.
+ see . To make working versions of
+ both variants of PL/Python available in one installation, the source
+ tree has to be configured and built twice.
+
+
+
+ However, if the builder specifies both
+ and while building with Python 3,
+ then in addition to the working Python-3-based PL/Python,
+ a stub version of plpython2u is
+ produced. This stub is non-functional and will simply throw errors if
+ any plpython2u function is executed, but its
+ presence allows such functions to be loaded into the database in
+ preparation for conversion to plpython3u. This
+ configuration also causes plpythonu to become
+ Python 3 rather than Python 2.
@@ -115,49 +122,38 @@
- Existing users and users who are currently not interested in
- Python 3 use the language name plpythonu and
- don't have to change anything for the foreseeable future. It is
- recommended to gradually future-proof the code
- via migration to Python 2.6/2.7 to simplify the eventual
- migration to Python 3.
+ Use the language name plpythonu if you have
+ simple Python code that works for either Python 2 or Python 3;
+ or if you are prepared to migrate your code whenever your packager
+ decides to change the default Python version.
In practice, many PL/Python functions will migrate to Python 3
- with few or no changes.
+ with few or no changes. However, there are some cases that
+ will require more work.
- Users who know that they have heavily Python 2 dependent code
- and don't plan to ever change it can make use of
+ If you know that you have heavily Python 2 dependent code
+ and don't plan to ever change it, you can make use of
the plpython2u language name. This will
- continue to work into the very distant future, until Python 2
- support might be completely dropped by PostgreSQL.
-
-
-
-
-
- Users who want to dive into Python 3 can use
- the plpython3u language name, which will keep
- working forever by today's standards. In the distant future,
- when Python 3 might become the default, they might like to
- remove the 3 for aesthetic reasons.
+ continue to work for as long as your operating system platform
+ continues to provide Python 2. PostgreSQL itself may eventually
+ drop support for this option, but that is unlikely to happen
+ as long as any platform support remains in the wild.
- Daredevils, who want to build a Python-3-only operating system
- environment, can change the contents of
- plpythonu's extension control and script files
- to make plpythonu be equivalent
- to plpython3u, keeping in mind that this
- would make their installation incompatible with most of the rest
- of the world.
+ If you know your code requires Python 3, use
+ the plpython3u language name. You can also
+ use this language name to tag functions that have been successfully
+ converted from Python 2, so as to keep track of which functions have
+ been converted and which have not.
@@ -171,6 +167,8 @@
Python major versions in a session, which will abort the session if
a mismatch is detected. It is possible, however, to use both
PL/Python variants in the same database, from separate sessions.
+ (Also, the stub version of plpython2u
+ does not present any conflicts.)
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index e4db3e8..f039fb4 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -180,6 +180,7 @@ bitcodedir = $(pkglibdir)/bitcode
with_icu = @with_icu@
with_perl = @with_perl@
with_python = @with_python@
+with_python_stub = @with_python_stub@
with_tcl = @with_tcl@
with_openssl = @with_openssl@
with_readline = @with_readline@
diff --git a/src/pl/Makefile b/src/pl/Makefile
index c4a0d1c..c011607 100644
--- a/src/pl/Makefile
+++ b/src/pl/Makefile
@@ -26,6 +26,12 @@ else
ALWAYS_SUBDIRS += plpython
endif
+ifeq ($(with_python_stub), yes)
+SUBDIRS += stub_plpython2
+else
+ALWAYS_SUBDIRS += stub_plpython2
+endif
+
ifeq ($(with_tcl), yes)
SUBDIRS += tcl
else
diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile
index 0d53d3d..e40844b 100644
--- a/src/pl/plpython/Makefile
+++ b/src/pl/plpython/Makefile
@@ -37,6 +37,9 @@ OBJS = \
DATA = $(NAME)u.control $(NAME)u--1.0.sql $(NAME)u--unpackaged--1.0.sql
ifeq ($(python_majorversion),2)
DATA += plpythonu.control plpythonu--1.0.sql plpythonu--unpackaged--1.0.sql
+else ifeq ($(with_python_stub), yes)
+# install extension files for the stub module (see ../stub_plpython2)
+DATA += plpythonu.control plpythonu--1.0.sql plpython2u.control plpython2u--1.0.sql
endif
ifeq ($(python_majorversion),3)
DATA += convert_python3.control convert_python3--1.0.sql
diff --git a/src/pl/stub_plpython2/Makefile b/src/pl/stub_plpython2/Makefile
new file mode 100644
index 0000000..67e7559
--- /dev/null
+++ b/src/pl/stub_plpython2/Makefile
@@ -0,0 +1,38 @@
+# src/pl/stub_plpython2/Makefile
+
+# Note that this Makefile only builds and installs a quasi-dummy
+# version of plpython2.so. The control and script files for the
+# plpythonu and plpython2u extensions are installed by ../plpython;
+# they are the same whether we're using real or stub plpython2.
+# (We'd probably not have this separate subdirectory at all, except
+# that Makefile.shlib can only build one shlib per directory.)
+
+subdir = src/pl/stub_plpython2
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+PGFILEDESC = "PL/Python - procedural language stub for Python 2"
+
+NAME = plpython2
+
+OBJS = \
+ $(WIN32RES) \
+ stub_plpython2.o
+
+include $(top_srcdir)/src/Makefile.shlib
+
+all: all-lib
+
+# Ensure parallel safety if a build is started in this directory
+$(OBJS): | submake-generated-headers
+
+install: all install-lib
+
+installdirs: installdirs-lib
+
+uninstall: uninstall-lib
+
+clean distclean: clean-lib
+ rm -f $(OBJS)
+
+maintainer-clean: distclean
diff --git a/src/pl/stub_plpython2/stub_plpython2.c b/src/pl/stub_plpython2/stub_plpython2.c
new file mode 100644
index 0000000..4ade88b
--- /dev/null
+++ b/src/pl/stub_plpython2/stub_plpython2.c
@@ -0,0 +1,105 @@
+/*
+ * PL/Python stub for Python 2, in an environment that has only Python 3
+ *
+ * Our strategy is to pass through "plpythonu" functions to Python 3,
+ * but throw a not-implemented error for "plpython2u".
+ *
+ * Pass-through is implemented by using dfmgr.c to look up the appropriate
+ * function in plpython3.so, rather than trying to resolve the reference
+ * directly. This greatly simplifies building this as an independent
+ * shared library, and it ensures that we can't somehow pull in a different
+ * version of plpython3 (and thence libpython) than would get loaded for
+ * a plpython3u function.
+ *
+ * src/pl/stub_plpython2/stub_plpython2.c
+ */
+
+#include "postgres.h"
+
+#include "fmgr.h"
+
+#define PLPYTHON_LIBNAME "$libdir/plpython3"
+
+/*
+ * exported functions
+ */
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1(plpython_validator);
+PG_FUNCTION_INFO_V1(plpython_call_handler);
+PG_FUNCTION_INFO_V1(plpython_inline_handler);
+
+PG_FUNCTION_INFO_V1(plpython2_validator);
+PG_FUNCTION_INFO_V1(plpython2_call_handler);
+PG_FUNCTION_INFO_V1(plpython2_inline_handler);
+
+
+Datum
+plpython_validator(PG_FUNCTION_ARGS)
+{
+ static PGFunction plpython3_validator = NULL;
+
+ if (plpython3_validator == NULL)
+ plpython3_validator =
+ load_external_function(PLPYTHON_LIBNAME,
+ "plpython3_validator",
+ true, NULL);
+
+ return (*plpython3_validator) (fcinfo);
+}
+
+Datum
+plpython_call_handler(PG_FUNCTION_ARGS)
+{
+ static PGFunction plpython3_call_handler = NULL;
+
+ if (plpython3_call_handler == NULL)
+ plpython3_call_handler =
+ load_external_function(PLPYTHON_LIBNAME,
+ "plpython3_call_handler",
+ true, NULL);
+
+ return (*plpython3_call_handler) (fcinfo);
+}
+
+Datum
+plpython_inline_handler(PG_FUNCTION_ARGS)
+{
+ static PGFunction plpython3_inline_handler = NULL;
+
+ if (plpython3_inline_handler == NULL)
+ plpython3_inline_handler =
+ load_external_function(PLPYTHON_LIBNAME,
+ "plpython3_inline_handler",
+ true, NULL);
+
+ return (*plpython3_inline_handler) (fcinfo);
+}
+
+Datum
+plpython2_validator(PG_FUNCTION_ARGS)
+{
+ /* It seems more convenient to do nothing here than throw an error. */
+ PG_RETURN_VOID();
+}
+
+Datum
+plpython2_call_handler(PG_FUNCTION_ARGS)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Python 2 is no longer supported"),
+ errhint("Convert the function to use plpython3u.")));
+ PG_RETURN_NULL(); /* keep compiler quiet */
+}
+
+Datum
+plpython2_inline_handler(PG_FUNCTION_ARGS)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Python 2 is no longer supported"),
+ errhint("Convert the DO block to use plpython3u.")));
+ PG_RETURN_NULL(); /* keep compiler quiet */
+}