diff --git a/ChangeLog b/ChangeLog index 09bfbc0f..07b6884c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2006-01-05 Federico Di Gregorio + * psycopg/psycopgmodule.c (psyco_set_error): added function to set extra + parameters on ProgrammingError instances. Also modified all occurances of + PyErr_SetString(ProgrammingError,...) to psycopg_set_error(). + * setup.{cfg,py}: we now use pg_config to locate PostgreSQL libraries and headers (modified patch from lbruno, see #70.) diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c index 2aadc78b..d6776d9d 100644 --- a/psycopg/cursor_type.c +++ b/psycopg/cursor_type.c @@ -241,14 +241,15 @@ _psyco_curs_execute(cursorObject *self, if (self->conn->async_cursor != NULL && self->conn->async_cursor != (PyObject*)self) { pthread_mutex_unlock(&(self->conn->lock)); - PyErr_SetString(ProgrammingError, - "asynchronous query already in execution"); + psyco_set_error(ProgrammingError, (PyObject*)self, + "asynchronous query already in execution", NULL, NULL); return 0; } pthread_mutex_unlock(&(self->conn->lock)); if (!PyObject_IsTrue(operation)) { - PyErr_SetString(ProgrammingError, "can't execute an empty query"); + psyco_set_error(ProgrammingError, (PyObject*)self, + "can't execute an empty query", NULL, NULL); return 0; } @@ -334,7 +335,8 @@ _psyco_curs_execute(cursorObject *self, if (!strcmp(s, "not enough arguments for format string") || !strcmp(s, "not all arguments converted")) { Dprintf("psyco_curs_execute: -> got a match"); - PyErr_SetString(ProgrammingError, s); + psyco_set_error(ProgrammingError, (PyObject*)self, + s, NULL, NULL); pe = 1; } @@ -403,18 +405,19 @@ psyco_curs_execute(cursorObject *self, PyObject *args, PyObject *kwargs) if (self->name != NULL) { if (self->query != Py_None) { - PyErr_SetString(ProgrammingError, - "can't call .execute() on named cursors more than once"); + psyco_set_error(ProgrammingError, (PyObject*)self, + "can't call .execute() on named cursors more than once", + NULL, NULL); return NULL; } if (self->conn->isolation_level == 0) { - PyErr_SetString(ProgrammingError, - "can't use a named cursor outside of transactions"); + psyco_set_error(ProgrammingError, (PyObject*)self, + "can't use a named cursor outside of transactions", NULL, NULL); return NULL; } if (self->conn->mark != self->mark) { - PyErr_SetString(ProgrammingError, - "named cursor isn't valid anymore"); + psyco_set_error(ProgrammingError, (PyObject*)self, + "named cursor isn't valid anymore", NULL, NULL); return NULL; } } @@ -449,8 +452,8 @@ psyco_curs_executemany(cursorObject *self, PyObject *args, PyObject *kwargs) EXC_IF_CURS_CLOSED(self); if (self->name != NULL) { - PyErr_SetString(ProgrammingError, - "can't call .executemany() on named cursors"); + psyco_set_error(ProgrammingError, (PyObject*)self, + "can't call .executemany() on named cursors", NULL, NULL); return NULL; } @@ -533,7 +536,8 @@ psyco_curs_mogrify(cursorObject *self, PyObject *args, PyObject *kwargs) if (!strcmp(s, "not enough arguments for format string") || !strcmp(s, "not all arguments converted")) { Dprintf("psyco_curs_execute: -> got a match"); - PyErr_SetString(ProgrammingError, s); + psyco_set_error(ProgrammingError, (PyObject*)self, + s, NULL, NULL); pe = 1; } @@ -585,8 +589,8 @@ _psyco_curs_prefetch(cursorObject *self) if (self->conn->async_cursor != NULL && self->conn->async_cursor != (PyObject*)self) { pthread_mutex_unlock(&(self->conn->lock)); - PyErr_SetString(ProgrammingError, - "asynchronous fetch by wrong cursor"); + psyco_set_error(ProgrammingError, (PyObject*)self, + "asynchronous fetch by wrong cursor", NULL, NULL); return -2; } pthread_mutex_unlock(&(self->conn->lock)); @@ -880,8 +884,8 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs) EXC_IF_CURS_CLOSED(self); if (self->name != NULL) { - PyErr_SetString(ProgrammingError, - "can't call .callproc() on named cursors"); + psyco_set_error(ProgrammingError, (PyObject*)self, + "can't call .callproc() on named cursors", NULL, NULL); return NULL; } @@ -1003,14 +1007,14 @@ psyco_curs_scroll(cursorObject *self, PyObject *args, PyObject *kwargs) } else if (strcmp( mode, "absolute") == 0) { newpos = value; } else { - PyErr_SetString(ProgrammingError, - "scroll mode must be 'relative' or 'absolute'"); + psyco_set_error(ProgrammingError, (PyObject*)self, + "scroll mode must be 'relative' or 'absolute'", NULL, NULL); return NULL; } if (newpos < 0 || newpos >= self->rowcount ) { - PyErr_SetString(PyExc_IndexError, - "scroll destination out of bounds"); + psyco_set_error(ProgrammingError, (PyObject*)self, + "scroll destination out of bounds", NULL, NULL); return NULL; } diff --git a/psycopg/microprotocols.c b/psycopg/microprotocols.c index 4f97279c..73abbfc7 100644 --- a/psycopg/microprotocols.c +++ b/psycopg/microprotocols.c @@ -108,7 +108,7 @@ microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt) } /* else set the right exception and return NULL */ - PyErr_SetString(ProgrammingError, "can't adapt"); + psyco_set_error(ProgrammingError, NULL, "can't adapt", NULL, NULL); return NULL; } diff --git a/psycopg/pqpath.c b/psycopg/pqpath.c index 4ee87813..7bceed20 100644 --- a/psycopg/pqpath.c +++ b/psycopg/pqpath.c @@ -46,12 +46,15 @@ void pq_raise(connectionObject *conn, cursorObject *curs, PyObject *exc, char *msg) { + PyObject *pgc = (PyObject*)curs; + char *err = NULL; + char *err2 = NULL; char *code = NULL; + char *buf = NULL; if ((conn == NULL && curs == NULL) || (curs != NULL && conn == NULL)) { - PyErr_SetString(Error, - "psycopg went psycotic and raised a null error"); + PyErr_SetString(Error, "psycopg went psycotic and raised a null error"); return; } @@ -102,20 +105,31 @@ pq_raise(connectionObject *conn, cursorObject *curs, PyObject *exc, char *msg) else exc = ProgrammingError; } - - /* try to remove the initial "ERROR: " part from the postgresql error */ - if (err && strlen(err) > 8) err = &(err[8]); + /* try to remove the initial "ERROR: " part from the postgresql error */ + if (err && strlen(err) > 8) err2 = &(err[8]); + else err2 = err; + /* if msg is not NULL, add it to the error message, after a '\n' */ if (msg && code) { - PyErr_Format(exc, "[%s] %s\n%s", code, err, msg); + int len = strlen(code) + strlen(err) + strlen(msg) + 5; + if ((buf = PyMem_Malloc(len))) { + snprintf(buf, len, "[%s] %s\n%s", code, err2, msg); + psyco_set_error(exc, pgc, buf, err, code); + } } else if (msg) { - PyErr_Format(exc, "%s\n%s", err, msg); + int len = strlen(err) + strlen(msg) + 2; + if ((buf = PyMem_Malloc(len))) { + snprintf(buf, len, "%s\n%s", err2, msg); + psyco_set_error(exc, pgc, buf, err, code); + } } else { - PyErr_SetString(exc, err); + psyco_set_error(exc, pgc, err2, err, code); } + + if (buf != NULL) PyMem_Free(buf); } /* pq_set_critical, pq_resolve_critical - manage critical errors diff --git a/psycopg/psycopg.h b/psycopg/psycopg.h index 4da312e7..7a7a202b 100644 --- a/psycopg/psycopg.h +++ b/psycopg/psycopg.h @@ -99,7 +99,11 @@ typedef struct { /* the Decimal type, used by the DECIMAL typecaster */ extern PyObject *decimalType; - + +/* some utility functions */ +extern void psyco_set_error(PyObject *exc, PyObject *curs, char *msg, + char *pgerror, char *pgcode); + #ifdef __cplusplus } #endif diff --git a/psycopg/psycopgmodule.c b/psycopg/psycopgmodule.c index bef1e7a7..58a57f99 100644 --- a/psycopg/psycopgmodule.c +++ b/psycopg/psycopgmodule.c @@ -366,6 +366,46 @@ psyco_errors_set(PyObject *type) PyObject_SetAttrString(type, "NotSupportedError", NotSupportedError); } +/* psyco_error_new + + Create a new error of the given type with extra attributes. */ + +void +psyco_set_error(PyObject *exc, PyObject *curs, char *msg, + char *pgerror, char *pgcode) +{ + PyObject *t; + + PyObject *err = PyObject_CallFunction(exc, "s", msg); + + if (err) { + if (pgerror) { + t = PyString_FromString(pgerror); + } + else { + t = Py_None ; Py_INCREF(t); + } + PyObject_SetAttrString(err, "pgerror", t); + Py_DECREF(t); + + if (pgcode) { + t = PyString_FromString(pgcode); + } + else { + t = Py_None ; Py_INCREF(t); + } + PyObject_SetAttrString(err, "pgcode", t); + Py_DECREF(t); + + if (curs) + PyObject_SetAttrString(err, "cursor", curs); + else + PyObject_SetAttrString(err, "cursor", Py_None); + + PyErr_SetObject(exc, err); + } +} + /* psyco_decimal_init Initialize the module's pointer to the decimal type. */