From eb17c7f733621bec5758a09737795d243306f360 Mon Sep 17 00:00:00 2001 From: Catalin Iacob Date: Thu, 28 Jan 2016 17:14:11 +0100 Subject: [PATCH 2/2] use plpy.Error to hold the data not plpy.SPIError --- src/pl/plpython/plpy_elog.c | 83 +++++++++++++++++++++++++++++++++++++++ src/pl/plpython/plpy_elog.h | 2 + src/pl/plpython/plpy_plpymodule.c | 2 +- src/pl/plpython/plpy_spi.c | 1 + src/pl/plpython/plpy_spi.h | 3 -- 5 files changed, 87 insertions(+), 4 deletions(-) diff --git a/src/pl/plpython/plpy_elog.c b/src/pl/plpython/plpy_elog.c index aea79db..80301c0 100644 --- a/src/pl/plpython/plpy_elog.c +++ b/src/pl/plpython/plpy_elog.c @@ -25,6 +25,9 @@ static void PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth); static void PLy_get_spi_error_data(PyObject *exc, int *sqlerrcode, char **detail, char **hint, char **query, int *position, char **schema_name, char **table_name, char **column_name, char **datatype_name, char **constraint_name); +static void PLy_get_error_data(PyObject *exc, int *sqlerrcode, char **detail, char **hint, char **query, int *position, + char **schema_name, char **table_name, char **column_name, + char **datatype_name, char **constraint_name); static char *get_source_line(const char *src, int lineno); @@ -66,6 +69,11 @@ PLy_elog(int elevel, const char *fmt,...) &schema_name, &table_name, &column_name, &datatype_name, &constraint_name); + if (PyErr_GivenExceptionMatches(val, PLy_exc_error)) + PLy_get_error_data(val, &sqlerrcode, &detail, &hint, &query, &position, + &schema_name, &table_name, &column_name, + &datatype_name, &constraint_name); + if (PyErr_GivenExceptionMatches(val, PLy_exc_fatal)) elevel = FATAL; } @@ -409,6 +417,35 @@ PLy_get_spi_error_data(PyObject *exc, int *sqlerrcode, char **detail, char **hin } /* + * Extract the error data from an Error + */ +static void +PLy_get_error_data(PyObject *exc, int *sqlerrcode, char **detail, char **hint, char **query, int *position, + char **schema_name, char **table_name, char **column_name, + char **datatype_name, char **constraint_name) +{ + PyObject *err_detail = NULL; + PyObject *err_hint = NULL; + + err_detail = PyObject_GetAttrString(exc, "detail"); + if (err_detail != NULL) + { + *detail = PyString_AsString(err_detail); + Py_DECREF(err_detail); + } + + err_hint = PyObject_GetAttrString(exc, "hint"); + if (err_hint != NULL) + { + *hint = PyString_AsString(err_hint); + Py_DECREF(err_hint); + } + + PyErr_Clear(); + /* no elog here, we simply won't report the errhint, errposition etc */ +} + +/* * Get the given source line as a palloc'd string */ static char * @@ -451,6 +488,52 @@ get_source_line(const char *src, int lineno) return pnstrdup(s, next - s); } +void +PLy_exception_set_with_details(PyObject *excclass, ErrorData *edata) +{ + PyObject *args = NULL; + PyObject *error = NULL; + PyObject *err_detail = NULL; + PyObject *err_hint = NULL; + + args = Py_BuildValue("(s)", edata->message); + if (!args) + goto failure; + + /* create a new exception with the error message as the parameter */ + error = PyObject_CallObject(excclass, args); + if (!error) + goto failure; + + err_detail = PyString_FromString(edata->detail ? edata->detail : ""); + if (!err_detail) + goto failure; + + if (PyObject_SetAttrString(error, "detail", err_detail) == -1) + goto failure; + + err_hint = PyString_FromString(edata->hint ? edata->hint : ""); + if (!err_hint) + goto failure; + + if (PyObject_SetAttrString(error, "hint", err_hint) == -1) + goto failure; + + PyErr_SetObject(excclass, error); + + Py_DECREF(args); + Py_DECREF(error); + Py_DECREF(err_detail); + Py_DECREF(err_hint); + return; + +failure: + Py_XDECREF(args); + Py_XDECREF(error); + Py_XDECREF(err_detail); + Py_XDECREF(err_hint); + elog(ERROR, "could not convert error to Python exception"); +} /* call PyErr_SetString with a vprint interface and translation support */ void diff --git a/src/pl/plpython/plpy_elog.h b/src/pl/plpython/plpy_elog.h index 94725c2..5dd4ef7 100644 --- a/src/pl/plpython/plpy_elog.h +++ b/src/pl/plpython/plpy_elog.h @@ -17,4 +17,6 @@ extern void PLy_exception_set(PyObject *exc, const char *fmt,...) pg_attribute_p extern void PLy_exception_set_plural(PyObject *exc, const char *fmt_singular, const char *fmt_plural, unsigned long n,...) pg_attribute_printf(2, 5) pg_attribute_printf(3, 5); +extern void PLy_exception_set_with_details(PyObject *excclass, ErrorData *edata); + #endif /* PLPY_ELOG_H */ diff --git a/src/pl/plpython/plpy_plpymodule.c b/src/pl/plpython/plpy_plpymodule.c index f264746..3e7a20a 100644 --- a/src/pl/plpython/plpy_plpymodule.c +++ b/src/pl/plpython/plpy_plpymodule.c @@ -583,7 +583,7 @@ PLy_output_kw(volatile int level, PyObject *self, PyObject *args, PyObject *kw) edata = CopyErrorData(); FlushErrorState(); - PLy_spi_exception_set(PLy_exc_spi_error, edata); + PLy_exception_set_with_details(PLy_exc_error, edata); FreeErrorData(edata); return NULL; } diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c index 36ea728..c1989c0 100644 --- a/src/pl/plpython/plpy_spi.c +++ b/src/pl/plpython/plpy_spi.c @@ -30,6 +30,7 @@ static PyObject *PLy_spi_execute_query(char *query, long limit); static PyObject *PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit); static PyObject *PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status); +static void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata); /* prepare(query="select * from foo") diff --git a/src/pl/plpython/plpy_spi.h b/src/pl/plpython/plpy_spi.h index f9c54b8..b042794 100644 --- a/src/pl/plpython/plpy_spi.h +++ b/src/pl/plpython/plpy_spi.h @@ -22,7 +22,4 @@ extern void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner extern void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner); extern void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner); -/* raise and fill SPIError */ -extern void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata); - #endif /* PLPY_SPI_H */ -- 2.7.0