From 4044c8613be343ad4431d42c16d6b190c97e2b35 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sat, 9 Aug 2025 18:27:30 +0200 Subject: [PATCH] plpython: Remove support for major version conflict detection 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. --- src/pl/plpython/plpy_main.c | 65 +++---------------------------------- 1 file changed, 4 insertions(+), 61 deletions(-) diff --git a/src/pl/plpython/plpy_main.c b/src/pl/plpython/plpy_main.c index f36eadbadc6..38f6365dd6b 100644 --- a/src/pl/plpython/plpy_main.c +++ b/src/pl/plpython/plpy_main.c @@ -38,6 +38,7 @@ PG_FUNCTION_INFO_V1(plpython3_call_handler); PG_FUNCTION_INFO_V1(plpython3_inline_handler); +static void PLy_initialize(void); static bool PLy_procedure_is_trigger(Form_pg_proc procStruct); static void plpython_error_callback(void *arg); static void plpython_inline_error_callback(void *arg); @@ -46,10 +47,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; @@ -60,62 +57,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"); @@ -129,8 +81,6 @@ PLy_initialize(void) explicit_subtransactions = NIL; PLy_execution_contexts = NULL; - - inited = true; } /* @@ -171,9 +121,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)) @@ -198,8 +145,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; @@ -271,8 +216,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); -- 2.50.1