Hi,

there seems to be a problem in the way we add exceptions to the plpy
module in PL/Python compiled with Python 3k.

Try this: DO $$ plpy.SPIError $$ language plpython3u;

I'm not a Python 3 expert, but I nicked some code from the Internet and
came up with this patch (passes regression tests on both Python 2 and 3).

The funny thing is that it never blew up earlier, because we only used
plpy.SPIError in except: blocks that weren't even executed, as errors in
plpy.execute just terminate the function.

With my changes they turn into catchable exceptions, and so accessing
plpy.SPIError in Python 3 becomes essential.

BTW: do we have any buildfarm animal that uses Python 3?

Cheers,
Jan
*** src/pl/plpython/expected/plpython_test.out
--- src/pl/plpython/expected/plpython_test.out	2010-12-18 18:46:17.000000000 +0100
***************
*** 35,40 ****
--- 35,53 ----
   willem doe => {fname: willem, lname: doe, userid: 3, username: w_doe}
  (3 rows)
  
+ -- check module contents
+ CREATE FUNCTION module_contents() RETURNS text AS
+ $$
+ contents = dir(plpy)
+ contents.sort()
+ return ", ".join(contents)
+ $$ LANGUAGE plpythonu;
+ select module_contents();
+                                                       module_contents                                                      
+ ---------------------------------------------------------------------------------------------------------------------------
+  Error, Fatal, SPIError, __doc__, __name__, __package__, debug, error, execute, fatal, info, log, notice, prepare, warning
+ (1 row)
+ 
  CREATE FUNCTION elog_test() RETURNS void
  AS $$
  plpy.debug('debug')
*** src/pl/plpython/plpython.c
--- src/pl/plpython/plpython.c	2010-12-18 18:39:00.000000000 +0100
***************
*** 3204,3209 ****
--- 3204,3238 ----
  
  
  /*
+  * Exception initialization
+  */
+ 
+ static void
+ PLy_initialize_exceptions(PyObject *plpy)
+ {
+ #if PY_MAJOR_VERSION < 3
+ 	PyObject *plpy_dict = PyModule_GetDict(plpy);
+ #endif
+ 
+ 	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);
+ 
+ #if PY_MAJOR_VERSION >= 3
+ 	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);
+ #else
+ 	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);
+ #endif
+ }
+ 
+ /*
   * language handler and interpreter initialization
   */
  
***************
*** 3211,3217 ****
  static PyMODINIT_FUNC
  PyInit_plpy(void)
  {
! 	return PyModule_Create(&PLy_module);
  }
  #endif
  
--- 3240,3254 ----
  static PyMODINIT_FUNC
  PyInit_plpy(void)
  {
! 	PyObject	*m;
! 
! 	m = PyModule_Create(&PLy_module);
! 	if (m == NULL)
! 		return NULL;
! 
! 	PLy_initialize_exceptions(m);
! 
! 	return m;
  }
  #endif
  
***************
*** 3290,3297 ****
  	PyObject   *main_mod,
  			   *main_dict,
  			   *plpy_mod;
! 	PyObject   *plpy,
! 			   *plpy_dict;
  
  	/*
  	 * initialize plpy module
--- 3327,3333 ----
  	PyObject   *main_mod,
  			   *main_dict,
  			   *plpy_mod;
! 	PyObject   *plpy;
  
  	/*
  	 * initialize plpy module
***************
*** 3305,3322 ****
  	plpy = PyModule_Create(&PLy_module);
  #else
  	plpy = Py_InitModule("plpy", PLy_methods);
  #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
  	 */
--- 3341,3352 ----
  	plpy = PyModule_Create(&PLy_module);
  #else
  	plpy = Py_InitModule("plpy", PLy_methods);
+ 	/* for Python 3 we initialized the exceptions in PyInit_plpy */
+ 	PLy_initialize_exceptions(plpy);
  #endif
  
  	/* PyDict_SetItemString(plpy, "PlanType", (PyObject *) &PLy_PlanType); */
  
  	/*
  	 * initialize main module, and add plpy
  	 */
*** src/pl/plpython/sql/plpython_test.sql
--- src/pl/plpython/sql/plpython_test.sql	2010-12-18 18:44:19.000000000 +0100
***************
*** 25,30 ****
--- 25,39 ----
  
  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 = dir(plpy)
+ contents.sort()
+ return ", ".join(contents)
+ $$ LANGUAGE plpythonu;
+ 
+ select module_contents();
  
  CREATE FUNCTION elog_test() RETURNS void
  AS $$
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to