plpython: Remove support for major version conflict detection
authorPeter Eisentraut <[email protected]>
Wed, 15 Oct 2025 06:13:07 +0000 (08:13 +0200)
committerPeter Eisentraut <[email protected]>
Wed, 15 Oct 2025 06:18:29 +0000 (08:18 +0200)
This essentially reverts commit 866566a690b, which installed
safeguards against loading plpython2 and plpython3 into the same
process.  We don't support plpython2 anymore, so this is obsolete.

The Python and PL/Python initialization now happens again in
_PG_init() rather than the first time a PL/Python call handler is
invoked.  (Often, these will be very close together.)

I kept the separate PLy_initialize() function introduced by
866566a690b to keep _PG_init() a bit modular.

Reviewed-by: Mario González Troncoso <[email protected]>
Reviewed-by: Nathan Bossart <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/9eb9feb6-1df3-4f0c-a0dc-9bcf35273111%40eisentraut.org

src/pl/plpython/plpy_main.c

index 70fc2c9257a89862eea0ca051edfd1e3d2ab3853..8ae02a239ae856af5a5c5590dac79f26d910fa1b 100644 (file)
@@ -39,6 +39,7 @@ PG_FUNCTION_INFO_V1(plpython3_call_handler);
 PG_FUNCTION_INFO_V1(plpython3_inline_handler);
 
 
+static void PLy_initialize(void);
 static PLyTrigType PLy_procedure_is_trigger(Form_pg_proc procStruct);
 static void plpython_error_callback(void *arg);
 static void plpython_inline_error_callback(void *arg);
@@ -47,10 +48,6 @@ static void PLy_init_interp(void);
 static PLyExecutionContext *PLy_push_execution_context(bool atomic_context);
 static void PLy_pop_execution_context(void);
 
-/* static state for Python library conflict detection */
-static int *plpython_version_bitmask_ptr = NULL;
-static int plpython_version_bitmask = 0;
-
 /* initialize global variables */
 PyObject   *PLy_interp_globals = NULL;
 
@@ -61,62 +58,17 @@ static PLyExecutionContext *PLy_execution_contexts = NULL;
 void
 _PG_init(void)
 {
-   int       **bitmask_ptr;
-
-   /*
-    * Set up a shared bitmask variable telling which Python version(s) are
-    * loaded into this process's address space.  If there's more than one, we
-    * cannot call into libpython for fear of causing crashes.  But postpone
-    * the actual failure for later, so that operations like pg_restore can
-    * load more than one plpython library so long as they don't try to do
-    * anything much with the language.
-    *
-    * While we only support Python 3 these days, somebody might create an
-    * out-of-tree version adding back support for Python 2. Conflicts with
-    * such an extension should be detected.
-    */
-   bitmask_ptr = (int **) find_rendezvous_variable("plpython_version_bitmask");
-   if (!(*bitmask_ptr))        /* am I the first? */
-       *bitmask_ptr = &plpython_version_bitmask;
-   /* Retain pointer to the agreed-on shared variable ... */
-   plpython_version_bitmask_ptr = *bitmask_ptr;
-   /* ... and announce my presence */
-   *plpython_version_bitmask_ptr |= (1 << PY_MAJOR_VERSION);
-
-   /*
-    * This should be safe even in the presence of conflicting plpythons, and
-    * it's necessary to do it before possibly throwing a conflict error, or
-    * the error message won't get localized.
-    */
    pg_bindtextdomain(TEXTDOMAIN);
+
+   PLy_initialize();
 }
 
 /*
- * Perform one-time setup of PL/Python, after checking for a conflict
- * with other versions of Python.
+ * Perform one-time setup of PL/Python.
  */
 static void
 PLy_initialize(void)
 {
-   static bool inited = false;
-
-   /*
-    * Check for multiple Python libraries before actively doing anything with
-    * libpython.  This must be repeated on each entry to PL/Python, in case a
-    * conflicting library got loaded since we last looked.
-    *
-    * It is attractive to weaken this error from FATAL to ERROR, but there
-    * would be corner cases, so it seems best to be conservative.
-    */
-   if (*plpython_version_bitmask_ptr != (1 << PY_MAJOR_VERSION))
-       ereport(FATAL,
-               (errmsg("multiple Python libraries are present in session"),
-                errdetail("Only one Python major version can be used in one session.")));
-
-   /* The rest should only be done once per session */
-   if (inited)
-       return;
-
    PyImport_AppendInittab("plpy", PyInit_plpy);
    Py_Initialize();
    PyImport_ImportModule("plpy");
@@ -130,8 +82,6 @@ PLy_initialize(void)
    explicit_subtransactions = NIL;
 
    PLy_execution_contexts = NULL;
-
-   inited = true;
 }
 
 /*
@@ -172,9 +122,6 @@ plpython3_validator(PG_FUNCTION_ARGS)
    if (!check_function_bodies)
        PG_RETURN_VOID();
 
-   /* Do this only after making sure we need to do something */
-   PLy_initialize();
-
    /* Get the new function's pg_proc entry */
    tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
    if (!HeapTupleIsValid(tuple))
@@ -199,8 +146,6 @@ plpython3_call_handler(PG_FUNCTION_ARGS)
    PLyExecutionContext *exec_ctx;
    ErrorContextCallback plerrcontext;
 
-   PLy_initialize();
-
    nonatomic = fcinfo->context &&
        IsA(fcinfo->context, CallContext) &&
        !castNode(CallContext, fcinfo->context)->atomic;
@@ -279,8 +224,6 @@ plpython3_inline_handler(PG_FUNCTION_ARGS)
    PLyExecutionContext *exec_ctx;
    ErrorContextCallback plerrcontext;
 
-   PLy_initialize();
-
    /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
    SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC);