static void handleSyncLoss(PGconn *conn, char id, int msgLength);
static int getRowDescriptions(PGconn *conn);
-static int getParamDescriptions(PGconn *conn);
+static int getParamDescriptions(PGconn *conn, int msgLength);
static int getAnotherTuple(PGconn *conn, int msgLength);
static int getParameterStatus(PGconn *conn);
static int getNotify(PGconn *conn);
return;
break;
case 'T': /* Row Description */
- if (conn->result == NULL ||
- conn->queryclass == PGQUERY_DESCRIBE)
+ if (conn->result != NULL &&
+ conn->result->resultStatus == PGRES_FATAL_ERROR)
+ {
+ /*
+ * We've already choked for some reason. Just discard
+ * the data till we get to the end of the query.
+ */
+ conn->inCursor += msgLength;
+ }
+ else if (conn->result == NULL ||
+ conn->queryclass == PGQUERY_DESCRIBE)
{
/* First 'T' in a query sequence */
if (getRowDescriptions(conn))
}
break;
case 't': /* Parameter Description */
- if (getParamDescriptions(conn))
+ if (getParamDescriptions(conn, msgLength))
return;
- break;
+ /* getParamDescriptions() moves inStart itself */
+ continue;
case 'D': /* Data Row */
if (conn->result != NULL &&
conn->result->resultStatus == PGRES_TUPLES_OK)
* that shouldn't happen often, since 't' messages usually fit in a packet.
*/
static int
-getParamDescriptions(PGconn *conn)
+getParamDescriptions(PGconn *conn, int msgLength)
{
PGresult *result;
int nparams;
int i;
+ const char *errmsg = NULL;
result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK);
if (!result)
- goto failure;
+ goto advance_and_error;
/* parseInput already read the 't' label and message length. */
/* the next two bytes are the number of parameters */
if (pqGetInt(&(result->numParameters), 2, conn))
- goto failure;
+ goto not_enough_data;
nparams = result->numParameters;
/* allocate space for the parameter descriptors */
result->paramDescs = (PGresParamDesc *)
pqResultAlloc(result, nparams * sizeof(PGresParamDesc), TRUE);
if (!result->paramDescs)
- goto failure;
+ goto advance_and_error;
MemSet(result->paramDescs, 0, nparams * sizeof(PGresParamDesc));
}
int typid;
if (pqGetInt(&typid, 4, conn))
- goto failure;
+ goto not_enough_data;
result->paramDescs[i].typid = typid;
}
/* Success! */
conn->result = result;
+
+ /* Advance inStart to show that the "t" message has been processed. */
+ conn->inStart = conn->inCursor;
+
return 0;
-failure:
+not_enough_data:
PQclear(result);
return EOF;
+
+advance_and_error:
+ /* Discard unsaved result, if any */
+ if (result && result != conn->result)
+ PQclear(result);
+
+ /* Discard the failed message by pretending we read it */
+ conn->inStart += 5 + msgLength;
+
+ /*
+ * Replace partially constructed result with an error result. First
+ * discard the old result to try to win back some memory.
+ */
+ pqClearAsyncResult(conn);
+
+ /*
+ * If preceding code didn't provide an error message, assume "out of
+ * memory" was meant. The advantage of having this special case is that
+ * freeing the old result first greatly improves the odds that gettext()
+ * will succeed in providing a translation.
+ */
+ if (!errmsg)
+ errmsg = libpq_gettext("out of memory");
+ printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
+ pqSaveErrorResult(conn);
+
+ return 0;
}
/*