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>
* 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.)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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. */