mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-23 01:16:34 +03:00
Added error checking to _pq_fetch_tuples()
This commit is contained in:
parent
c1715f66fe
commit
20f714f17c
122
psycopg/pqpath.c
122
psycopg/pqpath.c
|
@ -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;
|
||||||
PyMem_Free(dsize);
|
rv = 0;
|
||||||
Py_UNBLOCK_THREADS;
|
|
||||||
}
|
exit:
|
||||||
|
PyMem_Free(dsize);
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user