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 */