Correctly add exceptions to the plpy module for Python 3
authorPeter Eisentraut <peter_e@gmx.net>
Fri, 21 Jan 2011 21:46:56 +0000 (23:46 +0200)
committerPeter Eisentraut <peter_e@gmx.net>
Fri, 21 Jan 2011 21:46:56 +0000 (23:46 +0200)
The way the exception types where added to the module was wrong for
Python 3.  Exception classes were not actually available from plpy.
Fix that by factoring out code that is responsible for defining new
Python exceptions and make it work with Python 3.  New regression test
makes sure the plpy module has the expected contents.

Jan UrbanÅ›ki, slightly revised by me

src/pl/plpython/expected/plpython_test.out
src/pl/plpython/plpython.c
src/pl/plpython/sql/plpython_test.sql

index a229b18f448580539d8dd74b61880bdd9b7753af..32938295726d35f4baa12a0f9286c38ebba15c9e 100644 (file)
@@ -35,6 +35,19 @@ select argument_test_one(users, fname, lname) from users where lname = 'doe' ord
  willem doe => {fname: willem, lname: doe, userid: 3, username: w_doe}
 (3 rows)
 
+-- check module contents
+CREATE FUNCTION module_contents() RETURNS text AS
+$$
+contents = list(filter(lambda x: not x.startswith("__"), dir(plpy)))
+contents.sort()
+return ", ".join(contents)
+$$ LANGUAGE plpythonu;
+select module_contents();
+                                      module_contents                                      
+-------------------------------------------------------------------------------------------
+ Error, Fatal, SPIError, debug, error, execute, fatal, info, log, notice, prepare, warning
+(1 row)
+
 CREATE FUNCTION elog_test() RETURNS void
 AS $$
 plpy.debug('debug')
index 370f4f7ea28c7717b56ce9ce78d5325ad4b02ed6..18a523c8b3af96bd2260c0819e0fdbd4447c2450 100644 (file)
@@ -3268,11 +3268,37 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
  * language handler and interpreter initialization
  */
 
+/*
+ * Add exceptions to the plpy module
+ */
+static void
+PLy_add_exceptions(PyObject *plpy)
+{
+   PLy_exc_error = PyErr_NewException("plpy.Error", NULL, NULL);
+   PLy_exc_fatal = PyErr_NewException("plpy.Fatal", NULL, NULL);
+   PLy_exc_spi_error = PyErr_NewException("plpy.SPIError", NULL, NULL);
+
+   Py_INCREF(PLy_exc_error);
+   PyModule_AddObject(plpy, "Error", PLy_exc_error);
+   Py_INCREF(PLy_exc_fatal);
+   PyModule_AddObject(plpy, "Fatal", PLy_exc_fatal);
+   Py_INCREF(PLy_exc_spi_error);
+   PyModule_AddObject(plpy, "SPIError", PLy_exc_spi_error);
+}
+
 #if PY_MAJOR_VERSION >= 3
 static PyMODINIT_FUNC
 PyInit_plpy(void)
 {
-   return PyModule_Create(&PLy_module);
+   PyObject   *m;
+
+   m = PyModule_Create(&PLy_module);
+   if (m == NULL)
+       return NULL;
+
+   PLy_add_exceptions(m);
+
+   return m;
 }
 #endif
 
@@ -3363,8 +3389,7 @@ PLy_init_plpy(void)
    PyObject   *main_mod,
               *main_dict,
               *plpy_mod;
-   PyObject   *plpy,
-              *plpy_dict;
+   PyObject   *plpy;
 
    /*
     * initialize plpy module
@@ -3376,20 +3401,14 @@ PLy_init_plpy(void)
 
 #if PY_MAJOR_VERSION >= 3
    plpy = PyModule_Create(&PLy_module);
+   /* for Python 3 we initialized the exceptions in PyInit_plpy */
 #else
    plpy = Py_InitModule("plpy", PLy_methods);
+   PLy_add_exceptions(plpy);
 #endif
-   plpy_dict = PyModule_GetDict(plpy);
 
    /* PyDict_SetItemString(plpy, "PlanType", (PyObject *) &PLy_PlanType); */
 
-   PLy_exc_error = PyErr_NewException("plpy.Error", NULL, NULL);
-   PLy_exc_fatal = PyErr_NewException("plpy.Fatal", NULL, NULL);
-   PLy_exc_spi_error = PyErr_NewException("plpy.SPIError", NULL, NULL);
-   PyDict_SetItemString(plpy_dict, "Error", PLy_exc_error);
-   PyDict_SetItemString(plpy_dict, "Fatal", PLy_exc_fatal);
-   PyDict_SetItemString(plpy_dict, "SPIError", PLy_exc_spi_error);
-
    /*
     * initialize main module, and add plpy
     */
index 7cae124d98b263f4afc139ba3a76a9f97f0f7c0c..915189847a7cf0fd420da6c6c942dec65e60abbf 100644 (file)
@@ -26,6 +26,17 @@ return words'
 select argument_test_one(users, fname, lname) from users where lname = 'doe' order by 1;
 
 
+-- check module contents
+CREATE FUNCTION module_contents() RETURNS text AS
+$$
+contents = list(filter(lambda x: not x.startswith("__"), dir(plpy)))
+contents.sort()
+return ", ".join(contents)
+$$ LANGUAGE plpythonu;
+
+select module_contents();
+
+
 CREATE FUNCTION elog_test() RETURNS void
 AS $$
 plpy.debug('debug')