Commit ffa2e467 authored by Tom Lane's avatar Tom Lane

In libpq, always append new error messages to conn->errorMessage.

Previously, we had an undisciplined mish-mash of printfPQExpBuffer and
appendPQExpBuffer calls to report errors within libpq.  This commit
establishes a uniform rule that appendPQExpBuffer[Str] should be used.
conn->errorMessage is reset only at the start of an application request,
and then accumulates messages till we're done.  We can remove no less
than three different ad-hoc mechanisms that were used to get the effect
of concatenation of error messages within a sequence of operations.

Although this makes things quite a bit cleaner conceptually, the main
reason to do it is to make the world safer for the multiple-target-host
feature that was added awhile back.  Previously, there were many cases
in which an error occurring during an individual host connection attempt
would wipe out the record of what had happened during previous attempts.
(The reporting is still inadequate, in that it can be hard to tell which
host got the failure, but that seems like a matter for a separate commit.)

Currently, lo_import and lo_export contain exceptions to the "never
use printfPQExpBuffer" rule.  If we changed them, we'd risk reporting
an incidental lo_close failure before the actual read or write
failure, which would be confusing, not least because lo_close happened
after the main failure.  We could improve this by inventing an
internal version of lo_close that doesn't reset the errorMessage; but
we'd also need a version of PQfn() that does that, and it didn't quite
seem worth the trouble for now.

