Adjust error-handling logic in libpq. For the first time, libpq copes

sanely with running out of memory for a query result.
This commit is contained in:
Tom Lane 2003-05-26 20:05:20 +00:00
parent 90903069e9
commit 5493ecc3a5
1 changed files with 25 additions and 12 deletions

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.135 2003/05/08 18:16:37 tgl Exp $ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.136 2003/05/26 20:05:20 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -55,7 +55,7 @@ static void parseInput(PGconn *conn);
static void handleSendFailure(PGconn *conn); static void handleSendFailure(PGconn *conn);
static void handleSyncLoss(PGconn *conn, char id, int msgLength); static void handleSyncLoss(PGconn *conn, char id, int msgLength);
static int getRowDescriptions(PGconn *conn); static int getRowDescriptions(PGconn *conn);
static int getAnotherTuple(PGconn *conn); static int getAnotherTuple(PGconn *conn, int msgLength);
static int getParameterStatus(PGconn *conn); static int getParameterStatus(PGconn *conn);
static int getNotify(PGconn *conn); static int getNotify(PGconn *conn);
@ -835,17 +835,28 @@ parseInput(PGconn *conn)
} }
break; break;
case 'D': /* Data Row */ case 'D': /* Data Row */
if (conn->result != NULL) if (conn->result != NULL &&
conn->result->resultStatus == PGRES_TUPLES_OK)
{ {
/* Read another tuple of a normal query response */ /* Read another tuple of a normal query response */
if (getAnotherTuple(conn)) if (getAnotherTuple(conn, msgLength))
return; return;
} }
else if (conn->result != NULL &&
conn->result->resultStatus == PGRES_FATAL_ERROR)
{
/*
* We've already choked for some reason. Just discard
* tuples till we get to the end of the query.
*/
conn->inCursor += msgLength;
}
else else
{ {
snprintf(noticeWorkspace, sizeof(noticeWorkspace), /* Set up to report error at end of query */
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)\n")); libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)\n"));
DONOTICE(conn, noticeWorkspace); saveErrorResult(conn);
/* Discard the unexpected message */ /* Discard the unexpected message */
conn->inCursor += msgLength; conn->inCursor += msgLength;
} }
@ -888,6 +899,7 @@ parseInput(PGconn *conn)
id); id);
/* build an error result holding the error message */ /* build an error result holding the error message */
saveErrorResult(conn); saveErrorResult(conn);
/* not sure if we will see more, so go to ready state */
conn->asyncStatus = PGASYNC_READY; conn->asyncStatus = PGASYNC_READY;
/* Discard the unexpected message */ /* Discard the unexpected message */
conn->inCursor += msgLength; conn->inCursor += msgLength;
@ -931,6 +943,7 @@ handleSyncLoss(PGconn *conn, char id, int msgLength)
pqsecure_close(conn); pqsecure_close(conn);
closesocket(conn->sock); closesocket(conn->sock);
conn->sock = -1; conn->sock = -1;
conn->asyncStatus = PGASYNC_READY; /* drop out of GetResult wait loop */
} }
/* /*
@ -1023,7 +1036,7 @@ getRowDescriptions(PGconn *conn)
*/ */
static int static int
getAnotherTuple(PGconn *conn) getAnotherTuple(PGconn *conn, int msgLength)
{ {
PGresult *result = conn->result; PGresult *result = conn->result;
int nfields = result->numAttributes; int nfields = result->numAttributes;
@ -1050,12 +1063,11 @@ getAnotherTuple(PGconn *conn)
if (tupnfields != nfields) if (tupnfields != nfields)
{ {
/* Replace partially constructed result with an error result */ /* Replace partially constructed result with an error result */
pqClearAsyncResult(conn);
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("unexpected field count in D message\n")); libpq_gettext("unexpected field count in D message\n"));
saveErrorResult(conn); saveErrorResult(conn);
conn->asyncStatus = PGASYNC_READY;
/* Discard the failed message by pretending we read it */ /* Discard the failed message by pretending we read it */
conn->inCursor = conn->inStart + 5 + msgLength;
return 0; return 0;
} }
@ -1102,14 +1114,15 @@ outOfMemory:
/* /*
* we do NOT use saveErrorResult() here, because of the likelihood * we do NOT use saveErrorResult() here, because of the likelihood
* that there's not enough memory to concatenate messages... * that there's not enough memory to concatenate messages. Instead,
* discard the old result first to try to win back some memory.
*/ */
pqClearAsyncResult(conn); pqClearAsyncResult(conn);
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory for query result\n"));
conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
conn->asyncStatus = PGASYNC_READY;
/* Discard the failed message by pretending we read it */ /* Discard the failed message by pretending we read it */
conn->inCursor = conn->inStart + 5 + msgLength;
return 0; return 0;
} }