Extra attributes for ProgrammingError exception.

This commit is contained in:
Federico Di Gregorio 2006-01-05 08:13:03 +00:00
parent d5674253ca
commit 96ff591d79
6 changed files with 97 additions and 31 deletions

View File

@ -1,5 +1,9 @@
2006-01-05 Federico Di Gregorio <fog@initd.org> 2006-01-05 Federico Di Gregorio <fog@initd.org>
* 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 * setup.{cfg,py}: we now use pg_config to locate PostgreSQL libraries
and headers (modified patch from lbruno, see #70.) and headers (modified patch from lbruno, see #70.)

View File

@ -241,14 +241,15 @@ _psyco_curs_execute(cursorObject *self,
if (self->conn->async_cursor != NULL if (self->conn->async_cursor != NULL
&& self->conn->async_cursor != (PyObject*)self) { && self->conn->async_cursor != (PyObject*)self) {
pthread_mutex_unlock(&(self->conn->lock)); pthread_mutex_unlock(&(self->conn->lock));
PyErr_SetString(ProgrammingError, psyco_set_error(ProgrammingError, (PyObject*)self,
"asynchronous query already in execution"); "asynchronous query already in execution", NULL, NULL);
return 0; return 0;
} }
pthread_mutex_unlock(&(self->conn->lock)); pthread_mutex_unlock(&(self->conn->lock));
if (!PyObject_IsTrue(operation)) { 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; return 0;
} }
@ -334,7 +335,8 @@ _psyco_curs_execute(cursorObject *self,
if (!strcmp(s, "not enough arguments for format string") if (!strcmp(s, "not enough arguments for format string")
|| !strcmp(s, "not all arguments converted")) { || !strcmp(s, "not all arguments converted")) {
Dprintf("psyco_curs_execute: -> got a match"); Dprintf("psyco_curs_execute: -> got a match");
PyErr_SetString(ProgrammingError, s); psyco_set_error(ProgrammingError, (PyObject*)self,
s, NULL, NULL);
pe = 1; pe = 1;
} }
@ -403,18 +405,19 @@ psyco_curs_execute(cursorObject *self, PyObject *args, PyObject *kwargs)
if (self->name != NULL) { if (self->name != NULL) {
if (self->query != Py_None) { if (self->query != Py_None) {
PyErr_SetString(ProgrammingError, psyco_set_error(ProgrammingError, (PyObject*)self,
"can't call .execute() on named cursors more than once"); "can't call .execute() on named cursors more than once",
NULL, NULL);
return NULL; return NULL;
} }
if (self->conn->isolation_level == 0) { if (self->conn->isolation_level == 0) {
PyErr_SetString(ProgrammingError, psyco_set_error(ProgrammingError, (PyObject*)self,
"can't use a named cursor outside of transactions"); "can't use a named cursor outside of transactions", NULL, NULL);
return NULL; return NULL;
} }
if (self->conn->mark != self->mark) { if (self->conn->mark != self->mark) {
PyErr_SetString(ProgrammingError, psyco_set_error(ProgrammingError, (PyObject*)self,
"named cursor isn't valid anymore"); "named cursor isn't valid anymore", NULL, NULL);
return NULL; return NULL;
} }
} }
@ -449,8 +452,8 @@ psyco_curs_executemany(cursorObject *self, PyObject *args, PyObject *kwargs)
EXC_IF_CURS_CLOSED(self); EXC_IF_CURS_CLOSED(self);
if (self->name != NULL) { if (self->name != NULL) {
PyErr_SetString(ProgrammingError, psyco_set_error(ProgrammingError, (PyObject*)self,
"can't call .executemany() on named cursors"); "can't call .executemany() on named cursors", NULL, NULL);
return 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") if (!strcmp(s, "not enough arguments for format string")
|| !strcmp(s, "not all arguments converted")) { || !strcmp(s, "not all arguments converted")) {
Dprintf("psyco_curs_execute: -> got a match"); Dprintf("psyco_curs_execute: -> got a match");
PyErr_SetString(ProgrammingError, s); psyco_set_error(ProgrammingError, (PyObject*)self,
s, NULL, NULL);
pe = 1; pe = 1;
} }
@ -585,8 +589,8 @@ _psyco_curs_prefetch(cursorObject *self)
if (self->conn->async_cursor != NULL if (self->conn->async_cursor != NULL
&& self->conn->async_cursor != (PyObject*)self) { && self->conn->async_cursor != (PyObject*)self) {
pthread_mutex_unlock(&(self->conn->lock)); pthread_mutex_unlock(&(self->conn->lock));
PyErr_SetString(ProgrammingError, psyco_set_error(ProgrammingError, (PyObject*)self,
"asynchronous fetch by wrong cursor"); "asynchronous fetch by wrong cursor", NULL, NULL);
return -2; return -2;
} }
pthread_mutex_unlock(&(self->conn->lock)); pthread_mutex_unlock(&(self->conn->lock));
@ -880,8 +884,8 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
EXC_IF_CURS_CLOSED(self); EXC_IF_CURS_CLOSED(self);
if (self->name != NULL) { if (self->name != NULL) {
PyErr_SetString(ProgrammingError, psyco_set_error(ProgrammingError, (PyObject*)self,
"can't call .callproc() on named cursors"); "can't call .callproc() on named cursors", NULL, NULL);
return NULL; return NULL;
} }
@ -1003,14 +1007,14 @@ psyco_curs_scroll(cursorObject *self, PyObject *args, PyObject *kwargs)
} else if (strcmp( mode, "absolute") == 0) { } else if (strcmp( mode, "absolute") == 0) {
newpos = value; newpos = value;
} else { } else {
PyErr_SetString(ProgrammingError, psyco_set_error(ProgrammingError, (PyObject*)self,
"scroll mode must be 'relative' or 'absolute'"); "scroll mode must be 'relative' or 'absolute'", NULL, NULL);
return NULL; return NULL;
} }
if (newpos < 0 || newpos >= self->rowcount ) { if (newpos < 0 || newpos >= self->rowcount ) {
PyErr_SetString(PyExc_IndexError, psyco_set_error(ProgrammingError, (PyObject*)self,
"scroll destination out of bounds"); "scroll destination out of bounds", NULL, NULL);
return NULL; return NULL;
} }

