diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2021-01-11 13:12:09 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2021-01-11 13:12:09 -0500 |
commit | ffa2e4670123124b92f037d335a1e844c3782d3f (patch) | |
tree | d7a1d1c6779c862d5673e24cb3ce3a824d55446f /src/interfaces/libpq/fe-protocol2.c | |
parent | ce6a71fa5300cf00adf32c9daee302c523609709 (diff) |
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
Diffstat (limited to 'src/interfaces/libpq/fe-protocol2.c')
-rw-r--r-- | src/interfaces/libpq/fe-protocol2.c | 36 |
1 files changed, 17 insertions, 19 deletions
diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c index ad6587f924e..6efa53d8b71 100644 --- a/src/interfaces/libpq/fe-protocol2.c +++ b/src/interfaces/libpq/fe-protocol2.c @@ -83,7 +83,7 @@ pqSetenvPoll(PGconn *conn) return PGRES_POLLING_OK; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid setenv state %c, probably indicative of memory corruption\n"), conn->setenv_state); goto error_return; @@ -380,7 +380,7 @@ pqSetenvPoll(PGconn *conn) } default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid state %c, " "probably indicative of memory corruption\n"), conn->setenv_state); @@ -493,8 +493,8 @@ pqParseInput2(PGconn *conn) PGRES_COMMAND_OK); if (!conn->result) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); pqSaveErrorResult(conn); } } @@ -528,8 +528,8 @@ pqParseInput2(PGconn *conn) PGRES_EMPTY_QUERY); if (!conn->result) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); pqSaveErrorResult(conn); } } @@ -622,7 +622,7 @@ pqParseInput2(PGconn *conn) * never arrives from the server during protocol 2.0. */ default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unexpected response from server; first received character was \"%c\"\n"), id); /* build an error result holding the error message */ @@ -754,7 +754,7 @@ advance_and_error: if (!errmsg) 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 @@ -929,7 +929,7 @@ set_error_result: if (!errmsg) 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 @@ -1042,12 +1042,11 @@ pqGetErrorNotice2(PGconn *conn, bool isError) { pqClearAsyncResult(conn); /* redundant, but be safe */ conn->result = res; - resetPQExpBuffer(&conn->errorMessage); if (res && !PQExpBufferDataBroken(workBuf) && res->errMsg) appendPQExpBufferStr(&conn->errorMessage, res->errMsg); else - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); if (conn->xactStatus == PQTRANS_INTRANS) conn->xactStatus = PQTRANS_INERROR; } @@ -1203,8 +1202,8 @@ pqGetCopyData2(PGconn *conn, char **buffer, int async) *buffer = (char *) malloc(msgLength + 1); if (*buffer == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return -2; } memcpy(*buffer, &conn->inBuffer[conn->inStart], msgLength); @@ -1349,8 +1348,8 @@ pqEndcopy2(PGconn *conn) if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_OUT) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("no COPY in progress\n")); return 1; } @@ -1367,7 +1366,6 @@ pqEndcopy2(PGconn *conn) /* Return to active duty */ conn->asyncStatus = PGASYNC_BUSY; - resetPQExpBuffer(&conn->errorMessage); /* Wait for the completion response */ result = PQgetResult(conn); @@ -1526,7 +1524,7 @@ pqFunctionCall2(PGconn *conn, Oid fnid, else { /* The backend violates the protocol. */ - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("protocol error: id=0x%x\n"), id); pqSaveErrorResult(conn); @@ -1558,7 +1556,7 @@ pqFunctionCall2(PGconn *conn, Oid fnid, return PQmakeEmptyPGresult(conn, status); default: /* The backend violates the protocol. */ - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("protocol error: id=0x%x\n"), id); pqSaveErrorResult(conn); |