plpython: Streamline initialization
authorPeter Eisentraut <peter@eisentraut.org>
Thu, 15 Jan 2026 11:11:52 +0000 (12:11 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Thu, 15 Jan 2026 11:11:52 +0000 (12:11 +0100)
The initialization of PL/Python (the Python interpreter, the global
state, the plpy module) was arranged confusingly across different
functions with unclear and confusing boundaries.  For example,
PLy_init_interp() said "Initialize the Python interpreter ..." but it
didn't actually do this, and PLy_init_plpy() said "initialize plpy
module" but it didn't do that either.  After this change, all the
global initialization is called directly from _PG_init(), and the plpy
module initialization is all called from its registered initialization
function PyInit_plpy().

Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Matheus Alcantara <matheusssilv97@gmail.com>
Reviewed-by: li carol <carol.li2025@outlook.com>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Discussion: https://www.postgresql.org/message-id/f31333f1-fbb7-4098-b209-bf2d71fbd4f3%40eisentraut.org

src/pl/plpython/plpy_main.c
src/pl/plpython/plpy_plpymodule.c
src/pl/plpython/plpy_plpymodule.h

index 7673b5eca7b15ff7d796198e301319fd842d5fbd..9f07c115f8000a0f81f1674bef3daa258ceb695e 100644 (file)
@@ -39,11 +39,9 @@ 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);
-static void PLy_init_interp(void);
 
 static PLyExecutionContext *PLy_push_execution_context(bool atomic_context);
 static void PLy_pop_execution_context(void);
@@ -58,25 +56,53 @@ static PLyExecutionContext *PLy_execution_contexts = NULL;
 void
 _PG_init(void)
 {
-       pg_bindtextdomain(TEXTDOMAIN);
+       PyObject   *main_mod;
+       PyObject   *main_dict;
+       PyObject   *GD;
+       PyObject   *plpy_mod;
 
-       PLy_initialize();
-}
+       pg_bindtextdomain(TEXTDOMAIN);
 
-/*
- * Perform one-time setup of PL/Python.
- */
-static void
-PLy_initialize(void)
-{
+       /* Add plpy to table of built-in modules. */
        PyImport_AppendInittab("plpy", PyInit_plpy);
+
+       /* Initialize Python interpreter. */
        Py_Initialize();
-       PyImport_ImportModule("plpy");
-       PLy_init_interp();
-       PLy_init_plpy();
+
+       main_mod = PyImport_AddModule("__main__");
+       if (main_mod == NULL || PyErr_Occurred())
+               PLy_elog(ERROR, "could not import \"%s\" module", "__main__");
+       Py_INCREF(main_mod);
+
+       main_dict = PyModule_GetDict(main_mod);
+       if (main_dict == NULL)
+               PLy_elog(ERROR, NULL);
+
+       /*
+        * Set up GD.
+        */
+       GD = PyDict_New();
+       if (GD == NULL)
+               PLy_elog(ERROR, NULL);
+       PyDict_SetItemString(main_dict, "GD", GD);
+
+       /*
+        * Import plpy.
+        */
+       plpy_mod = PyImport_ImportModule("plpy");
+       if (plpy_mod == NULL)
+               PLy_elog(ERROR, "could not import \"%s\" module", "plpy");
+       if (PyDict_SetItemString(main_dict, "plpy", plpy_mod) == -1)
+               PLy_elog(ERROR, NULL);
+
        if (PyErr_Occurred())
                PLy_elog(FATAL, "untrapped error in initialization");
 
+       Py_INCREF(main_dict);
+       PLy_interp_globals = main_dict;
+
+       Py_DECREF(main_mod);
+
        init_procedure_caches();
 
        explicit_subtransactions = NIL;
@@ -84,30 +110,6 @@ PLy_initialize(void)
        PLy_execution_contexts = NULL;
 }
 
-/*
- * This should be called only once, from PLy_initialize. Initialize the Python
- * interpreter and global data.
- */
-static void
-PLy_init_interp(void)
-{
-       static PyObject *PLy_interp_safe_globals = NULL;
-       PyObject   *mainmod;
-
-       mainmod = PyImport_AddModule("__main__");
-       if (mainmod == NULL || PyErr_Occurred())
-               PLy_elog(ERROR, "could not import \"__main__\" module");
-       Py_INCREF(mainmod);
-       PLy_interp_globals = PyModule_GetDict(mainmod);
-       PLy_interp_safe_globals = PyDict_New();
-       if (PLy_interp_safe_globals == NULL)
-               PLy_elog(ERROR, NULL);
-       PyDict_SetItemString(PLy_interp_globals, "GD", PLy_interp_safe_globals);
-       Py_DECREF(mainmod);
-       if (PLy_interp_globals == NULL || PyErr_Occurred())
-               PLy_elog(ERROR, "could not initialize globals");
-}
-
 Datum
 plpython3_validator(PG_FUNCTION_ARGS)
 {
index 72867388653a92678225653c47a687d727d10d01..72806c17e17a4135b1790c5763681575ed92b7f9 100644 (file)
@@ -133,35 +133,12 @@ PyInit_plpy(void)
 
        PLy_add_exceptions(m);
 
-       return m;
-}
-
-void
-PLy_init_plpy(void)
-{
-       PyObject   *main_mod,
-                          *main_dict,
-                          *plpy_mod;
-
-       /*
-        * initialize plpy module
-        */
        PLy_plan_init_type();
        PLy_result_init_type();
        PLy_subtransaction_init_type();
        PLy_cursor_init_type();
 
-       /*
-        * initialize main module, and add plpy
-        */
-       main_mod = PyImport_AddModule("__main__");
-       main_dict = PyModule_GetDict(main_mod);
-       plpy_mod = PyImport_AddModule("plpy");
-       if (plpy_mod == NULL)
-               PLy_elog(ERROR, "could not import \"plpy\" module");
-       PyDict_SetItemString(main_dict, "plpy", plpy_mod);
-       if (PyErr_Occurred())
-               PLy_elog(ERROR, "could not import \"plpy\" module");
+       return m;
 }
 
 static void
index 1ca3823daf283027ba76d478375caf951e67abce..88f902346a6ec8307be558f2e72d3425f083d89f 100644 (file)
@@ -13,6 +13,5 @@ extern HTAB *PLy_spi_exceptions;
 
 
 PyMODINIT_FUNC PyInit_plpy(void);
-extern void PLy_init_plpy(void);
 
 #endif                                                 /* PLPY_PLPYMODULE_H */