diff --git a/src/pl/plpython/plpy_main.c b/src/pl/plpython/plpy_main.c index 3c2ebfa..059adfa 100644 *** a/src/pl/plpython/plpy_main.c --- b/src/pl/plpython/plpy_main.c *************** static void PLy_init_interp(void); *** 63,69 **** static PLyExecutionContext *PLy_push_execution_context(void); static void PLy_pop_execution_context(void); ! static const int plpython_python_version = PY_MAJOR_VERSION; /* initialize global variables */ PyObject *PLy_interp_globals = NULL; --- 63,70 ---- static PLyExecutionContext *PLy_push_execution_context(void); static void PLy_pop_execution_context(void); ! static int *plpython_version_bitmask_ptr = NULL; ! static int plpython_version_bitmask = 0; /* initialize global variables */ PyObject *PLy_interp_globals = NULL; *************** static PLyExecutionContext *PLy_executio *** 75,102 **** void _PG_init(void) { ! /* Be sure we do initialization only once (should be redundant now) */ ! static bool inited = false; const int **version_ptr; ! if (inited) ! return; ! /* Be sure we don't run Python 2 and 3 in the same session (might crash) */ version_ptr = (const int **) find_rendezvous_variable("plpython_python_version"); ! if (!(*version_ptr)) ! *version_ptr = &plpython_python_version; ! else ! { ! if (**version_ptr != plpython_python_version) ! ereport(FATAL, ! (errmsg("Python major version mismatch in session"), ! errdetail("This session has previously used Python major version %d, and it is now attempting to use Python major version %d.", ! **version_ptr, plpython_python_version), ! errhint("Start a new session to use a different Python major version."))); ! } ! pg_bindtextdomain(TEXTDOMAIN); #if PY_MAJOR_VERSION >= 3 PyImport_AppendInittab("plpy", PyInit_plpy); --- 76,144 ---- void _PG_init(void) { ! int **bitmask_ptr; const int **version_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. ! */ ! 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 here for the next error to be localized. ! */ ! pg_bindtextdomain(TEXTDOMAIN); ! ! /* ! * We used to have a scheme whereby PL/Python would fail immediately if ! * loaded into a session in which a conflicting libpython is already ! * present. We don't like to do that anymore, but it seems possible that ! * a plpython library adhering to the old convention is present in the ! * session, in which case we have to fail. ! */ version_ptr = (const int **) find_rendezvous_variable("plpython_python_version"); ! if ((*version_ptr) != NULL) ! ereport(FATAL, ! (errmsg("Python major version mismatch in session"), ! errdetail("This session has previously used Python major version %d, and it is now attempting to use Python major version %d.", ! **version_ptr, PY_MAJOR_VERSION), ! errhint("Start a new session to use a different Python major version."))); ! } ! /* ! * Perform one-time setup of PL/Python, after checking for a conflict ! * with other versions of 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. ! */ ! if (*plpython_version_bitmask_ptr != (1 << PY_MAJOR_VERSION)) ! ereport(ERROR, ! (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; #if PY_MAJOR_VERSION >= 3 PyImport_AppendInittab("plpy", PyInit_plpy); *************** _PG_init(void) *** 120,126 **** } /* ! * This should only be called once from _PG_init. Initialize the Python * interpreter and global data. */ static void --- 162,168 ---- } /* ! * This should be called only once, from PLy_initialize. Initialize the Python * interpreter and global data. */ static void *************** plpython_validator(PG_FUNCTION_ARGS) *** 155,163 **** PG_RETURN_VOID(); if (!check_function_bodies) - { PG_RETURN_VOID(); ! } /* Get the new function's pg_proc entry */ tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid)); --- 197,206 ---- PG_RETURN_VOID(); 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)); *************** plpython_call_handler(PG_FUNCTION_ARGS) *** 191,196 **** --- 234,241 ---- PLyExecutionContext *exec_ctx; ErrorContextCallback plerrcontext; + PLy_initialize(); + /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */ if (SPI_connect() != SPI_OK_CONNECT) elog(ERROR, "SPI_connect failed"); *************** plpython_inline_handler(PG_FUNCTION_ARGS *** 266,271 **** --- 311,318 ---- PLyExecutionContext *exec_ctx; ErrorContextCallback plerrcontext; + PLy_initialize(); + /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */ if (SPI_connect() != SPI_OK_CONNECT) elog(ERROR, "SPI_connect failed");