Discussion: https://postgr.es/m/BN6PR05MB3492948E4FD76C156E747E8BC9160@BN6PR05MB3492.namprd05.prod.outlook.com
parent ce6a71fa
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -46,7 +46,6 @@ void ...@@ -46,7 +46,6 @@ void
pg_GSS_error(const char *mprefix, PGconn *conn, pg_GSS_error(const char *mprefix, PGconn *conn,
OM_uint32 maj_stat, OM_uint32 min_stat) OM_uint32 maj_stat, OM_uint32 min_stat)
{ {
resetPQExpBuffer(&conn->errorMessage);
appendPQExpBuffer(&conn->errorMessage, "%s:", mprefix); appendPQExpBuffer(&conn->errorMessage, "%s:", mprefix);
pg_GSS_error_int(&conn->errorMessage, maj_stat, GSS_C_GSS_CODE); pg_GSS_error_int(&conn->errorMessage, maj_stat, GSS_C_GSS_CODE);
appendPQExpBufferChar(&conn->errorMessage, ':'); appendPQExpBufferChar(&conn->errorMessage, ':');
...@@ -94,8 +93,8 @@ pg_GSS_load_servicename(PGconn *conn) ...@@ -94,8 +93,8 @@ pg_GSS_load_servicename(PGconn *conn)
host = PQhost(conn); host = PQhost(conn);
if (!(host && host[0] != '\0')) if (!(host && host[0] != '\0'))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("host name must be specified\n")); libpq_gettext("host name must be specified\n"));
return STATUS_ERROR; return STATUS_ERROR;
} }
...@@ -107,8 +106,8 @@ pg_GSS_load_servicename(PGconn *conn) ...@@ -107,8 +106,8 @@ pg_GSS_load_servicename(PGconn *conn)
temp_gbuf.value = (char *) malloc(maxlen); temp_gbuf.value = (char *) malloc(maxlen);
if (!temp_gbuf.value) if (!temp_gbuf.value)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return STATUS_ERROR; return STATUS_ERROR;
} }
snprintf(temp_gbuf.value, maxlen, "%s@%s", snprintf(temp_gbuf.value, maxlen, "%s@%s",
......
This diff is collapsed.
...@@ -379,8 +379,8 @@ pqCheckOutBufferSpace(size_t bytes_needed, PGconn *conn) ...@@ -379,8 +379,8 @@ pqCheckOutBufferSpace(size_t bytes_needed, PGconn *conn)
} }
/* realloc failed. Probably out of memory */ /* realloc failed. Probably out of memory */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
"cannot allocate memory for output buffer\n"); "cannot allocate memory for output buffer\n");
return EOF; return EOF;
} }
...@@ -473,8 +473,8 @@ pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn) ...@@ -473,8 +473,8 @@ pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn)
} }
/* realloc failed. Probably out of memory */ /* realloc failed. Probably out of memory */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
"cannot allocate memory for input buffer\n"); "cannot allocate memory for input buffer\n");
return EOF; return EOF;
} }
...@@ -619,8 +619,8 @@ pqReadData(PGconn *conn) ...@@ -619,8 +619,8 @@ pqReadData(PGconn *conn)
if (conn->sock == PGINVALID_SOCKET) if (conn->sock == PGINVALID_SOCKET)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("connection not open\n")); libpq_gettext("connection not open\n"));
return -1; return -1;
} }
...@@ -798,10 +798,10 @@ retry4: ...@@ -798,10 +798,10 @@ retry4:
* means the connection has been closed. Cope. * means the connection has been closed. Cope.
*/ */
definitelyEOF: definitelyEOF:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("server closed the connection unexpectedly\n" libpq_gettext("server closed the connection unexpectedly\n"
"\tThis probably means the server terminated abnormally\n" "\tThis probably means the server terminated abnormally\n"
"\tbefore or while processing the request.\n")); "\tbefore or while processing the request.\n"));
/* Come here if lower-level code already set a suitable errorMessage */ /* Come here if lower-level code already set a suitable errorMessage */
definitelyFailed: definitelyFailed:
...@@ -836,6 +836,7 @@ pqSendSome(PGconn *conn, int len) ...@@ -836,6 +836,7 @@ pqSendSome(PGconn *conn, int len)
{ {
char *ptr = conn->outBuffer; char *ptr = conn->outBuffer;
int remaining = conn->outCount; int remaining = conn->outCount;
int oldmsglen = conn->errorMessage.len;
int result = 0; int result = 0;
/* /*
...@@ -862,13 +863,10 @@ pqSendSome(PGconn *conn, int len) ...@@ -862,13 +863,10 @@ pqSendSome(PGconn *conn, int len)
if (conn->sock == PGINVALID_SOCKET) if (conn->sock == PGINVALID_SOCKET)
{ {
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("connection not open\n"));
conn->write_failed = true; conn->write_failed = true;
/* Transfer error message to conn->write_err_msg, if possible */ /* Insert error message into conn->write_err_msg, if possible */
/* (strdup failure is OK, we'll cope later) */ /* (strdup failure is OK, we'll cope later) */
conn->write_err_msg = strdup(conn->errorMessage.data); conn->write_err_msg = strdup(libpq_gettext("connection not open\n"));
resetPQExpBuffer(&conn->errorMessage);
/* Discard queued data; no chance it'll ever be sent */ /* Discard queued data; no chance it'll ever be sent */
conn->outCount = 0; conn->outCount = 0;
return 0; return 0;
...@@ -915,14 +913,16 @@ pqSendSome(PGconn *conn, int len) ...@@ -915,14 +913,16 @@ pqSendSome(PGconn *conn, int len)
* Transfer error message to conn->write_err_msg, if * Transfer error message to conn->write_err_msg, if
* possible (strdup failure is OK, we'll cope later). * possible (strdup failure is OK, we'll cope later).
* *
* Note: this assumes that pqsecure_write and its children * We only want to transfer whatever has been appended to
* will overwrite not append to conn->errorMessage. If * conn->errorMessage since we entered this routine.
* that's ever changed, we could remember the length of
* conn->errorMessage at entry to this routine, and then
* save and delete just what was appended.
*/ */
conn->write_err_msg = strdup(conn->errorMessage.data); if (!PQExpBufferBroken(&conn->errorMessage))
resetPQExpBuffer(&conn->errorMessage); {
conn->write_err_msg = strdup(conn->errorMessage.data +
oldmsglen);
conn->errorMessage.len = oldmsglen;
conn->errorMessage.data[oldmsglen] = '\0';
}
/* Discard queued data; no chance it'll ever be sent */ /* Discard queued data; no chance it'll ever be sent */
conn->outCount = 0; conn->outCount = 0;
...@@ -1056,8 +1056,8 @@ pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time) ...@@ -1056,8 +1056,8 @@ pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time)
if (result == 0) if (result == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("timeout expired\n")); libpq_gettext("timeout expired\n"));
return 1; return 1;
} }
...@@ -1101,8 +1101,8 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time) ...@@ -1101,8 +1101,8 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time)
return -1; return -1;
if (conn->sock == PGINVALID_SOCKET) if (conn->sock == PGINVALID_SOCKET)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("invalid socket\n")); libpq_gettext("invalid socket\n"));
return -1; return -1;
} }
...@@ -1124,7 +1124,7 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time) ...@@ -1124,7 +1124,7 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time)
{ {
char sebuf[PG_STRERROR_R_BUFLEN]; char sebuf[PG_STRERROR_R_BUFLEN];
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("select() failed: %s\n"), libpq_gettext("select() failed: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
} }
......
...@@ -83,7 +83,7 @@ pqSetenvPoll(PGconn *conn) ...@@ -83,7 +83,7 @@ pqSetenvPoll(PGconn *conn)
return PGRES_POLLING_OK; return PGRES_POLLING_OK;
default: default:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("invalid setenv state %c, probably indicative of memory corruption\n"), libpq_gettext("invalid setenv state %c, probably indicative of memory corruption\n"),
conn->setenv_state); conn->setenv_state);
goto error_return; goto error_return;
...@@ -380,7 +380,7 @@ pqSetenvPoll(PGconn *conn) ...@@ -380,7 +380,7 @@ pqSetenvPoll(PGconn *conn)
} }
default: default:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("invalid state %c, " libpq_gettext("invalid state %c, "
"probably indicative of memory corruption\n"), "probably indicative of memory corruption\n"),
conn->setenv_state); conn->setenv_state);
...@@ -493,8 +493,8 @@ pqParseInput2(PGconn *conn) ...@@ -493,8 +493,8 @@ pqParseInput2(PGconn *conn)
PGRES_COMMAND_OK); PGRES_COMMAND_OK);
if (!conn->result) if (!conn->result)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory")); libpq_gettext("out of memory"));
pqSaveErrorResult(conn); pqSaveErrorResult(conn);
} }
} }
...@@ -528,8 +528,8 @@ pqParseInput2(PGconn *conn) ...@@ -528,8 +528,8 @@ pqParseInput2(PGconn *conn)
PGRES_EMPTY_QUERY); PGRES_EMPTY_QUERY);
if (!conn->result) if (!conn->result)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory")); libpq_gettext("out of memory"));
pqSaveErrorResult(conn); pqSaveErrorResult(conn);
} }
} }
...@@ -622,7 +622,7 @@ pqParseInput2(PGconn *conn) ...@@ -622,7 +622,7 @@ pqParseInput2(PGconn *conn)
* never arrives from the server during protocol 2.0. * never arrives from the server during protocol 2.0.
*/ */
default: default:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("unexpected response from server; first received character was \"%c\"\n"), libpq_gettext("unexpected response from server; first received character was \"%c\"\n"),
id); id);
/* build an error result holding the error message */ /* build an error result holding the error message */
...@@ -754,7 +754,7 @@ advance_and_error: ...@@ -754,7 +754,7 @@ advance_and_error:
if (!errmsg) if (!errmsg)
errmsg = libpq_gettext("out of memory for query result"); errmsg = libpq_gettext("out of memory for query result");
printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
/* /*
* XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can * XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can
...@@ -929,7 +929,7 @@ set_error_result: ...@@ -929,7 +929,7 @@ set_error_result:
if (!errmsg) if (!errmsg)
errmsg = libpq_gettext("out of memory for query result"); errmsg = libpq_gettext("out of memory for query result");
printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
/* /*
* XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can * XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can
...@@ -1042,12 +1042,11 @@ pqGetErrorNotice2(PGconn *conn, bool isError) ...@@ -1042,12 +1042,11 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
{ {
pqClearAsyncResult(conn); /* redundant, but be safe */ pqClearAsyncResult(conn); /* redundant, but be safe */
conn->result = res; conn->result = res;
resetPQExpBuffer(&conn->errorMessage);
if (res && !PQExpBufferDataBroken(workBuf) && res->errMsg) if (res && !PQExpBufferDataBroken(workBuf) && res->errMsg)
appendPQExpBufferStr(&conn->errorMessage, res->errMsg); appendPQExpBufferStr(&conn->errorMessage, res->errMsg);
else else
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory")); libpq_gettext("out of memory"));
if (conn->xactStatus == PQTRANS_INTRANS) if (conn->xactStatus == PQTRANS_INTRANS)
conn->xactStatus = PQTRANS_INERROR; conn->xactStatus = PQTRANS_INERROR;
} }
...@@ -1203,8 +1202,8 @@ pqGetCopyData2(PGconn *conn, char **buffer, int async) ...@@ -1203,8 +1202,8 @@ pqGetCopyData2(PGconn *conn, char **buffer, int async)
*buffer = (char *) malloc(msgLength + 1); *buffer = (char *) malloc(msgLength + 1);
if (*buffer == NULL) if (*buffer == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return -2; return -2;
} }
memcpy(*buffer, &conn->inBuffer[conn->inStart], msgLength); memcpy(*buffer, &conn->inBuffer[conn->inStart], msgLength);
...@@ -1349,8 +1348,8 @@ pqEndcopy2(PGconn *conn) ...@@ -1349,8 +1348,8 @@ pqEndcopy2(PGconn *conn)
if (conn->asyncStatus != PGASYNC_COPY_IN && if (conn->asyncStatus != PGASYNC_COPY_IN &&
conn->asyncStatus != PGASYNC_COPY_OUT) conn->asyncStatus != PGASYNC_COPY_OUT)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("no COPY in progress\n")); libpq_gettext("no COPY in progress\n"));
return 1; return 1;
} }
...@@ -1367,7 +1366,6 @@ pqEndcopy2(PGconn *conn) ...@@ -1367,7 +1366,6 @@ pqEndcopy2(PGconn *conn)
/* Return to active duty */ /* Return to active duty */
conn->asyncStatus = PGASYNC_BUSY; conn->asyncStatus = PGASYNC_BUSY;
resetPQExpBuffer(&conn->errorMessage);
/* Wait for the completion response */ /* Wait for the completion response */
result = PQgetResult(conn); result = PQgetResult(conn);
...@@ -1526,7 +1524,7 @@ pqFunctionCall2(PGconn *conn, Oid fnid, ...@@ -1526,7 +1524,7 @@ pqFunctionCall2(PGconn *conn, Oid fnid,
else else
{ {
/* The backend violates the protocol. */ /* The backend violates the protocol. */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("protocol error: id=0x%x\n"), libpq_gettext("protocol error: id=0x%x\n"),
id); id);
pqSaveErrorResult(conn); pqSaveErrorResult(conn);
...@@ -1558,7 +1556,7 @@ pqFunctionCall2(PGconn *conn, Oid fnid, ...@@ -1558,7 +1556,7 @@ pqFunctionCall2(PGconn *conn, Oid fnid,
return PQmakeEmptyPGresult(conn, status); return PQmakeEmptyPGresult(conn, status);
default: default:
/* The backend violates the protocol. */ /* The backend violates the protocol. */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("protocol error: id=0x%x\n"), libpq_gettext("protocol error: id=0x%x\n"),
id); id);
pqSaveErrorResult(conn); pqSaveErrorResult(conn);
......
...@@ -202,8 +202,8 @@ pqParseInput3(PGconn *conn) ...@@ -202,8 +202,8 @@ pqParseInput3(PGconn *conn)
PGRES_COMMAND_OK); PGRES_COMMAND_OK);
if (!conn->result) if (!conn->result)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory")); libpq_gettext("out of memory"));
pqSaveErrorResult(conn); pqSaveErrorResult(conn);
} }
} }
...@@ -229,8 +229,8 @@ pqParseInput3(PGconn *conn) ...@@ -229,8 +229,8 @@ pqParseInput3(PGconn *conn)
PGRES_EMPTY_QUERY); PGRES_EMPTY_QUERY);
if (!conn->result) if (!conn->result)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory")); libpq_gettext("out of memory"));
pqSaveErrorResult(conn); pqSaveErrorResult(conn);
} }
} }
...@@ -246,8 +246,8 @@ pqParseInput3(PGconn *conn) ...@@ -246,8 +246,8 @@ pqParseInput3(PGconn *conn)
PGRES_COMMAND_OK); PGRES_COMMAND_OK);
if (!conn->result) if (!conn->result)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory")); libpq_gettext("out of memory"));
pqSaveErrorResult(conn); pqSaveErrorResult(conn);
} }
} }
...@@ -326,8 +326,8 @@ pqParseInput3(PGconn *conn) ...@@ -326,8 +326,8 @@ pqParseInput3(PGconn *conn)
PGRES_COMMAND_OK); PGRES_COMMAND_OK);
if (!conn->result) if (!conn->result)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory")); libpq_gettext("out of memory"));
pqSaveErrorResult(conn); pqSaveErrorResult(conn);
} }
} }
...@@ -361,8 +361,8 @@ pqParseInput3(PGconn *conn) ...@@ -361,8 +361,8 @@ pqParseInput3(PGconn *conn)
else else
{ {
/* Set up to report error at end of query */ /* Set up to report error at end of query */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&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"));
pqSaveErrorResult(conn); pqSaveErrorResult(conn);
/* Discard the unexpected message */ /* Discard the unexpected message */
conn->inCursor += msgLength; conn->inCursor += msgLength;
...@@ -404,7 +404,7 @@ pqParseInput3(PGconn *conn) ...@@ -404,7 +404,7 @@ pqParseInput3(PGconn *conn)
*/ */
break; break;
default: default:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("unexpected response from server; first received character was \"%c\"\n"), libpq_gettext("unexpected response from server; first received character was \"%c\"\n"),
id); id);
/* build an error result holding the error message */ /* build an error result holding the error message */
...@@ -425,7 +425,7 @@ pqParseInput3(PGconn *conn) ...@@ -425,7 +425,7 @@ pqParseInput3(PGconn *conn)
else else
{ {
/* Trouble --- report it */ /* Trouble --- report it */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("message contents do not agree with length in message type \"%c\"\n"), libpq_gettext("message contents do not agree with length in message type \"%c\"\n"),
id); id);
/* build an error result holding the error message */ /* build an error result holding the error message */
...@@ -445,7 +445,7 @@ pqParseInput3(PGconn *conn) ...@@ -445,7 +445,7 @@ pqParseInput3(PGconn *conn)
static void static void
handleSyncLoss(PGconn *conn, char id, int msgLength) handleSyncLoss(PGconn *conn, char id, int msgLength)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("lost synchronization with server: got message type \"%c\", length %d\n"), libpq_gettext("lost synchronization with server: got message type \"%c\", length %d\n"),
id, msgLength); id, msgLength);
/* build an error result holding the error message */ /* build an error result holding the error message */
...@@ -621,7 +621,7 @@ advance_and_error: ...@@ -621,7 +621,7 @@ advance_and_error:
if (!errmsg) if (!errmsg)
errmsg = libpq_gettext("out of memory for query result"); errmsg = libpq_gettext("out of memory for query result");
printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
pqSaveErrorResult(conn); pqSaveErrorResult(conn);
/* /*
...@@ -721,7 +721,7 @@ advance_and_error: ...@@ -721,7 +721,7 @@ advance_and_error:
*/ */
if (!errmsg) if (!errmsg)
errmsg = libpq_gettext("out of memory"); errmsg = libpq_gettext("out of memory");
printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
pqSaveErrorResult(conn); pqSaveErrorResult(conn);
/* /*
...@@ -848,7 +848,7 @@ set_error_result: ...@@ -848,7 +848,7 @@ set_error_result:
if (!errmsg) if (!errmsg)
errmsg = libpq_gettext("out of memory for query result"); errmsg = libpq_gettext("out of memory for query result");
printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
pqSaveErrorResult(conn); pqSaveErrorResult(conn);
/* /*
...@@ -950,8 +950,8 @@ pqGetErrorNotice3(PGconn *conn, bool isError) ...@@ -950,8 +950,8 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
pqClearAsyncResult(conn); /* redundant, but be safe */ pqClearAsyncResult(conn); /* redundant, but be safe */
conn->result = res; conn->result = res;
if (PQExpBufferDataBroken(workBuf)) if (PQExpBufferDataBroken(workBuf))
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory")); libpq_gettext("out of memory"));
else else
appendPQExpBufferStr(&conn->errorMessage, workBuf.data); appendPQExpBufferStr(&conn->errorMessage, workBuf.data);
} }
...@@ -1695,8 +1695,8 @@ pqGetCopyData3(PGconn *conn, char **buffer, int async) ...@@ -1695,8 +1695,8 @@ pqGetCopyData3(PGconn *conn, char **buffer, int async)
*buffer = (char *) malloc(msgLength + 1); *buffer = (char *) malloc(msgLength + 1);
if (*buffer == NULL) if (*buffer == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return -2; return -2;
} }
memcpy(*buffer, &conn->inBuffer[conn->inCursor], msgLength); memcpy(*buffer, &conn->inBuffer[conn->inCursor], msgLength);
...@@ -1728,8 +1728,8 @@ pqGetline3(PGconn *conn, char *s, int maxlen) ...@@ -1728,8 +1728,8 @@ pqGetline3(PGconn *conn, char *s, int maxlen)
conn->asyncStatus != PGASYNC_COPY_BOTH) || conn->asyncStatus != PGASYNC_COPY_BOTH) ||
conn->copy_is_binary) conn->copy_is_binary)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("PQgetline: not doing text COPY OUT\n")); libpq_gettext("PQgetline: not doing text COPY OUT\n"));
*s = '\0'; *s = '\0';
return EOF; return EOF;
} }
...@@ -1834,8 +1834,8 @@ pqEndcopy3(PGconn *conn) ...@@ -1834,8 +1834,8 @@ pqEndcopy3(PGconn *conn)
conn->asyncStatus != PGASYNC_COPY_OUT && conn->asyncStatus != PGASYNC_COPY_OUT &&
conn->asyncStatus != PGASYNC_COPY_BOTH) conn->asyncStatus != PGASYNC_COPY_BOTH)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("no COPY in progress\n")); libpq_gettext("no COPY in progress\n"));
return 1; return 1;
} }
...@@ -1868,7 +1868,6 @@ pqEndcopy3(PGconn *conn) ...@@ -1868,7 +1868,6 @@ pqEndcopy3(PGconn *conn)
/* Return to active duty */ /* Return to active duty */
conn->asyncStatus = PGASYNC_BUSY; conn->asyncStatus = PGASYNC_BUSY;
resetPQExpBuffer(&conn->errorMessage);
/* /*
* Non blocking connections may have to abort at this point. If everyone * Non blocking connections may have to abort at this point. If everyone
...@@ -2091,7 +2090,7 @@ pqFunctionCall3(PGconn *conn, Oid fnid, ...@@ -2091,7 +2090,7 @@ pqFunctionCall3(PGconn *conn, Oid fnid,
break; break;
default: default:
/* The backend violates the protocol. */ /* The backend violates the protocol. */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("protocol error: id=0x%x\n"), libpq_gettext("protocol error: id=0x%x\n"),
id); id);
pqSaveErrorResult(conn); pqSaveErrorResult(conn);
......
...@@ -94,8 +94,8 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn, ...@@ -94,8 +94,8 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn,
if (!(host && host[0] != '\0')) if (!(host && host[0] != '\0'))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("host name must be specified\n")); libpq_gettext("host name must be specified\n"));
return -1; return -1;
} }
...@@ -106,8 +106,8 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn, ...@@ -106,8 +106,8 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn,
name = malloc(namelen + 1); name = malloc(namelen + 1);
if (name == NULL) if (name == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return -1; return -1;
} }
memcpy(name, namedata, namelen); memcpy(name, namedata, namelen);
...@@ -120,8 +120,8 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn, ...@@ -120,8 +120,8 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn,
if (namelen != strlen(name)) if (namelen != strlen(name))
{ {
free(name); free(name);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("SSL certificate's name contains embedded null\n")); libpq_gettext("SSL certificate's name contains embedded null\n"));
return -1; return -1;
} }
...@@ -167,8 +167,8 @@ pq_verify_peer_name_matches_certificate(PGconn *conn) ...@@ -167,8 +167,8 @@ pq_verify_peer_name_matches_certificate(PGconn *conn)
/* Check that we have a hostname to compare with. */ /* Check that we have a hostname to compare with. */
if (!(host && host[0] != '\0')) if (!(host && host[0] != '\0'))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("host name must be specified for a verified SSL connection\n")); libpq_gettext("host name must be specified for a verified SSL connection\n"));
return false; return false;
} }
...@@ -184,7 +184,7 @@ pq_verify_peer_name_matches_certificate(PGconn *conn) ...@@ -184,7 +184,7 @@ pq_verify_peer_name_matches_certificate(PGconn *conn)
*/ */
if (names_examined > 1) if (names_examined > 1)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_ngettext("server certificate for \"%s\" (and %d other name) does not match host name \"%s\"\n", libpq_ngettext("server certificate for \"%s\" (and %d other name) does not match host name \"%s\"\n",
"server certificate for \"%s\" (and %d other names) does not match host name \"%s\"\n", "server certificate for \"%s\" (and %d other names) does not match host name \"%s\"\n",
names_examined - 1), names_examined - 1),
...@@ -192,14 +192,14 @@ pq_verify_peer_name_matches_certificate(PGconn *conn) ...@@ -192,14 +192,14 @@ pq_verify_peer_name_matches_certificate(PGconn *conn)
} }
else if (names_examined == 1) else if (names_examined == 1)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("server certificate for \"%s\" does not match host name \"%s\"\n"), libpq_gettext("server certificate for \"%s\" does not match host name \"%s\"\n"),
first_name, host); first_name, host);
} }
else else
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("could not get server's host name from server certificate\n")); libpq_gettext("could not get server's host name from server certificate\n"));
} }
} }
......
...@@ -78,7 +78,7 @@ ...@@ -78,7 +78,7 @@
* *
* On success, returns the number of data bytes consumed (possibly less than * On success, returns the number of data bytes consumed (possibly less than
* len). On failure, returns -1 with errno set appropriately. If the errno * len). On failure, returns -1 with errno set appropriately. If the errno
* indicates a non-retryable error, a message is put into conn->errorMessage. * indicates a non-retryable error, a message is added to conn->errorMessage.
* For retryable errors, caller should call again (passing the same data) * For retryable errors, caller should call again (passing the same data)
* once the socket is ready. * once the socket is ready.
*/ */
...@@ -106,8 +106,8 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len) ...@@ -106,8 +106,8 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len)
*/ */
if (len < PqGSSSendConsumed) if (len < PqGSSSendConsumed)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
"GSSAPI caller failed to retransmit all data needing to be retried\n"); "GSSAPI caller failed to retransmit all data needing to be retried\n");
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
...@@ -205,15 +205,15 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len) ...@@ -205,15 +205,15 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len)
if (conf_state == 0) if (conf_state == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("outgoing GSSAPI message would not use confidentiality\n")); libpq_gettext("outgoing GSSAPI message would not use confidentiality\n"));
errno = EIO; /* for lack of a better idea */ errno = EIO; /* for lack of a better idea */
goto cleanup; goto cleanup;
} }
if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)) if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("client tried to send oversize GSSAPI packet (%zu > %zu)\n"), libpq_gettext("client tried to send oversize GSSAPI packet (%zu > %zu)\n"),
(size_t) output.length, (size_t) output.length,
PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)); PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32));
...@@ -258,7 +258,7 @@ cleanup: ...@@ -258,7 +258,7 @@ cleanup:
* *
* Returns the number of data bytes read, or on failure, returns -1 * Returns the number of data bytes read, or on failure, returns -1
* with errno set appropriately. If the errno indicates a non-retryable * with errno set appropriately. If the errno indicates a non-retryable
* error, a message is put into conn->errorMessage. For retryable errors, * error, a message is added to conn->errorMessage. For retryable errors,
* caller should call again once the socket is ready. * caller should call again once the socket is ready.
*/ */
ssize_t ssize_t
...@@ -350,7 +350,7 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len) ...@@ -350,7 +350,7 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len)
if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)) if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("oversize GSSAPI packet sent by the server (%zu > %zu)\n"), libpq_gettext("oversize GSSAPI packet sent by the server (%zu > %zu)\n"),
(size_t) input.length, (size_t) input.length,
PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)); PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32));
...@@ -399,8 +399,8 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len) ...@@ -399,8 +399,8 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len)
if (conf_state == 0) if (conf_state == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("incoming GSSAPI message did not use confidentiality\n")); libpq_gettext("incoming GSSAPI message did not use confidentiality\n"));
ret = -1; ret = -1;
errno = EIO; /* for lack of a better idea */ errno = EIO; /* for lack of a better idea */
goto cleanup; goto cleanup;
...@@ -500,8 +500,8 @@ pqsecure_open_gss(PGconn *conn) ...@@ -500,8 +500,8 @@ pqsecure_open_gss(PGconn *conn)
PqGSSResultBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE); PqGSSResultBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);
if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return PGRES_POLLING_FAILED; return PGRES_POLLING_FAILED;
} }
PqGSSSendLength = PqGSSSendNext = PqGSSSendConsumed = 0; PqGSSSendLength = PqGSSSendNext = PqGSSSendConsumed = 0;
...@@ -578,7 +578,7 @@ pqsecure_open_gss(PGconn *conn) ...@@ -578,7 +578,7 @@ pqsecure_open_gss(PGconn *conn)
PqGSSRecvLength += ret; PqGSSRecvLength += ret;
printfPQExpBuffer(&conn->errorMessage, "%s\n", PqGSSRecvBuffer + 1); appendPQExpBuffer(&conn->errorMessage, "%s\n", PqGSSRecvBuffer + 1);
return PGRES_POLLING_FAILED; return PGRES_POLLING_FAILED;
} }
...@@ -592,7 +592,7 @@ pqsecure_open_gss(PGconn *conn) ...@@ -592,7 +592,7 @@ pqsecure_open_gss(PGconn *conn)
input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer); input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer);
if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)) if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("oversize GSSAPI packet sent by the server (%zu > %zu)\n"), libpq_gettext("oversize GSSAPI packet sent by the server (%zu > %zu)\n"),
(size_t) input.length, (size_t) input.length,
PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)); PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32));
......
This diff is collapsed.
...@@ -205,8 +205,8 @@ pqsecure_close(PGconn *conn) ...@@ -205,8 +205,8 @@ pqsecure_close(PGconn *conn)
/* /*
* Read data from a secure connection. * Read data from a secure connection.
* *
* On failure, this function is responsible for putting a suitable message * On failure, this function is responsible for appending a suitable message
* into conn->errorMessage. The caller must still inspect errno, but only * to conn->errorMessage. The caller must still inspect errno, but only
* to determine whether to continue/retry after error. * to determine whether to continue/retry after error.
*/ */
ssize_t ssize_t
...@@ -263,14 +263,14 @@ pqsecure_raw_read(PGconn *conn, void *ptr, size_t len) ...@@ -263,14 +263,14 @@ pqsecure_raw_read(PGconn *conn, void *ptr, size_t len)
case EPIPE: case EPIPE:
case ECONNRESET: case ECONNRESET:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("server closed the connection unexpectedly\n" libpq_gettext("server closed the connection unexpectedly\n"
"\tThis probably means the server terminated abnormally\n" "\tThis probably means the server terminated abnormally\n"
"\tbefore or while processing the request.\n")); "\tbefore or while processing the request.\n"));
break; break;
default: default:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not receive data from server: %s\n"), libpq_gettext("could not receive data from server: %s\n"),
SOCK_STRERROR(result_errno, SOCK_STRERROR(result_errno,
sebuf, sizeof(sebuf))); sebuf, sizeof(sebuf)));
...@@ -287,8 +287,8 @@ pqsecure_raw_read(PGconn *conn, void *ptr, size_t len) ...@@ -287,8 +287,8 @@ pqsecure_raw_read(PGconn *conn, void *ptr, size_t len)
/* /*
* Write data to a secure connection. * Write data to a secure connection.
* *
* On failure, this function is responsible for putting a suitable message * On failure, this function is responsible for appending a suitable message
* into conn->errorMessage. The caller must still inspect errno, but only * to conn->errorMessage. The caller must still inspect errno, but only
* to determine whether to continue/retry after error. * to determine whether to continue/retry after error.
*/ */
ssize_t ssize_t
...@@ -376,14 +376,14 @@ retry_masked: ...@@ -376,14 +376,14 @@ retry_masked:
/* FALL THRU */ /* FALL THRU */
case ECONNRESET: case ECONNRESET:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("server closed the connection unexpectedly\n" libpq_gettext("server closed the connection unexpectedly\n"
"\tThis probably means the server terminated abnormally\n" "\tThis probably means the server terminated abnormally\n"
"\tbefore or while processing the request.\n")); "\tbefore or while processing the request.\n"));
break; break;
default: default:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not send data to server: %s\n"), libpq_gettext("could not send data to server: %s\n"),
SOCK_STRERROR(result_errno, SOCK_STRERROR(result_errno,
sebuf, sizeof(sebuf))); sebuf, sizeof(sebuf)));
......
...@@ -522,7 +522,11 @@ struct pg_conn ...@@ -522,7 +522,11 @@ struct pg_conn
* connection */ * connection */
#endif #endif
/* Buffer for current error message */ /*
* Buffer for current error message. This is cleared at the start of any
* connection attempt or query cycle; after that, all code should append
* messages to it, never overwrite.
*/
PQExpBufferData errorMessage; /* expansible string */ PQExpBufferData errorMessage; /* expansible string */
/* Buffer for receiving various parts of messages */ /* Buffer for receiving various parts of messages */
...@@ -600,7 +604,6 @@ extern pgthreadlock_t pg_g_threadlock; ...@@ -600,7 +604,6 @@ extern pgthreadlock_t pg_g_threadlock;
/* === in fe-exec.c === */ /* === in fe-exec.c === */
extern void pqSetResultError(PGresult *res, const char *msg); extern void pqSetResultError(PGresult *res, const char *msg);
extern void pqCatenateResultError(PGresult *res, const char *msg);
extern void *pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary); extern void *pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary);
extern char *pqResultStrdup(PGresult *res, const char *str); extern char *pqResultStrdup(PGresult *res, const char *str);
extern void pqClearAsyncResult(PGconn *conn); extern void pqClearAsyncResult(PGconn *conn);
...@@ -612,6 +615,7 @@ extern void pqSaveMessageField(PGresult *res, char code, ...@@ -612,6 +615,7 @@ extern void pqSaveMessageField(PGresult *res, char code,
extern void pqSaveParameterStatus(PGconn *conn, const char *name, extern void pqSaveParameterStatus(PGconn *conn, const char *name,
const char *value); const char *value);
extern int pqRowProcessor(PGconn *conn, const char **errmsgp); extern int pqRowProcessor(PGconn *conn, const char **errmsgp);
extern int PQsendQueryContinue(PGconn *conn, const char *query);
/* === in fe-protocol2.c === */ /* === in fe-protocol2.c === */
...@@ -708,7 +712,7 @@ extern void pgtls_init_library(bool do_ssl, int do_crypto); ...@@ -708,7 +712,7 @@ extern void pgtls_init_library(bool do_ssl, int do_crypto);
* The conn parameter is only used to be able to pass back an error * The conn parameter is only used to be able to pass back an error
* message - no connection-local setup is made here. * message - no connection-local setup is made here.
* *
* Returns 0 if OK, -1 on failure (with a message in conn->errorMessage). * Returns 0 if OK, -1 on failure (adding a message to conn->errorMessage).
*/ */
extern int pgtls_init(PGconn *conn); extern int pgtls_init(PGconn *conn);
...@@ -725,8 +729,8 @@ extern void pgtls_close(PGconn *conn); ...@@ -725,8 +729,8 @@ extern void pgtls_close(PGconn *conn);
/* /*
* Read data from a secure connection. * Read data from a secure connection.
* *
* On failure, this function is responsible for putting a suitable message * On failure, this function is responsible for appending a suitable message
* into conn->errorMessage. The caller must still inspect errno, but only * to conn->errorMessage. The caller must still inspect errno, but only
* to determine whether to continue/retry after error. * to determine whether to continue/retry after error.
*/ */
extern ssize_t pgtls_read(PGconn *conn, void *ptr, size_t len); extern ssize_t pgtls_read(PGconn *conn, void *ptr, size_t len);
...@@ -739,8 +743,8 @@ extern bool pgtls_read_pending(PGconn *conn); ...@@ -739,8 +743,8 @@ extern bool pgtls_read_pending(PGconn *conn);
/* /*
* Write data to a secure connection. * Write data to a secure connection.
* *
* On failure, this function is responsible for putting a suitable message * On failure, this function is responsible for appending a suitable message
* into conn->errorMessage. The caller must still inspect errno, but only * to conn->errorMessage. The caller must still inspect errno, but only
* to determine whether to continue/retry after error. * to determine whether to continue/retry after error.
*/ */
extern ssize_t pgtls_write(PGconn *conn, const void *ptr, size_t len); extern ssize_t pgtls_write(PGconn *conn, const void *ptr, size_t len);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment