Added error checking to _pq_fetch_tuples()

This commit is contained in:
Daniele Varrazzo 2011-02-23 00:31:38 +00:00
parent c1715f66fe
commit 20f714f17c

View File

@ -893,15 +893,19 @@ pq_get_last_result(connectionObject *conn)
1 - result from backend (possibly data is ready) 1 - result from backend (possibly data is ready)
*/ */
static void static int
_pq_fetch_tuples(cursorObject *curs) _pq_fetch_tuples(cursorObject *curs)
{ {
int i, *dsize = NULL; int i, *dsize = NULL;
int pgnfields; int pgnfields;
int pgbintuples; int pgbintuples;
int rv = -1;
PyObject *description = NULL;
PyObject *casts = NULL;
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&(curs->conn->lock)); pthread_mutex_lock(&(curs->conn->lock));
Py_END_ALLOW_THREADS;
pgnfields = PQnfields(curs->pgres); pgnfields = PQnfields(curs->pgres);
pgbintuples = PQbinaryTuples(curs->pgres); pgbintuples = PQbinaryTuples(curs->pgres);
@ -909,20 +913,20 @@ _pq_fetch_tuples(cursorObject *curs)
curs->notuples = 0; curs->notuples = 0;
/* create the tuple for description and typecasting */ /* create the tuple for description and typecasting */
Py_BLOCK_THREADS; Py_CLEAR(curs->description);
Py_XDECREF(curs->description); Py_CLEAR(curs->casts);
Py_XDECREF(curs->casts); if (!(description = PyTuple_New(pgnfields))) { goto exit; }
curs->description = PyTuple_New(pgnfields); if (!(casts = PyTuple_New(pgnfields))) { goto exit; }
curs->casts = PyTuple_New(pgnfields);
curs->columns = pgnfields; curs->columns = pgnfields;
Py_UNBLOCK_THREADS;
/* calculate the display size for each column (cpu intensive, can be /* calculate the display size for each column (cpu intensive, can be
switched off at configuration time) */ switched off at configuration time) */
#ifdef PSYCOPG_DISPLAY_SIZE #ifdef PSYCOPG_DISPLAY_SIZE
Py_BLOCK_THREADS; if (!(dsize = PyMem_New(int, pgnfields))) {
dsize = (int *)PyMem_Malloc(pgnfields * sizeof(int)); PyErr_NoMemory();
Py_UNBLOCK_THREADS; goto exit;
}
Py_BEGIN_ALLOW_THREADS;
if (dsize != NULL) { if (dsize != NULL) {
int j, len; int j, len;
for (i=0; i < pgnfields; i++) { for (i=0; i < pgnfields; i++) {
@ -935,6 +939,7 @@ _pq_fetch_tuples(cursorObject *curs)
} }
} }
} }
Py_END_ALLOW_THREADS;
#endif #endif
/* calculate various parameters and typecasters */ /* calculate various parameters and typecasters */
@ -943,13 +948,11 @@ _pq_fetch_tuples(cursorObject *curs)
int fsize = PQfsize(curs->pgres, i); int fsize = PQfsize(curs->pgres, i);
int fmod = PQfmod(curs->pgres, i); int fmod = PQfmod(curs->pgres, i);
PyObject *dtitem; PyObject *dtitem = NULL;
PyObject *type; PyObject *type = NULL;
PyObject *cast = NULL; PyObject *cast = NULL;
Py_BLOCK_THREADS; if (!(dtitem = PyTuple_New(7))) { goto exit; }
dtitem = PyTuple_New(7);
/* fill the right cast function by accessing three different dictionaries: /* fill the right cast function by accessing three different dictionaries:
- the per-cursor dictionary, if available (can be NULL or None) - the per-cursor dictionary, if available (can be NULL or None)
@ -957,7 +960,9 @@ _pq_fetch_tuples(cursorObject *curs)
- the global dictionary (at module level) - the global dictionary (at module level)
if we get no defined cast use the default one */ if we get no defined cast use the default one */
type = PyInt_FromLong(ftype); if (!(type = PyInt_FromLong(ftype))) {
goto err_for;
}
Dprintf("_pq_fetch_tuples: looking for cast %d:", ftype); Dprintf("_pq_fetch_tuples: looking for cast %d:", ftype);
cast = curs_get_cast(curs, type); cast = curs_get_cast(curs, type);
@ -976,16 +981,25 @@ _pq_fetch_tuples(cursorObject *curs)
cast, Bytes_AS_STRING(((typecastObject*)cast)->name), cast, Bytes_AS_STRING(((typecastObject*)cast)->name),
PQftype(curs->pgres,i)); PQftype(curs->pgres,i));
Py_INCREF(cast); Py_INCREF(cast);
PyTuple_SET_ITEM(curs->casts, i, cast); PyTuple_SET_ITEM(casts, i, cast);
/* 1/ fill the other fields */ /* 1/ fill the other fields */
PyTuple_SET_ITEM(dtitem, 0, {
conn_text_from_chars(curs->conn, PQfname(curs->pgres, i))); PyObject *tmp;
if (!(tmp = conn_text_from_chars(
curs->conn, PQfname(curs->pgres, i)))) {
goto err_for;
}
PyTuple_SET_ITEM(dtitem, 0, tmp);
}
PyTuple_SET_ITEM(dtitem, 1, type); PyTuple_SET_ITEM(dtitem, 1, type);
type = NULL;
/* 2/ display size is the maximum size of this field result tuples. */ /* 2/ display size is the maximum size of this field result tuples. */
if (dsize && dsize[i] >= 0) { if (dsize && dsize[i] >= 0) {
PyTuple_SET_ITEM(dtitem, 2, PyInt_FromLong(dsize[i])); PyObject *tmp;
if (!(tmp = PyInt_FromLong(dsize[i]))) { goto err_for; }
PyTuple_SET_ITEM(dtitem, 2, tmp);
} }
else { else {
Py_INCREF(Py_None); Py_INCREF(Py_None);
@ -996,21 +1010,35 @@ _pq_fetch_tuples(cursorObject *curs)
if (fmod > 0) fmod = fmod - sizeof(int); if (fmod > 0) fmod = fmod - sizeof(int);
if (fsize == -1) { if (fsize == -1) {
if (ftype == NUMERICOID) { if (ftype == NUMERICOID) {
PyTuple_SET_ITEM(dtitem, 3, PyObject *tmp;
PyInt_FromLong((fmod >> 16) & 0xFFFF)); if (!(tmp = PyInt_FromLong((fmod >> 16)))) { goto err_for; }
PyTuple_SET_ITEM(dtitem, 3, tmp);
} }
else { /* If variable length record, return maximum size */ else { /* If variable length record, return maximum size */
PyTuple_SET_ITEM(dtitem, 3, PyInt_FromLong(fmod)); PyObject *tmp;
if (!(tmp = PyInt_FromLong(fmod))) { goto err_for; }
PyTuple_SET_ITEM(dtitem, 3, tmp);
} }
} }
else { else {
PyTuple_SET_ITEM(dtitem, 3, PyInt_FromLong(fsize)); PyObject *tmp;
if (!(tmp = PyInt_FromLong(fsize))) { goto err_for; }
PyTuple_SET_ITEM(dtitem, 3, tmp);
} }
/* 4,5/ scale and precision */ /* 4,5/ scale and precision */
if (ftype == NUMERICOID) { if (ftype == NUMERICOID) {
PyTuple_SET_ITEM(dtitem, 4, PyInt_FromLong((fmod >> 16) & 0xFFFF)); PyObject *tmp;
PyTuple_SET_ITEM(dtitem, 5, PyInt_FromLong(fmod & 0xFFFF));
if (!(tmp = PyInt_FromLong((fmod >> 16) & 0xFFFF))) {
goto err_for;
}
PyTuple_SET_ITEM(dtitem, 4, tmp);
if (!(tmp = PyInt_FromLong(fmod & 0xFFFF))) {
PyTuple_SET_ITEM(dtitem, 5, tmp);
}
PyTuple_SET_ITEM(dtitem, 5, tmp);
} }
else { else {
Py_INCREF(Py_None); Py_INCREF(Py_None);
@ -1026,30 +1054,36 @@ _pq_fetch_tuples(cursorObject *curs)
/* Convert into a namedtuple if available */ /* Convert into a namedtuple if available */
if (Py_None != psyco_DescriptionType) { if (Py_None != psyco_DescriptionType) {
PyObject *tmp = dtitem; PyObject *tmp = dtitem;
if ((dtitem = PyObject_CallObject(psyco_DescriptionType, tmp))) { dtitem = PyObject_CallObject(psyco_DescriptionType, tmp);
Py_DECREF(tmp); Py_DECREF(tmp);
} if (NULL == dtitem) { goto err_for; }
else {
/* FIXME: this function is painfully missing any error check.
* The caller doesn't expect them, so swallow it. */
PyErr_Clear();
dtitem = tmp;
}
} }
PyTuple_SET_ITEM(curs->description, i, dtitem); PyTuple_SET_ITEM(description, i, dtitem);
dtitem = NULL;
Py_UNBLOCK_THREADS; continue;
err_for:
Py_XDECREF(type);
Py_XDECREF(dtitem);
goto exit;
} }
if (dsize) { curs->description = description; description = NULL;
Py_BLOCK_THREADS; curs->casts = casts; casts = NULL;
rv = 0;
exit:
PyMem_Free(dsize); PyMem_Free(dsize);
Py_UNBLOCK_THREADS; Py_XDECREF(description);
} Py_XDECREF(casts);
Py_BEGIN_ALLOW_THREADS;
pthread_mutex_unlock(&(curs->conn->lock)); pthread_mutex_unlock(&(curs->conn->lock));
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
return rv;
} }
static int static int
@ -1312,7 +1346,7 @@ pq_fetch(cursorObject *curs)
case PGRES_TUPLES_OK: case PGRES_TUPLES_OK:
Dprintf("pq_fetch: data from a SELECT (got tuples)"); Dprintf("pq_fetch: data from a SELECT (got tuples)");
curs->rowcount = PQntuples(curs->pgres); curs->rowcount = PQntuples(curs->pgres);
_pq_fetch_tuples(curs); ex = 0; if (0 == _pq_fetch_tuples(curs)) { ex = 0; }
/* don't clear curs->pgres, because it contains the results! */ /* don't clear curs->pgres, because it contains the results! */
break; break;