Skip to content

Commit 5493ecc

Browse files
committed
Adjust error-handling logic in libpq. For the first time, libpq copes
sanely with running out of memory for a query result.
1 parent 9090306 commit 5493ecc

File tree

1 file changed

+25
-12
lines changed

1 file changed

+25
-12
lines changed

src/interfaces/libpq/fe-exec.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.135 2003/05/08 18:16:37 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.136 2003/05/26 20:05:20 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -55,7 +55,7 @@ static void parseInput(PGconn *conn);
5555
static void handleSendFailure(PGconn *conn);
5656
static void handleSyncLoss(PGconn *conn, char id, int msgLength);
5757
static int getRowDescriptions(PGconn *conn);
58-
static int getAnotherTuple(PGconn *conn);
58+
static int getAnotherTuple(PGconn *conn, int msgLength);
5959
static int getParameterStatus(PGconn *conn);
6060
static int getNotify(PGconn *conn);
6161

@@ -835,17 +835,28 @@ parseInput(PGconn *conn)
835835
}
836836
break;
837837
case 'D': /* Data Row */
838-
if (conn->result != NULL)
838+
if (conn->result != NULL &&
839+
conn->result->resultStatus == PGRES_TUPLES_OK)
839840
{
840841
/* Read another tuple of a normal query response */
841-
if (getAnotherTuple(conn))
842+
if (getAnotherTuple(conn, msgLength))
842843
return;
843844
}
845+
else if (conn->result != NULL &&
846+
conn->result->resultStatus == PGRES_FATAL_ERROR)
847+
{
848+
/*
849+
* We've already choked for some reason. Just discard
850+
* tuples till we get to the end of the query.
851+
*/
852+
conn->inCursor += msgLength;
853+
}
844854
else
845855
{
846-
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
856+
/* Set up to report error at end of query */
857+
printfPQExpBuffer(&conn->errorMessage,
847858
libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)\n"));
848-
DONOTICE(conn, noticeWorkspace);
859+
saveErrorResult(conn);
849860
/* Discard the unexpected message */
850861
conn->inCursor += msgLength;
851862
}
@@ -888,6 +899,7 @@ parseInput(PGconn *conn)
888899
id);
889900
/* build an error result holding the error message */
890901
saveErrorResult(conn);
902+
/* not sure if we will see more, so go to ready state */
891903
conn->asyncStatus = PGASYNC_READY;
892904
/* Discard the unexpected message */
893905
conn->inCursor += msgLength;
@@ -931,6 +943,7 @@ handleSyncLoss(PGconn *conn, char id, int msgLength)
931943
pqsecure_close(conn);
932944
closesocket(conn->sock);
933945
conn->sock = -1;
946+
conn->asyncStatus = PGASYNC_READY; /* drop out of GetResult wait loop */
934947
}
935948

936949
/*
@@ -1023,7 +1036,7 @@ getRowDescriptions(PGconn *conn)
10231036
*/
10241037

10251038
static int
1026-
getAnotherTuple(PGconn *conn)
1039+
getAnotherTuple(PGconn *conn, int msgLength)
10271040
{
10281041
PGresult *result = conn->result;
10291042
int nfields = result->numAttributes;
@@ -1050,12 +1063,11 @@ getAnotherTuple(PGconn *conn)
10501063
if (tupnfields != nfields)
10511064
{
10521065
/* Replace partially constructed result with an error result */
1053-
pqClearAsyncResult(conn);
10541066
printfPQExpBuffer(&conn->errorMessage,
10551067
libpq_gettext("unexpected field count in D message\n"));
10561068
saveErrorResult(conn);
1057-
conn->asyncStatus = PGASYNC_READY;
10581069
/* Discard the failed message by pretending we read it */
1070+
conn->inCursor = conn->inStart + 5 + msgLength;
10591071
return 0;
10601072
}
10611073

@@ -1102,14 +1114,15 @@ getAnotherTuple(PGconn *conn)
11021114

11031115
/*
11041116
* we do NOT use saveErrorResult() here, because of the likelihood
1105-
* that there's not enough memory to concatenate messages...
1117+
* that there's not enough memory to concatenate messages. Instead,
1118+
* discard the old result first to try to win back some memory.
11061119
*/
11071120
pqClearAsyncResult(conn);
11081121
printfPQExpBuffer(&conn->errorMessage,
1109-
libpq_gettext("out of memory\n"));
1122+
libpq_gettext("out of memory for query result\n"));
11101123
conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
1111-
conn->asyncStatus = PGASYNC_READY;
11121124
/* Discard the failed message by pretending we read it */
1125+
conn->inCursor = conn->inStart + 5 + msgLength;
11131126
return 0;
11141127
}
11151128

0 commit comments

Comments
 (0)