View File

@ -108,7 +108,7 @@ microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt)
} }
/* else set the right exception and return NULL */ /* 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; return NULL;
} }

View File

@ -46,12 +46,15 @@
void void
pq_raise(connectionObject *conn, cursorObject *curs, PyObject *exc, char *msg) pq_raise(connectionObject *conn, cursorObject *curs, PyObject *exc, char *msg)
{ {
PyObject *pgc = (PyObject*)curs;
char *err = NULL; char *err = NULL;
char *err2 = NULL;
char *code = NULL; char *code = NULL;
char *buf = NULL;
if ((conn == NULL && curs == NULL) || (curs != NULL && conn == NULL)) { if ((conn == NULL && curs == NULL) || (curs != NULL && conn == NULL)) {
PyErr_SetString(Error, PyErr_SetString(Error, "psycopg went psycotic and raised a null error");
"psycopg went psycotic and raised a null error");
return; return;
} }
@ -104,18 +107,29 @@ pq_raise(connectionObject *conn, cursorObject *curs, PyObject *exc, char *msg)
} }
/* try to remove the initial "ERROR: " part from the postgresql error */ /* try to remove the initial "ERROR: " part from the postgresql error */
if (err && strlen(err) > 8) err = &(err[8]); 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 is not NULL, add it to the error message, after a '\n' */
if (msg && code) { 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) { 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 { 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 /* pq_set_critical, pq_resolve_critical - manage critical errors

View File

@ -100,6 +100,10 @@ typedef struct {
/* the Decimal type, used by the DECIMAL typecaster */ /* the Decimal type, used by the DECIMAL typecaster */
extern PyObject *decimalType; extern PyObject *decimalType;
/* some utility functions */
extern void psyco_set_error(PyObject *exc, PyObject *curs, char *msg,
char *pgerror, char *pgcode);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -366,6 +366,46 @@ psyco_errors_set(PyObject *type)
PyObject_SetAttrString(type, "NotSupportedError", NotSupportedError); 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 /* psyco_decimal_init
Initialize the module's pointer to the decimal type. */ Initialize the module's pointer to the decimal type. */