1
0
mirror of https://github.com/postgres/postgres.git synced 2025-10-19 15:49:24 +03:00

plpython: Remove support for major version conflict detection

This essentially reverts commit 866566a690, 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
866566a690 to keep _PG_init() a bit modular.

Reviewed-by: Mario González Troncoso <gonzalemario@gmail.com>
Reviewed-by: Nathan Bossart <nathandbossart@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/9eb9feb6-1df3-4f0c-a0dc-9bcf35273111%40eisentraut.org
This commit is contained in:
Peter Eisentraut
2025-10-15 08:13:07 +02:00
parent 2436b8c047
commit 594ba21bce

View File

@@ -39,6 +39,7 @@ PG_FUNCTION_INFO_V1(plpython3_call_handler);
PG_FUNCTION_INFO_V1(plpython3_inline_handler); PG_FUNCTION_INFO_V1(plpython3_inline_handler);
static void PLy_initialize(void);
static PLyTrigType PLy_procedure_is_trigger(Form_pg_proc procStruct); static PLyTrigType PLy_procedure_is_trigger(Form_pg_proc procStruct);
static void plpython_error_callback(void *arg); static void plpython_error_callback(void *arg);
static void plpython_inline_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 PLyExecutionContext *PLy_push_execution_context(bool atomic_context);
static void PLy_pop_execution_context(void); 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 */ /* initialize global variables */
PyObject *PLy_interp_globals = NULL; PyObject *PLy_interp_globals = NULL;
@@ -61,62 +58,17 @@ static PLyExecutionContext *PLy_execution_contexts = NULL;
void void
_PG_init(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); pg_bindtextdomain(TEXTDOMAIN);
PLy_initialize();
} }
/* /*
* Perform one-time setup of PL/Python, after checking for a conflict * Perform one-time setup of PL/Python.
* with other versions of Python.
*/ */
static void static void
PLy_initialize(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); PyImport_AppendInittab("plpy", PyInit_plpy);
Py_Initialize(); Py_Initialize();
PyImport_ImportModule("plpy"); PyImport_ImportModule("plpy");
@@ -130,8 +82,6 @@ PLy_initialize(void)
explicit_subtransactions = NIL; explicit_subtransactions = NIL;
PLy_execution_contexts = NULL; PLy_execution_contexts = NULL;
inited = true;
} }
/* /*
@@ -172,9 +122,6 @@ plpython3_validator(PG_FUNCTION_ARGS)
if (!check_function_bodies) if (!check_function_bodies)
PG_RETURN_VOID(); PG_RETURN_VOID();
/* Do this only after making sure we need to do something */
PLy_initialize();
/* Get the new function's pg_proc entry */ /* Get the new function's pg_proc entry */
tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid)); tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
@@ -199,8 +146,6 @@ plpython3_call_handler(PG_FUNCTION_ARGS)
PLyExecutionContext *exec_ctx; PLyExecutionContext *exec_ctx;
ErrorContextCallback plerrcontext; ErrorContextCallback plerrcontext;
PLy_initialize();
nonatomic = fcinfo->context && nonatomic = fcinfo->context &&
IsA(fcinfo->context, CallContext) && IsA(fcinfo->context, CallContext) &&
!castNode(CallContext, fcinfo->context)->atomic; !castNode(CallContext, fcinfo->context)->atomic;
@@ -279,8 +224,6 @@ plpython3_inline_handler(PG_FUNCTION_ARGS)
PLyExecutionContext *exec_ctx; PLyExecutionContext *exec_ctx;
ErrorContextCallback plerrcontext; ErrorContextCallback plerrcontext;
PLy_initialize();
/* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */ /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC); SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC);