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
...@@ -208,13 +208,13 @@ pg_fe_scram_exchange(void *opaq, char *input, int inputlen, ...@@ -208,13 +208,13 @@ pg_fe_scram_exchange(void *opaq, char *input, int inputlen,
{ {
if (inputlen == 0) if (inputlen == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("malformed SCRAM message (empty message)\n")); libpq_gettext("malformed SCRAM message (empty message)\n"));
goto error; goto error;
} }
if (inputlen != strlen(input)) if (inputlen != strlen(input))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("malformed SCRAM message (length mismatch)\n")); libpq_gettext("malformed SCRAM message (length mismatch)\n"));
goto error; goto error;
} }
...@@ -258,14 +258,14 @@ pg_fe_scram_exchange(void *opaq, char *input, int inputlen, ...@@ -258,14 +258,14 @@ pg_fe_scram_exchange(void *opaq, char *input, int inputlen,
*/ */
if (!verify_server_signature(state, success)) if (!verify_server_signature(state, success))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("could not verify server signature\n")); libpq_gettext("could not verify server signature\n"));
goto error; goto error;
} }
if (!*success) if (!*success)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("incorrect server signature\n")); libpq_gettext("incorrect server signature\n"));
} }
*done = true; *done = true;
...@@ -274,7 +274,7 @@ pg_fe_scram_exchange(void *opaq, char *input, int inputlen, ...@@ -274,7 +274,7 @@ pg_fe_scram_exchange(void *opaq, char *input, int inputlen,
default: default:
/* shouldn't happen */ /* shouldn't happen */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("invalid SCRAM exchange state\n")); libpq_gettext("invalid SCRAM exchange state\n"));
goto error; goto error;
} }
...@@ -287,6 +287,11 @@ error: ...@@ -287,6 +287,11 @@ error:
/* /*
* Read value for an attribute part of a SCRAM message. * Read value for an attribute part of a SCRAM message.
*
* The buffer at **input is destructively modified, and *input is
* advanced over the "attr=value" string and any following comma.
*
* On failure, append an error message to *errorMessage and return NULL.
*/ */
static char * static char *
read_attr_value(char **input, char attr, PQExpBuffer errorMessage) read_attr_value(char **input, char attr, PQExpBuffer errorMessage)
...@@ -296,7 +301,7 @@ read_attr_value(char **input, char attr, PQExpBuffer errorMessage) ...@@ -296,7 +301,7 @@ read_attr_value(char **input, char attr, PQExpBuffer errorMessage)
if (*begin != attr) if (*begin != attr)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("malformed SCRAM message (attribute \"%c\" expected)\n"), libpq_gettext("malformed SCRAM message (attribute \"%c\" expected)\n"),
attr); attr);
return NULL; return NULL;
...@@ -305,7 +310,7 @@ read_attr_value(char **input, char attr, PQExpBuffer errorMessage) ...@@ -305,7 +310,7 @@ read_attr_value(char **input, char attr, PQExpBuffer errorMessage)
if (*begin != '=') if (*begin != '=')
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("malformed SCRAM message (expected character \"=\" for attribute \"%c\")\n"), libpq_gettext("malformed SCRAM message (expected character \"=\" for attribute \"%c\")\n"),
attr); attr);
return NULL; return NULL;
...@@ -346,7 +351,7 @@ build_client_first_message(fe_scram_state *state) ...@@ -346,7 +351,7 @@ build_client_first_message(fe_scram_state *state)
*/ */
if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN)) if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("could not generate nonce\n")); libpq_gettext("could not generate nonce\n"));
return NULL; return NULL;
} }
...@@ -356,7 +361,7 @@ build_client_first_message(fe_scram_state *state) ...@@ -356,7 +361,7 @@ build_client_first_message(fe_scram_state *state)
state->client_nonce = malloc(encoded_len + 1); state->client_nonce = malloc(encoded_len + 1);
if (state->client_nonce == NULL) if (state->client_nonce == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return NULL; return NULL;
} }
...@@ -364,7 +369,7 @@ build_client_first_message(fe_scram_state *state) ...@@ -364,7 +369,7 @@ build_client_first_message(fe_scram_state *state)
state->client_nonce, encoded_len); state->client_nonce, encoded_len);
if (encoded_len < 0) if (encoded_len < 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("could not encode nonce\n")); libpq_gettext("could not encode nonce\n"));
return NULL; return NULL;
} }
...@@ -431,7 +436,7 @@ build_client_first_message(fe_scram_state *state) ...@@ -431,7 +436,7 @@ build_client_first_message(fe_scram_state *state)
oom_error: oom_error:
termPQExpBuffer(&buf); termPQExpBuffer(&buf);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return NULL; return NULL;
} }
...@@ -508,7 +513,7 @@ build_client_final_message(fe_scram_state *state) ...@@ -508,7 +513,7 @@ build_client_final_message(fe_scram_state *state)
free(cbind_data); free(cbind_data);
free(cbind_input); free(cbind_input);
termPQExpBuffer(&buf); termPQExpBuffer(&buf);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
"could not encode cbind data for channel binding\n"); "could not encode cbind data for channel binding\n");
return NULL; return NULL;
} }
...@@ -523,7 +528,7 @@ build_client_final_message(fe_scram_state *state) ...@@ -523,7 +528,7 @@ build_client_final_message(fe_scram_state *state)
* Shouldn't happen. * Shouldn't happen.
*/ */
termPQExpBuffer(&buf); termPQExpBuffer(&buf);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
"channel binding not supported by this build\n"); "channel binding not supported by this build\n");
return NULL; return NULL;
#endif /* HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH */ #endif /* HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH */
...@@ -553,7 +558,7 @@ build_client_final_message(fe_scram_state *state) ...@@ -553,7 +558,7 @@ build_client_final_message(fe_scram_state *state)
client_proof)) client_proof))
{ {
termPQExpBuffer(&buf); termPQExpBuffer(&buf);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("could not calculate client proof\n")); libpq_gettext("could not calculate client proof\n"));
return NULL; return NULL;
} }
...@@ -569,7 +574,7 @@ build_client_final_message(fe_scram_state *state) ...@@ -569,7 +574,7 @@ build_client_final_message(fe_scram_state *state)
if (encoded_len < 0) if (encoded_len < 0)
{ {
termPQExpBuffer(&buf); termPQExpBuffer(&buf);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("could not encode client proof\n")); libpq_gettext("could not encode client proof\n"));
return NULL; return NULL;
} }
...@@ -585,7 +590,7 @@ build_client_final_message(fe_scram_state *state) ...@@ -585,7 +590,7 @@ build_client_final_message(fe_scram_state *state)
oom_error: oom_error:
termPQExpBuffer(&buf); termPQExpBuffer(&buf);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return NULL; return NULL;
} }
...@@ -606,7 +611,7 @@ read_server_first_message(fe_scram_state *state, char *input) ...@@ -606,7 +611,7 @@ read_server_first_message(fe_scram_state *state, char *input)
state->server_first_message = strdup(input); state->server_first_message = strdup(input);
if (state->server_first_message == NULL) if (state->server_first_message == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return false; return false;
} }
...@@ -616,7 +621,7 @@ read_server_first_message(fe_scram_state *state, char *input) ...@@ -616,7 +621,7 @@ read_server_first_message(fe_scram_state *state, char *input)
&conn->errorMessage); &conn->errorMessage);
if (nonce == NULL) if (nonce == NULL)
{ {
/* read_attr_value() has generated an error string */ /* read_attr_value() has appended an error string */
return false; return false;
} }
...@@ -624,7 +629,7 @@ read_server_first_message(fe_scram_state *state, char *input) ...@@ -624,7 +629,7 @@ read_server_first_message(fe_scram_state *state, char *input)
if (strlen(nonce) < strlen(state->client_nonce) || if (strlen(nonce) < strlen(state->client_nonce) ||
memcmp(nonce, state->client_nonce, strlen(state->client_nonce)) != 0) memcmp(nonce, state->client_nonce, strlen(state->client_nonce)) != 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("invalid SCRAM response (nonce mismatch)\n")); libpq_gettext("invalid SCRAM response (nonce mismatch)\n"));
return false; return false;
} }
...@@ -632,7 +637,7 @@ read_server_first_message(fe_scram_state *state, char *input) ...@@ -632,7 +637,7 @@ read_server_first_message(fe_scram_state *state, char *input)
state->nonce = strdup(nonce); state->nonce = strdup(nonce);
if (state->nonce == NULL) if (state->nonce == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return false; return false;
} }
...@@ -640,14 +645,14 @@ read_server_first_message(fe_scram_state *state, char *input) ...@@ -640,14 +645,14 @@ read_server_first_message(fe_scram_state *state, char *input)
encoded_salt = read_attr_value(&input, 's', &conn->errorMessage); encoded_salt = read_attr_value(&input, 's', &conn->errorMessage);
if (encoded_salt == NULL) if (encoded_salt == NULL)
{ {
/* read_attr_value() has generated an error string */ /* read_attr_value() has appended an error string */
return false; return false;
} }
decoded_salt_len = pg_b64_dec_len(strlen(encoded_salt)); decoded_salt_len = pg_b64_dec_len(strlen(encoded_salt));
state->salt = malloc(decoded_salt_len); state->salt = malloc(decoded_salt_len);
if (state->salt == NULL) if (state->salt == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return false; return false;
} }
...@@ -657,7 +662,7 @@ read_server_first_message(fe_scram_state *state, char *input) ...@@ -657,7 +662,7 @@ read_server_first_message(fe_scram_state *state, char *input)
decoded_salt_len); decoded_salt_len);
if (state->saltlen < 0) if (state->saltlen < 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("malformed SCRAM message (invalid salt)\n")); libpq_gettext("malformed SCRAM message (invalid salt)\n"));
return false; return false;
} }
...@@ -665,19 +670,19 @@ read_server_first_message(fe_scram_state *state, char *input) ...@@ -665,19 +670,19 @@ read_server_first_message(fe_scram_state *state, char *input)
iterations_str = read_attr_value(&input, 'i', &conn->errorMessage); iterations_str = read_attr_value(&input, 'i', &conn->errorMessage);
if (iterations_str == NULL) if (iterations_str == NULL)
{ {
/* read_attr_value() has generated an error string */ /* read_attr_value() has appended an error string */
return false; return false;
} }
state->iterations = strtol(iterations_str, &endptr, 10); state->iterations = strtol(iterations_str, &endptr, 10);
if (*endptr != '\0' || state->iterations < 1) if (*endptr != '\0' || state->iterations < 1)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("malformed SCRAM message (invalid iteration count)\n")); libpq_gettext("malformed SCRAM message (invalid iteration count)\n"));
return false; return false;
} }
if (*input != '\0') if (*input != '\0')
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("malformed SCRAM message (garbage at end of server-first-message)\n")); libpq_gettext("malformed SCRAM message (garbage at end of server-first-message)\n"));
return true; return true;
...@@ -697,7 +702,7 @@ read_server_final_message(fe_scram_state *state, char *input) ...@@ -697,7 +702,7 @@ read_server_final_message(fe_scram_state *state, char *input)
state->server_final_message = strdup(input); state->server_final_message = strdup(input);
if (!state->server_final_message) if (!state->server_final_message)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return false; return false;
} }
...@@ -708,7 +713,12 @@ read_server_final_message(fe_scram_state *state, char *input) ...@@ -708,7 +713,12 @@ read_server_final_message(fe_scram_state *state, char *input)
char *errmsg = read_attr_value(&input, 'e', char *errmsg = read_attr_value(&input, 'e',
&conn->errorMessage); &conn->errorMessage);
printfPQExpBuffer(&conn->errorMessage, if (errmsg == NULL)
{
/* read_attr_value() has appended an error message */
return false;
}
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("error received from server in SCRAM exchange: %s\n"), libpq_gettext("error received from server in SCRAM exchange: %s\n"),
errmsg); errmsg);
return false; return false;
...@@ -719,19 +729,19 @@ read_server_final_message(fe_scram_state *state, char *input) ...@@ -719,19 +729,19 @@ read_server_final_message(fe_scram_state *state, char *input)
&conn->errorMessage); &conn->errorMessage);
if (encoded_server_signature == NULL) if (encoded_server_signature == NULL)
{ {
/* read_attr_value() has generated an error message */ /* read_attr_value() has appended an error message */
return false; return false;
} }
if (*input != '\0') if (*input != '\0')
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("malformed SCRAM message (garbage at end of server-final-message)\n")); libpq_gettext("malformed SCRAM message (garbage at end of server-final-message)\n"));
server_signature_len = pg_b64_dec_len(strlen(encoded_server_signature)); server_signature_len = pg_b64_dec_len(strlen(encoded_server_signature));
decoded_server_signature = malloc(server_signature_len); decoded_server_signature = malloc(server_signature_len);
if (!decoded_server_signature) if (!decoded_server_signature)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return false; return false;
} }
...@@ -743,7 +753,7 @@ read_server_final_message(fe_scram_state *state, char *input) ...@@ -743,7 +753,7 @@ read_server_final_message(fe_scram_state *state, char *input)
if (server_signature_len != SCRAM_KEY_LEN) if (server_signature_len != SCRAM_KEY_LEN)
{ {
free(decoded_server_signature); free(decoded_server_signature);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("malformed SCRAM message (invalid server signature)\n")); libpq_gettext("malformed SCRAM message (invalid server signature)\n"));
return false; return false;
} }
......
...@@ -72,7 +72,7 @@ pg_GSS_continue(PGconn *conn, int payloadlen) ...@@ -72,7 +72,7 @@ pg_GSS_continue(PGconn *conn, int payloadlen)
ginbuf.value = malloc(payloadlen); ginbuf.value = malloc(payloadlen);
if (!ginbuf.value) if (!ginbuf.value)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("out of memory allocating GSSAPI buffer (%d)\n"), libpq_gettext("out of memory allocating GSSAPI buffer (%d)\n"),
payloadlen); payloadlen);
return STATUS_ERROR; return STATUS_ERROR;
...@@ -154,14 +154,14 @@ pg_GSS_startup(PGconn *conn, int payloadlen) ...@@ -154,14 +154,14 @@ pg_GSS_startup(PGconn *conn, int payloadlen)
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;
} }
if (conn->gctx) if (conn->gctx)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("duplicate GSS authentication request\n")); libpq_gettext("duplicate GSS authentication request\n"));
return STATUS_ERROR; return STATUS_ERROR;
} }
...@@ -195,10 +195,10 @@ pg_SSPI_error(PGconn *conn, const char *mprefix, SECURITY_STATUS r) ...@@ -195,10 +195,10 @@ pg_SSPI_error(PGconn *conn, const char *mprefix, SECURITY_STATUS r)
FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_FROM_SYSTEM,
NULL, r, 0, NULL, r, 0,
sysmsg, sizeof(sysmsg), NULL) == 0) sysmsg, sizeof(sysmsg), NULL) == 0)
printfPQExpBuffer(&conn->errorMessage, "%s: SSPI error %x\n", appendPQExpBuffer(&conn->errorMessage, "%s: SSPI error %x\n",
mprefix, (unsigned int) r); mprefix, (unsigned int) r);
else else
printfPQExpBuffer(&conn->errorMessage, "%s: %s (%x)\n", appendPQExpBuffer(&conn->errorMessage, "%s: %s (%x)\n",
mprefix, sysmsg, (unsigned int) r); mprefix, sysmsg, (unsigned int) r);
} }
...@@ -226,7 +226,7 @@ pg_SSPI_continue(PGconn *conn, int payloadlen) ...@@ -226,7 +226,7 @@ pg_SSPI_continue(PGconn *conn, int payloadlen)
inputbuf = malloc(payloadlen); inputbuf = malloc(payloadlen);
if (!inputbuf) if (!inputbuf)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("out of memory allocating SSPI buffer (%d)\n"), libpq_gettext("out of memory allocating SSPI buffer (%d)\n"),
payloadlen); payloadlen);
return STATUS_ERROR; return STATUS_ERROR;
...@@ -286,7 +286,8 @@ pg_SSPI_continue(PGconn *conn, int payloadlen) ...@@ -286,7 +286,8 @@ pg_SSPI_continue(PGconn *conn, int payloadlen)
conn->sspictx = malloc(sizeof(CtxtHandle)); conn->sspictx = malloc(sizeof(CtxtHandle));
if (conn->sspictx == NULL) if (conn->sspictx == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n"));
return STATUS_ERROR; return STATUS_ERROR;
} }
memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle)); memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle));
...@@ -305,7 +306,8 @@ pg_SSPI_continue(PGconn *conn, int payloadlen) ...@@ -305,7 +306,8 @@ pg_SSPI_continue(PGconn *conn, int payloadlen)
* authentication. Keep check in case it shows up with other * authentication. Keep check in case it shows up with other
* authentication methods later. * authentication methods later.
*/ */
printfPQExpBuffer(&conn->errorMessage, "SSPI returned invalid number of output buffers\n"); appendPQExpBufferStr(&conn->errorMessage,
"SSPI returned invalid number of output buffers\n");
return STATUS_ERROR; return STATUS_ERROR;
} }
...@@ -345,7 +347,7 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen) ...@@ -345,7 +347,7 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen)
if (conn->sspictx) if (conn->sspictx)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("duplicate SSPI authentication request\n")); libpq_gettext("duplicate SSPI authentication request\n"));
return STATUS_ERROR; return STATUS_ERROR;
} }
...@@ -356,7 +358,8 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen) ...@@ -356,7 +358,8 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen)
conn->sspicred = malloc(sizeof(CredHandle)); conn->sspicred = malloc(sizeof(CredHandle));
if (conn->sspicred == NULL) if (conn->sspicred == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n"));
return STATUS_ERROR; return STATUS_ERROR;
} }
...@@ -384,14 +387,15 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen) ...@@ -384,14 +387,15 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen)
*/ */
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;
} }
conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(host) + 2); conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(host) + 2);
if (!conn->sspitarget) if (!conn->sspitarget)
{ {
printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n"));
return STATUS_ERROR; return STATUS_ERROR;
} }
sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, host); sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, host);
...@@ -425,14 +429,14 @@ pg_SASL_init(PGconn *conn, int payloadlen) ...@@ -425,14 +429,14 @@ pg_SASL_init(PGconn *conn, int payloadlen)
if (conn->channel_binding[0] == 'r' && /* require */ if (conn->channel_binding[0] == 'r' && /* require */
!conn->ssl_in_use) !conn->ssl_in_use)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("channel binding required, but SSL not in use\n")); libpq_gettext("channel binding required, but SSL not in use\n"));
goto error; goto error;
} }
if (conn->sasl_state) if (conn->sasl_state)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("duplicate SASL authentication request\n")); libpq_gettext("duplicate SASL authentication request\n"));
goto error; goto error;
} }
...@@ -448,7 +452,7 @@ pg_SASL_init(PGconn *conn, int payloadlen) ...@@ -448,7 +452,7 @@ pg_SASL_init(PGconn *conn, int payloadlen)
{ {
if (pqGets(&mechanism_buf, conn)) if (pqGets(&mechanism_buf, conn))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
"fe_sendauth: invalid authentication request from server: invalid list of authentication mechanisms\n"); "fe_sendauth: invalid authentication request from server: invalid list of authentication mechanisms\n");
goto error; goto error;
} }
...@@ -488,7 +492,7 @@ pg_SASL_init(PGconn *conn, int payloadlen) ...@@ -488,7 +492,7 @@ pg_SASL_init(PGconn *conn, int payloadlen)
*/ */
if (conn->channel_binding[0] == 'r') /* require */ if (conn->channel_binding[0] == 'r') /* require */
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("channel binding is required, but client does not support it\n")); libpq_gettext("channel binding is required, but client does not support it\n"));
goto error; goto error;
} }
...@@ -505,7 +509,7 @@ pg_SASL_init(PGconn *conn, int payloadlen) ...@@ -505,7 +509,7 @@ pg_SASL_init(PGconn *conn, int payloadlen)
* the client and server supported it. The SCRAM exchange * the client and server supported it. The SCRAM exchange
* checks for that, to prevent downgrade attacks. * checks for that, to prevent downgrade attacks.
*/ */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("server offered SCRAM-SHA-256-PLUS authentication over a non-SSL connection\n")); libpq_gettext("server offered SCRAM-SHA-256-PLUS authentication over a non-SSL connection\n"));
goto error; goto error;
} }
...@@ -517,7 +521,7 @@ pg_SASL_init(PGconn *conn, int payloadlen) ...@@ -517,7 +521,7 @@ pg_SASL_init(PGconn *conn, int payloadlen)
if (!selected_mechanism) if (!selected_mechanism)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("none of the server's SASL authentication mechanisms are supported\n")); libpq_gettext("none of the server's SASL authentication mechanisms are supported\n"));
goto error; goto error;
} }
...@@ -525,7 +529,7 @@ pg_SASL_init(PGconn *conn, int payloadlen) ...@@ -525,7 +529,7 @@ pg_SASL_init(PGconn *conn, int payloadlen)
if (conn->channel_binding[0] == 'r' && /* require */ if (conn->channel_binding[0] == 'r' && /* require */
strcmp(selected_mechanism, SCRAM_SHA_256_PLUS_NAME) != 0) strcmp(selected_mechanism, SCRAM_SHA_256_PLUS_NAME) != 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("channel binding is required, but server did not offer an authentication method that supports channel binding\n")); libpq_gettext("channel binding is required, but server did not offer an authentication method that supports channel binding\n"));
goto error; goto error;
} }
...@@ -546,7 +550,7 @@ pg_SASL_init(PGconn *conn, int payloadlen) ...@@ -546,7 +550,7 @@ pg_SASL_init(PGconn *conn, int payloadlen)
password = conn->pgpass; password = conn->pgpass;
if (password == NULL || password[0] == '\0') if (password == NULL || password[0] == '\0')
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
PQnoPasswordSupplied); PQnoPasswordSupplied);
goto error; goto error;
} }
...@@ -607,7 +611,7 @@ oom_error: ...@@ -607,7 +611,7 @@ oom_error:
termPQExpBuffer(&mechanism_buf); termPQExpBuffer(&mechanism_buf);
if (initialresponse) if (initialresponse)
free(initialresponse); free(initialresponse);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return STATUS_ERROR; return STATUS_ERROR;
} }
...@@ -631,7 +635,7 @@ pg_SASL_continue(PGconn *conn, int payloadlen, bool final) ...@@ -631,7 +635,7 @@ pg_SASL_continue(PGconn *conn, int payloadlen, bool final)
challenge = malloc(payloadlen + 1); challenge = malloc(payloadlen + 1);
if (!challenge) if (!challenge)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("out of memory allocating SASL buffer (%d)\n"), libpq_gettext("out of memory allocating SASL buffer (%d)\n"),
payloadlen); payloadlen);
return STATUS_ERROR; return STATUS_ERROR;
...@@ -656,7 +660,7 @@ pg_SASL_continue(PGconn *conn, int payloadlen, bool final) ...@@ -656,7 +660,7 @@ pg_SASL_continue(PGconn *conn, int payloadlen, bool final)
if (outputlen != 0) if (outputlen != 0)
free(output); free(output);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("AuthenticationSASLFinal received from server, but SASL authentication was not completed\n")); libpq_gettext("AuthenticationSASLFinal received from server, but SASL authentication was not completed\n"));
return STATUS_ERROR; return STATUS_ERROR;
} }
...@@ -726,14 +730,14 @@ pg_local_sendauth(PGconn *conn) ...@@ -726,14 +730,14 @@ pg_local_sendauth(PGconn *conn)
{ {
char sebuf[PG_STRERROR_R_BUFLEN]; char sebuf[PG_STRERROR_R_BUFLEN];
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
"pg_local_sendauth: sendmsg: %s\n", "pg_local_sendauth: sendmsg: %s\n",
strerror_r(errno, sebuf, sizeof(sebuf))); strerror_r(errno, sebuf, sizeof(sebuf)));
return STATUS_ERROR; return STATUS_ERROR;
} }
return STATUS_OK; return STATUS_OK;
#else #else
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("SCM_CRED authentication method not supported\n")); libpq_gettext("SCM_CRED authentication method not supported\n"));
return STATUS_ERROR; return STATUS_ERROR;
#endif #endif
...@@ -766,7 +770,7 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq) ...@@ -766,7 +770,7 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1)); crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1));
if (!crypt_pwd) if (!crypt_pwd)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return STATUS_ERROR; return STATUS_ERROR;
} }
...@@ -832,13 +836,13 @@ check_expected_areq(AuthRequest areq, PGconn *conn) ...@@ -832,13 +836,13 @@ check_expected_areq(AuthRequest areq, PGconn *conn)
case AUTH_REQ_OK: case AUTH_REQ_OK:
if (!pg_fe_scram_channel_bound(conn->sasl_state)) if (!pg_fe_scram_channel_bound(conn->sasl_state))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("channel binding required, but server authenticated client without channel binding\n")); libpq_gettext("channel binding required, but server authenticated client without channel binding\n"));
result = false; result = false;
} }
break; break;
default: default:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("channel binding required but not supported by server's authentication request\n")); libpq_gettext("channel binding required but not supported by server's authentication request\n"));
result = false; result = false;
break; break;
...@@ -862,6 +866,8 @@ check_expected_areq(AuthRequest areq, PGconn *conn) ...@@ -862,6 +866,8 @@ check_expected_areq(AuthRequest areq, PGconn *conn)
int int
pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
{ {
int oldmsglen;
if (!check_expected_areq(areq, conn)) if (!check_expected_areq(areq, conn))
return STATUS_ERROR; return STATUS_ERROR;
...@@ -871,12 +877,12 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) ...@@ -871,12 +877,12 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
break; break;
case AUTH_REQ_KRB4: case AUTH_REQ_KRB4:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("Kerberos 4 authentication not supported\n")); libpq_gettext("Kerberos 4 authentication not supported\n"));
return STATUS_ERROR; return STATUS_ERROR;
case AUTH_REQ_KRB5: case AUTH_REQ_KRB5:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("Kerberos 5 authentication not supported\n")); libpq_gettext("Kerberos 5 authentication not supported\n"));
return STATUS_ERROR; return STATUS_ERROR;
...@@ -947,7 +953,7 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) ...@@ -947,7 +953,7 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
/* No GSSAPI *or* SSPI support */ /* No GSSAPI *or* SSPI support */
case AUTH_REQ_GSS: case AUTH_REQ_GSS:
case AUTH_REQ_GSS_CONT: case AUTH_REQ_GSS_CONT:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("GSSAPI authentication not supported\n")); libpq_gettext("GSSAPI authentication not supported\n"));
return STATUS_ERROR; return STATUS_ERROR;
#endif /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */ #endif /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
...@@ -979,7 +985,7 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) ...@@ -979,7 +985,7 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
*/ */
#if !defined(ENABLE_GSS) #if !defined(ENABLE_GSS)
case AUTH_REQ_SSPI: case AUTH_REQ_SSPI:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("SSPI authentication not supported\n")); libpq_gettext("SSPI authentication not supported\n"));
return STATUS_ERROR; return STATUS_ERROR;
#endif /* !define(ENABLE_GSS) */ #endif /* !define(ENABLE_GSS) */
...@@ -987,7 +993,7 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) ...@@ -987,7 +993,7 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
case AUTH_REQ_CRYPT: case AUTH_REQ_CRYPT:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("Crypt authentication not supported\n")); libpq_gettext("Crypt authentication not supported\n"));
return STATUS_ERROR; return STATUS_ERROR;
...@@ -1002,13 +1008,13 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) ...@@ -1002,13 +1008,13 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
password = conn->pgpass; password = conn->pgpass;
if (password == NULL || password[0] == '\0') if (password == NULL || password[0] == '\0')
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
PQnoPasswordSupplied); PQnoPasswordSupplied);
return STATUS_ERROR; return STATUS_ERROR;
} }
if (pg_password_sendauth(conn, password, areq) != STATUS_OK) if (pg_password_sendauth(conn, password, areq) != STATUS_OK)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
"fe_sendauth: error sending password authentication\n"); "fe_sendauth: error sending password authentication\n");
return STATUS_ERROR; return STATUS_ERROR;
} }
...@@ -1032,16 +1038,17 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) ...@@ -1032,16 +1038,17 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
case AUTH_REQ_SASL_FIN: case AUTH_REQ_SASL_FIN:
if (conn->sasl_state == NULL) if (conn->sasl_state == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
"fe_sendauth: invalid authentication request from server: AUTH_REQ_SASL_CONT without AUTH_REQ_SASL\n"); "fe_sendauth: invalid authentication request from server: AUTH_REQ_SASL_CONT without AUTH_REQ_SASL\n");
return STATUS_ERROR; return STATUS_ERROR;
} }
oldmsglen = conn->errorMessage.len;
if (pg_SASL_continue(conn, payloadlen, if (pg_SASL_continue(conn, payloadlen,
(areq == AUTH_REQ_SASL_FIN)) != STATUS_OK) (areq == AUTH_REQ_SASL_FIN)) != STATUS_OK)
{ {
/* Use error message, if set already */ /* Use this message if pg_SASL_continue didn't supply one */
if (conn->errorMessage.len == 0) if (conn->errorMessage.len == oldmsglen)
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
"fe_sendauth: error in SASL authentication\n"); "fe_sendauth: error in SASL authentication\n");
return STATUS_ERROR; return STATUS_ERROR;
} }
...@@ -1053,7 +1060,7 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) ...@@ -1053,7 +1060,7 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
break; break;
default: default:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("authentication method %u not supported\n"), areq); libpq_gettext("authentication method %u not supported\n"), areq);
return STATUS_ERROR; return STATUS_ERROR;
} }
...@@ -1067,7 +1074,7 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) ...@@ -1067,7 +1074,7 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
* *
* Returns a pointer to malloc'd space containing whatever name the user * Returns a pointer to malloc'd space containing whatever name the user
* has authenticated to the system. If there is an error, return NULL, * has authenticated to the system. If there is an error, return NULL,
* and put a suitable error message in *errorMessage if that's not NULL. * and append a suitable error message to *errorMessage if that's not NULL.
*/ */
char * char *
pg_fe_getauthname(PQExpBuffer errorMessage) pg_fe_getauthname(PQExpBuffer errorMessage)
...@@ -1100,7 +1107,7 @@ pg_fe_getauthname(PQExpBuffer errorMessage) ...@@ -1100,7 +1107,7 @@ pg_fe_getauthname(PQExpBuffer errorMessage)
if (GetUserName(username, &namesize)) if (GetUserName(username, &namesize))
name = username; name = username;
else if (errorMessage) else if (errorMessage)
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("user name lookup failure: error code %lu\n"), libpq_gettext("user name lookup failure: error code %lu\n"),
GetLastError()); GetLastError());
#else #else
...@@ -1110,12 +1117,12 @@ pg_fe_getauthname(PQExpBuffer errorMessage) ...@@ -1110,12 +1117,12 @@ pg_fe_getauthname(PQExpBuffer errorMessage)
else if (errorMessage) else if (errorMessage)
{ {
if (pwerr != 0) if (pwerr != 0)
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("could not look up local user ID %d: %s\n"), libpq_gettext("could not look up local user ID %d: %s\n"),
(int) user_id, (int) user_id,
strerror_r(pwerr, pwdbuf, sizeof(pwdbuf))); strerror_r(pwerr, pwdbuf, sizeof(pwdbuf)));
else else
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("local user with ID %d does not exist\n"), libpq_gettext("local user with ID %d does not exist\n"),
(int) user_id); (int) user_id);
} }
...@@ -1125,7 +1132,7 @@ pg_fe_getauthname(PQExpBuffer errorMessage) ...@@ -1125,7 +1132,7 @@ pg_fe_getauthname(PQExpBuffer errorMessage)
{ {
result = strdup(name); result = strdup(name);
if (result == NULL && errorMessage) if (result == NULL && errorMessage)
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
} }
...@@ -1196,6 +1203,8 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, ...@@ -1196,6 +1203,8 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user,
if (!conn) if (!conn)
return NULL; return NULL;
resetPQExpBuffer(&conn->errorMessage);
/* If no algorithm was given, ask the server. */ /* If no algorithm was given, ask the server. */
if (algorithm == NULL) if (algorithm == NULL)
{ {
...@@ -1217,7 +1226,7 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, ...@@ -1217,7 +1226,7 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user,
if (PQntuples(res) != 1 || PQnfields(res) != 1) if (PQntuples(res) != 1 || PQnfields(res) != 1)
{ {
PQclear(res); PQclear(res);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("unexpected shape of result set returned for SHOW\n")); libpq_gettext("unexpected shape of result set returned for SHOW\n"));
return NULL; return NULL;
} }
...@@ -1226,7 +1235,7 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, ...@@ -1226,7 +1235,7 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user,
if (strlen(val) > MAX_ALGORITHM_NAME_LEN) if (strlen(val) > MAX_ALGORITHM_NAME_LEN)
{ {
PQclear(res); PQclear(res);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("password_encryption value too long\n")); libpq_gettext("password_encryption value too long\n"));
return NULL; return NULL;
} }
...@@ -1266,14 +1275,14 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, ...@@ -1266,14 +1275,14 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user,
} }
else else
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("unrecognized password encryption algorithm \"%s\"\n"), libpq_gettext("unrecognized password encryption algorithm \"%s\"\n"),
algorithm); algorithm);
return NULL; return NULL;
} }
if (!crypt_pwd) if (!crypt_pwd)
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return crypt_pwd; return crypt_pwd;
......
...@@ -755,7 +755,9 @@ PQconnectStartParams(const char *const *keywords, ...@@ -755,7 +755,9 @@ PQconnectStartParams(const char *const *keywords,
PQconninfoOption *connOptions; PQconninfoOption *connOptions;
/* /*
* Allocate memory for the conn structure * Allocate memory for the conn structure. Note that we also expect this
* to initialize conn->errorMessage to empty. All subsequent steps during
* connection initialization will only append to that buffer.
*/ */
conn = makeEmptyPGconn(); conn = makeEmptyPGconn();
if (conn == NULL) if (conn == NULL)
...@@ -831,7 +833,9 @@ PQconnectStart(const char *conninfo) ...@@ -831,7 +833,9 @@ PQconnectStart(const char *conninfo)
PGconn *conn; PGconn *conn;
/* /*
* Allocate memory for the conn structure * Allocate memory for the conn structure. Note that we also expect this
* to initialize conn->errorMessage to empty. All subsequent steps during
* connection initialization will only append to that buffer.
*/ */
conn = makeEmptyPGconn(); conn = makeEmptyPGconn();
if (conn == NULL) if (conn == NULL)
...@@ -889,7 +893,7 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions) ...@@ -889,7 +893,7 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
*connmember = strdup(tmp); *connmember = strdup(tmp);
if (*connmember == NULL) if (*connmember == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return false; return false;
} }
...@@ -1072,7 +1076,7 @@ connectOptions2(PGconn *conn) ...@@ -1072,7 +1076,7 @@ connectOptions2(PGconn *conn)
if (more || i != conn->nconnhost) if (more || i != conn->nconnhost)
{ {
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not match %d host names to %d hostaddr values\n"), libpq_gettext("could not match %d host names to %d hostaddr values\n"),
count_comma_separated_elems(conn->pghost), conn->nconnhost); count_comma_separated_elems(conn->pghost), conn->nconnhost);
return false; return false;
...@@ -1153,7 +1157,7 @@ connectOptions2(PGconn *conn) ...@@ -1153,7 +1157,7 @@ connectOptions2(PGconn *conn)
else if (more || i != conn->nconnhost) else if (more || i != conn->nconnhost)
{ {
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not match %d port numbers to %d hosts\n"), libpq_gettext("could not match %d port numbers to %d hosts\n"),
count_comma_separated_elems(conn->pgport), conn->nconnhost); count_comma_separated_elems(conn->pgport), conn->nconnhost);
return false; return false;
...@@ -1246,7 +1250,7 @@ connectOptions2(PGconn *conn) ...@@ -1246,7 +1250,7 @@ connectOptions2(PGconn *conn)
&& strcmp(conn->channel_binding, "require") != 0) && strcmp(conn->channel_binding, "require") != 0)
{ {
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("invalid %s value: \"%s\"\n"), libpq_gettext("invalid %s value: \"%s\"\n"),
"channel_binding", conn->channel_binding); "channel_binding", conn->channel_binding);
return false; return false;
...@@ -1272,7 +1276,7 @@ connectOptions2(PGconn *conn) ...@@ -1272,7 +1276,7 @@ connectOptions2(PGconn *conn)
&& strcmp(conn->sslmode, "verify-full") != 0) && strcmp(conn->sslmode, "verify-full") != 0)
{ {
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("invalid %s value: \"%s\"\n"), libpq_gettext("invalid %s value: \"%s\"\n"),
"sslmode", conn->sslmode); "sslmode", conn->sslmode);
return false; return false;
...@@ -1293,7 +1297,7 @@ connectOptions2(PGconn *conn) ...@@ -1293,7 +1297,7 @@ connectOptions2(PGconn *conn)
case 'r': /* "require" */ case 'r': /* "require" */
case 'v': /* "verify-ca" or "verify-full" */ case 'v': /* "verify-ca" or "verify-full" */
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("sslmode value \"%s\" invalid when SSL support is not compiled in\n"), libpq_gettext("sslmode value \"%s\" invalid when SSL support is not compiled in\n"),
conn->sslmode); conn->sslmode);
return false; return false;
...@@ -1314,7 +1318,7 @@ connectOptions2(PGconn *conn) ...@@ -1314,7 +1318,7 @@ connectOptions2(PGconn *conn)
if (!sslVerifyProtocolVersion(conn->ssl_min_protocol_version)) if (!sslVerifyProtocolVersion(conn->ssl_min_protocol_version))
{ {
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("invalid %s value: \"%s\"\n"), libpq_gettext("invalid %s value: \"%s\"\n"),
"ssl_min_protocol_version", "ssl_min_protocol_version",
conn->ssl_min_protocol_version); conn->ssl_min_protocol_version);
...@@ -1323,7 +1327,7 @@ connectOptions2(PGconn *conn) ...@@ -1323,7 +1327,7 @@ connectOptions2(PGconn *conn)
if (!sslVerifyProtocolVersion(conn->ssl_max_protocol_version)) if (!sslVerifyProtocolVersion(conn->ssl_max_protocol_version))
{ {
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("invalid %s value: \"%s\"\n"), libpq_gettext("invalid %s value: \"%s\"\n"),
"ssl_max_protocol_version", "ssl_max_protocol_version",
conn->ssl_max_protocol_version); conn->ssl_max_protocol_version);
...@@ -1341,7 +1345,7 @@ connectOptions2(PGconn *conn) ...@@ -1341,7 +1345,7 @@ connectOptions2(PGconn *conn)
conn->ssl_max_protocol_version)) conn->ssl_max_protocol_version))
{ {
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("invalid SSL protocol version range\n")); libpq_gettext("invalid SSL protocol version range\n"));
return false; return false;
} }
...@@ -1356,7 +1360,7 @@ connectOptions2(PGconn *conn) ...@@ -1356,7 +1360,7 @@ connectOptions2(PGconn *conn)
strcmp(conn->gssencmode, "require") != 0) strcmp(conn->gssencmode, "require") != 0)
{ {
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("invalid %s value: \"%s\"\n"), libpq_gettext("invalid %s value: \"%s\"\n"),
"gssencmode", "gssencmode",
conn->gssencmode); conn->gssencmode);
...@@ -1366,7 +1370,7 @@ connectOptions2(PGconn *conn) ...@@ -1366,7 +1370,7 @@ connectOptions2(PGconn *conn)
if (strcmp(conn->gssencmode, "require") == 0) if (strcmp(conn->gssencmode, "require") == 0)
{ {
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("gssencmode value \"%s\" invalid when GSSAPI support is not compiled in\n"), libpq_gettext("gssencmode value \"%s\" invalid when GSSAPI support is not compiled in\n"),
conn->gssencmode); conn->gssencmode);
return false; return false;
...@@ -1401,7 +1405,7 @@ connectOptions2(PGconn *conn) ...@@ -1401,7 +1405,7 @@ connectOptions2(PGconn *conn)
&& strcmp(conn->target_session_attrs, "read-write") != 0) && strcmp(conn->target_session_attrs, "read-write") != 0)
{ {
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("invalid %s value: \"%s\"\n"), libpq_gettext("invalid %s value: \"%s\"\n"),
"target_settion_attrs", "target_settion_attrs",
conn->target_session_attrs); conn->target_session_attrs);
...@@ -1420,7 +1424,7 @@ connectOptions2(PGconn *conn) ...@@ -1420,7 +1424,7 @@ connectOptions2(PGconn *conn)
oom_error: oom_error:
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return false; return false;
} }
...@@ -1487,7 +1491,9 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, ...@@ -1487,7 +1491,9 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
PGconn *conn; PGconn *conn;
/* /*
* Allocate memory for the conn structure * Allocate memory for the conn structure. Note that we also expect this
* to initialize conn->errorMessage to empty. All subsequent steps during
* connection initialization will only append to that buffer.
*/ */
conn = makeEmptyPGconn(); conn = makeEmptyPGconn();
if (conn == NULL) if (conn == NULL)
...@@ -1596,7 +1602,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, ...@@ -1596,7 +1602,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
oom_error: oom_error:
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return conn; return conn;
} }
...@@ -2017,7 +2023,7 @@ connectDBStart(PGconn *conn) ...@@ -2017,7 +2023,7 @@ connectDBStart(PGconn *conn)
*/ */
if (!pg_link_canary_is_frontend()) if (!pg_link_canary_is_frontend())
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
"libpq is incorrectly linked to backend functions\n"); "libpq is incorrectly linked to backend functions\n");
goto connect_errReturn; goto connect_errReturn;
} }
...@@ -2026,14 +2032,6 @@ connectDBStart(PGconn *conn) ...@@ -2026,14 +2032,6 @@ connectDBStart(PGconn *conn)
conn->inStart = conn->inCursor = conn->inEnd = 0; conn->inStart = conn->inCursor = conn->inEnd = 0;
conn->outCount = 0; conn->outCount = 0;
/*
* Ensure errorMessage is empty, too. PQconnectPoll will append messages
* to it in the process of scanning for a working server. Thus, if we
* fail to connect to multiple hosts, the final error message will include
* details about each failure.
*/
resetPQExpBuffer(&conn->errorMessage);
/* /*
* Set up to try to connect to the first host. (Setting whichhost = -1 is * Set up to try to connect to the first host. (Setting whichhost = -1 is
* a bit of a cheat, but PQconnectPoll will advance it to 0 before * a bit of a cheat, but PQconnectPoll will advance it to 0 before
...@@ -2139,12 +2137,6 @@ connectDBComplete(PGconn *conn) ...@@ -2139,12 +2137,6 @@ connectDBComplete(PGconn *conn)
switch (flag) switch (flag)
{ {
case PGRES_POLLING_OK: case PGRES_POLLING_OK:
/*
* Reset stored error messages since we now have a working
* connection
*/
resetPQExpBuffer(&conn->errorMessage);
return 1; /* success! */ return 1; /* success! */
case PGRES_POLLING_READING: case PGRES_POLLING_READING:
...@@ -2189,46 +2181,6 @@ connectDBComplete(PGconn *conn) ...@@ -2189,46 +2181,6 @@ connectDBComplete(PGconn *conn)
} }
} }
/*
* This subroutine saves conn->errorMessage, which will be restored back by
* restoreErrorMessage subroutine. Returns false on OOM failure.
*/
static bool
saveErrorMessage(PGconn *conn, PQExpBuffer savedMessage)
{
initPQExpBuffer(savedMessage);
appendPQExpBufferStr(savedMessage,
conn->errorMessage.data);
if (PQExpBufferBroken(savedMessage))
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("out of memory\n"));
return false;
}
/* Clear whatever is in errorMessage now */
resetPQExpBuffer(&conn->errorMessage);
return true;
}
/*
* Restores saved error messages back to conn->errorMessage, prepending them
* to whatever is in conn->errorMessage already. (This does the right thing
* if anything's been added to conn->errorMessage since saveErrorMessage.)
*/
static void
restoreErrorMessage(PGconn *conn, PQExpBuffer savedMessage)
{
appendPQExpBufferStr(savedMessage, conn->errorMessage.data);
resetPQExpBuffer(&conn->errorMessage);
appendPQExpBufferStr(&conn->errorMessage, savedMessage->data);
/* If any step above hit OOM, just report that */
if (PQExpBufferBroken(savedMessage) ||
PQExpBufferBroken(&conn->errorMessage))
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("out of memory\n"));
termPQExpBuffer(savedMessage);
}
/* ---------------- /* ----------------
* PQconnectPoll * PQconnectPoll
* *
...@@ -2264,7 +2216,6 @@ PQconnectPoll(PGconn *conn) ...@@ -2264,7 +2216,6 @@ PQconnectPoll(PGconn *conn)
PGresult *res; PGresult *res;
char sebuf[PG_STRERROR_R_BUFLEN]; char sebuf[PG_STRERROR_R_BUFLEN];
int optval; int optval;
PQExpBufferData savedMessage;
if (conn == NULL) if (conn == NULL)
return PGRES_POLLING_FAILED; return PGRES_POLLING_FAILED;
...@@ -2954,11 +2905,7 @@ keep_going: /* We will come back to here until there is ...@@ -2954,11 +2905,7 @@ keep_going: /* We will come back to here until there is
EnvironmentOptions); EnvironmentOptions);
if (!startpacket) if (!startpacket)
{ {
/* appendPQExpBufferStr(&conn->errorMessage,
* will not appendbuffer here, since it's likely to also
* run out of memory
*/
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
goto error_return; goto error_return;
} }
...@@ -3448,7 +3395,6 @@ keep_going: /* We will come back to here until there is ...@@ -3448,7 +3395,6 @@ keep_going: /* We will come back to here until there is
* avoid the Kerberos code doing a hostname look-up. * avoid the Kerberos code doing a hostname look-up.
*/ */
res = pg_fe_sendauth(areq, msgLength, conn); res = pg_fe_sendauth(areq, msgLength, conn);
conn->errorMessage.len = strlen(conn->errorMessage.data);
/* OK, we have processed the message; mark data consumed */ /* OK, we have processed the message; mark data consumed */
conn->inStart = conn->inCursor; conn->inStart = conn->inCursor;
...@@ -3576,24 +3522,16 @@ keep_going: /* We will come back to here until there is ...@@ -3576,24 +3522,16 @@ keep_going: /* We will come back to here until there is
strcmp(conn->target_session_attrs, "read-write") == 0) strcmp(conn->target_session_attrs, "read-write") == 0)
{ {
/* /*
* Save existing error messages across the PQsendQuery * We use PQsendQueryContinue so that conn->errorMessage
* attempt. This is necessary because PQsendQuery is * does not get cleared. We need to preserve any error
* going to reset conn->errorMessage, so we would lose * messages related to previous hosts we have tried and
* error messages related to previous hosts we have tried * failed to connect to.
* and failed to connect to.
*/ */
if (!saveErrorMessage(conn, &savedMessage))
goto error_return;
conn->status = CONNECTION_OK; conn->status = CONNECTION_OK;
if (!PQsendQuery(conn, if (!PQsendQueryContinue(conn,
"SHOW transaction_read_only")) "SHOW transaction_read_only"))
{
restoreErrorMessage(conn, &savedMessage);
goto error_return; goto error_return;
}
conn->status = CONNECTION_CHECK_WRITABLE; conn->status = CONNECTION_CHECK_WRITABLE;
restoreErrorMessage(conn, &savedMessage);
return PGRES_POLLING_READING; return PGRES_POLLING_READING;
} }
...@@ -3673,20 +3611,13 @@ keep_going: /* We will come back to here until there is ...@@ -3673,20 +3611,13 @@ keep_going: /* We will come back to here until there is
const char *displayed_host; const char *displayed_host;
const char *displayed_port; const char *displayed_port;
if (!saveErrorMessage(conn, &savedMessage))
goto error_return;
conn->status = CONNECTION_OK; conn->status = CONNECTION_OK;
if (!PQconsumeInput(conn)) if (!PQconsumeInput(conn))
{
restoreErrorMessage(conn, &savedMessage);
goto error_return; goto error_return;
}
if (PQisBusy(conn)) if (PQisBusy(conn))
{ {
conn->status = CONNECTION_CHECK_WRITABLE; conn->status = CONNECTION_CHECK_WRITABLE;
restoreErrorMessage(conn, &savedMessage);
return PGRES_POLLING_READING; return PGRES_POLLING_READING;
} }
...@@ -3701,7 +3632,6 @@ keep_going: /* We will come back to here until there is ...@@ -3701,7 +3632,6 @@ keep_going: /* We will come back to here until there is
{ {
/* Not writable; fail this connection. */ /* Not writable; fail this connection. */
PQclear(res); PQclear(res);
restoreErrorMessage(conn, &savedMessage);
/* Append error report to conn->errorMessage. */ /* Append error report to conn->errorMessage. */
if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS) if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
...@@ -3732,7 +3662,6 @@ keep_going: /* We will come back to here until there is ...@@ -3732,7 +3662,6 @@ keep_going: /* We will come back to here until there is
/* Session is read-write, so we're good. */ /* Session is read-write, so we're good. */
PQclear(res); PQclear(res);
termPQExpBuffer(&savedMessage);
/* /*
* Finish reading any remaining messages before being * Finish reading any remaining messages before being
...@@ -3748,7 +3677,6 @@ keep_going: /* We will come back to here until there is ...@@ -3748,7 +3677,6 @@ keep_going: /* We will come back to here until there is
*/ */
if (res) if (res)
PQclear(res); PQclear(res);
restoreErrorMessage(conn, &savedMessage);
/* Append error report to conn->errorMessage. */ /* Append error report to conn->errorMessage. */
if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS) if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
...@@ -4157,6 +4085,9 @@ closePGconn(PGconn *conn) ...@@ -4157,6 +4085,9 @@ closePGconn(PGconn *conn)
/* /*
* Close the connection, reset all transient state, flush I/O buffers. * Close the connection, reset all transient state, flush I/O buffers.
* Note that this includes clearing conn->errorMessage; we're no longer
* interested in any failures associated with the old connection, and we
* want a clean slate for any new connection attempt.
*/ */
pqDropConnection(conn, true); pqDropConnection(conn, true);
conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just absent */ conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just absent */
...@@ -4212,7 +4143,7 @@ PQreset(PGconn *conn) ...@@ -4212,7 +4143,7 @@ PQreset(PGconn *conn)
conn->events[i].passThrough)) conn->events[i].passThrough))
{ {
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("PGEventProc \"%s\" failed during PGEVT_CONNRESET event\n"), libpq_gettext("PGEventProc \"%s\" failed during PGEVT_CONNRESET event\n"),
conn->events[i].name); conn->events[i].name);
break; break;
...@@ -4272,7 +4203,7 @@ PQresetPoll(PGconn *conn) ...@@ -4272,7 +4203,7 @@ PQresetPoll(PGconn *conn)
conn->events[i].passThrough)) conn->events[i].passThrough))
{ {
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("PGEventProc \"%s\" failed during PGEVT_CONNRESET event\n"), libpq_gettext("PGEventProc \"%s\" failed during PGEVT_CONNRESET event\n"),
conn->events[i].name); conn->events[i].name);
return PGRES_POLLING_FAILED; return PGRES_POLLING_FAILED;
...@@ -4569,7 +4500,7 @@ pqPacketSend(PGconn *conn, char pack_type, ...@@ -4569,7 +4500,7 @@ pqPacketSend(PGconn *conn, char pack_type,
* 2 if a connection could not be established, and * 2 if a connection could not be established, and
* 3 if a fatal error occurred. * 3 if a fatal error occurred.
* *
* An error message is returned in the third argument for return codes 1 and 3. * An error message is appended to *errorMessage for return codes 1 and 3.
*/ */
static int static int
ldapServiceLookup(const char *purl, PQconninfoOption *options, ldapServiceLookup(const char *purl, PQconninfoOption *options,
...@@ -4607,7 +4538,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4607,7 +4538,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
if ((url = strdup(purl)) == NULL) if ((url = strdup(purl)) == NULL)
{ {
printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); appendPQExpBufferStr(errorMessage, libpq_gettext("out of memory\n"));
return 3; return 3;
} }
...@@ -4619,7 +4550,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4619,7 +4550,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
if (pg_strncasecmp(url, LDAP_URL, strlen(LDAP_URL)) != 0) if (pg_strncasecmp(url, LDAP_URL, strlen(LDAP_URL)) != 0)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("invalid LDAP URL \"%s\": scheme must be ldap://\n"), purl); libpq_gettext("invalid LDAP URL \"%s\": scheme must be ldap://\n"), purl);
free(url); free(url);
return 3; return 3;
...@@ -4634,7 +4565,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4634,7 +4565,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
p = strchr(url + strlen(LDAP_URL), '/'); p = strchr(url + strlen(LDAP_URL), '/');
if (p == NULL || *(p + 1) == '\0' || *(p + 1) == '?') if (p == NULL || *(p + 1) == '\0' || *(p + 1) == '?')
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("invalid LDAP URL \"%s\": missing distinguished name\n"), libpq_gettext("invalid LDAP URL \"%s\": missing distinguished name\n"),
purl); purl);
free(url); free(url);
...@@ -4646,7 +4577,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4646,7 +4577,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
/* attribute */ /* attribute */
if ((p = strchr(dn, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') if ((p = strchr(dn, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?')
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("invalid LDAP URL \"%s\": must have exactly one attribute\n"), libpq_gettext("invalid LDAP URL \"%s\": must have exactly one attribute\n"),
purl); purl);
free(url); free(url);
...@@ -4658,7 +4589,9 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4658,7 +4589,9 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
/* scope */ /* scope */
if ((p = strchr(attrs[0], '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') if ((p = strchr(attrs[0], '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?')
{ {
printfPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": must have search scope (base/one/sub)\n"), purl); appendPQExpBuffer(errorMessage,
libpq_gettext("invalid LDAP URL \"%s\": must have search scope (base/one/sub)\n"),
purl);
free(url); free(url);
return 3; return 3;
} }
...@@ -4668,8 +4601,9 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4668,8 +4601,9 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
/* filter */ /* filter */
if ((p = strchr(scopestr, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') if ((p = strchr(scopestr, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?')
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("invalid LDAP URL \"%s\": no filter\n"), purl); libpq_gettext("invalid LDAP URL \"%s\": no filter\n"),
purl);
free(url); free(url);
return 3; return 3;
} }
...@@ -4689,7 +4623,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4689,7 +4623,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
lport = strtol(portstr, &endptr, 10); lport = strtol(portstr, &endptr, 10);
if (*portstr == '\0' || *endptr != '\0' || errno || lport < 0 || lport > 65535) if (*portstr == '\0' || *endptr != '\0' || errno || lport < 0 || lport > 65535)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("invalid LDAP URL \"%s\": invalid port number\n"), libpq_gettext("invalid LDAP URL \"%s\": invalid port number\n"),
purl); purl);
free(url); free(url);
...@@ -4701,7 +4635,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4701,7 +4635,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
/* Allow only one attribute */ /* Allow only one attribute */
if (strchr(attrs[0], ',') != NULL) if (strchr(attrs[0], ',') != NULL)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("invalid LDAP URL \"%s\": must have exactly one attribute\n"), libpq_gettext("invalid LDAP URL \"%s\": must have exactly one attribute\n"),
purl); purl);
free(url); free(url);
...@@ -4717,7 +4651,9 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4717,7 +4651,9 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
scope = LDAP_SCOPE_SUBTREE; scope = LDAP_SCOPE_SUBTREE;
else else
{ {
printfPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": must have search scope (base/one/sub)\n"), purl); appendPQExpBuffer(errorMessage,
libpq_gettext("invalid LDAP URL \"%s\": must have search scope (base/one/sub)\n"),
purl);
free(url); free(url);
return 3; return 3;
} }
...@@ -4725,7 +4661,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4725,7 +4661,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
/* initialize LDAP structure */ /* initialize LDAP structure */
if ((ld = ldap_init(hostname, port)) == NULL) if ((ld = ldap_init(hostname, port)) == NULL)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("could not create LDAP structure\n")); libpq_gettext("could not create LDAP structure\n"));
free(url); free(url);
return 3; return 3;
...@@ -4801,7 +4737,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4801,7 +4737,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
{ {
if (res != NULL) if (res != NULL)
ldap_msgfree(res); ldap_msgfree(res);
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("lookup on LDAP server failed: %s\n"), libpq_gettext("lookup on LDAP server failed: %s\n"),
ldap_err2string(rc)); ldap_err2string(rc));
ldap_unbind(ld); ldap_unbind(ld);
...@@ -4812,7 +4748,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4812,7 +4748,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
/* complain if there was not exactly one result */ /* complain if there was not exactly one result */
if ((rc = ldap_count_entries(ld, res)) != 1) if ((rc = ldap_count_entries(ld, res)) != 1)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
rc ? libpq_gettext("more than one entry found on LDAP lookup\n") rc ? libpq_gettext("more than one entry found on LDAP lookup\n")
: libpq_gettext("no entry found on LDAP lookup\n")); : libpq_gettext("no entry found on LDAP lookup\n"));
ldap_msgfree(res); ldap_msgfree(res);
...@@ -4825,7 +4761,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4825,7 +4761,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
if ((entry = ldap_first_entry(ld, res)) == NULL) if ((entry = ldap_first_entry(ld, res)) == NULL)
{ {
/* should never happen */ /* should never happen */
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("no entry found on LDAP lookup\n")); libpq_gettext("no entry found on LDAP lookup\n"));
ldap_msgfree(res); ldap_msgfree(res);
ldap_unbind(ld); ldap_unbind(ld);
...@@ -4836,7 +4772,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4836,7 +4772,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
/* get values */ /* get values */
if ((values = ldap_get_values_len(ld, entry, attrs[0])) == NULL) if ((values = ldap_get_values_len(ld, entry, attrs[0])) == NULL)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("attribute has no values on LDAP lookup\n")); libpq_gettext("attribute has no values on LDAP lookup\n"));
ldap_msgfree(res); ldap_msgfree(res);
ldap_unbind(ld); ldap_unbind(ld);
...@@ -4849,7 +4785,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4849,7 +4785,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
if (values[0] == NULL) if (values[0] == NULL)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("attribute has no values on LDAP lookup\n")); libpq_gettext("attribute has no values on LDAP lookup\n"));
ldap_value_free_len(values); ldap_value_free_len(values);
ldap_unbind(ld); ldap_unbind(ld);
...@@ -4862,7 +4798,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4862,7 +4798,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
size += values[i]->bv_len + 1; size += values[i]->bv_len + 1;
if ((result = malloc(size)) == NULL) if ((result = malloc(size)) == NULL)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
ldap_value_free_len(values); ldap_value_free_len(values);
ldap_unbind(ld); ldap_unbind(ld);
...@@ -4901,7 +4837,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4901,7 +4837,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
} }
else if (ld_is_nl_cr(*p)) else if (ld_is_nl_cr(*p))
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"), libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"),
optname); optname);
free(result); free(result);
...@@ -4920,7 +4856,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4920,7 +4856,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
} }
else if (!ld_is_sp_tab(*p)) else if (!ld_is_sp_tab(*p))
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"), libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"),
optname); optname);
free(result); free(result);
...@@ -4981,7 +4917,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4981,7 +4917,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
options[i].val = strdup(optval); options[i].val = strdup(optval);
if (!options[i].val) if (!options[i].val)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
free(result); free(result);
return 3; return 3;
...@@ -4993,7 +4929,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -4993,7 +4929,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
} }
if (!found_keyword) if (!found_keyword)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("invalid connection option \"%s\"\n"), libpq_gettext("invalid connection option \"%s\"\n"),
optname); optname);
free(result); free(result);
...@@ -5009,7 +4945,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, ...@@ -5009,7 +4945,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
if (state == 5 || state == 6) if (state == 5 || state == 6)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("unterminated quoted string in connection info string\n")); libpq_gettext("unterminated quoted string in connection info string\n"));
return 3; return 3;
} }
...@@ -5090,7 +5026,7 @@ next_file: ...@@ -5090,7 +5026,7 @@ next_file:
last_file: last_file:
if (!group_found) if (!group_found)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("definition of service \"%s\" not found\n"), service); libpq_gettext("definition of service \"%s\" not found\n"), service);
return 3; return 3;
} }
...@@ -5117,7 +5053,7 @@ parseServiceFile(const char *serviceFile, ...@@ -5117,7 +5053,7 @@ parseServiceFile(const char *serviceFile,
f = fopen(serviceFile, "r"); f = fopen(serviceFile, "r");
if (f == NULL) if (f == NULL)
{ {
printfPQExpBuffer(errorMessage, libpq_gettext("service file \"%s\" not found\n"), appendPQExpBuffer(errorMessage, libpq_gettext("service file \"%s\" not found\n"),
serviceFile); serviceFile);
return 1; return 1;
} }
...@@ -5193,7 +5129,7 @@ parseServiceFile(const char *serviceFile, ...@@ -5193,7 +5129,7 @@ parseServiceFile(const char *serviceFile,
val = strchr(line, '='); val = strchr(line, '=');
if (val == NULL) if (val == NULL)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("syntax error in service file \"%s\", line %d\n"), libpq_gettext("syntax error in service file \"%s\", line %d\n"),
serviceFile, serviceFile,
linenr); linenr);
...@@ -5204,7 +5140,7 @@ parseServiceFile(const char *serviceFile, ...@@ -5204,7 +5140,7 @@ parseServiceFile(const char *serviceFile,
if (strcmp(key, "service") == 0) if (strcmp(key, "service") == 0)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("nested service specifications not supported in service file \"%s\", line %d\n"), libpq_gettext("nested service specifications not supported in service file \"%s\", line %d\n"),
serviceFile, serviceFile,
linenr); linenr);
...@@ -5225,7 +5161,7 @@ parseServiceFile(const char *serviceFile, ...@@ -5225,7 +5161,7 @@ parseServiceFile(const char *serviceFile,
options[i].val = strdup(val); options[i].val = strdup(val);
if (!options[i].val) if (!options[i].val)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
result = 3; result = 3;
goto exit; goto exit;
...@@ -5237,7 +5173,7 @@ parseServiceFile(const char *serviceFile, ...@@ -5237,7 +5173,7 @@ parseServiceFile(const char *serviceFile,
if (!found_keyword) if (!found_keyword)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("syntax error in service file \"%s\", line %d\n"), libpq_gettext("syntax error in service file \"%s\", line %d\n"),
serviceFile, serviceFile,
linenr); linenr);
...@@ -5307,7 +5243,7 @@ conninfo_init(PQExpBuffer errorMessage) ...@@ -5307,7 +5243,7 @@ conninfo_init(PQExpBuffer errorMessage)
options = (PQconninfoOption *) malloc(sizeof(PQconninfoOption) * sizeof(PQconninfoOptions) / sizeof(PQconninfoOptions[0])); options = (PQconninfoOption *) malloc(sizeof(PQconninfoOption) * sizeof(PQconninfoOptions) / sizeof(PQconninfoOptions[0]));
if (options == NULL) if (options == NULL)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return NULL; return NULL;
} }
...@@ -5328,7 +5264,7 @@ conninfo_init(PQExpBuffer errorMessage) ...@@ -5328,7 +5264,7 @@ conninfo_init(PQExpBuffer errorMessage)
* Connection string parser * Connection string parser
* *
* Returns a malloc'd PQconninfoOption array, if parsing is successful. * Returns a malloc'd PQconninfoOption array, if parsing is successful.
* Otherwise, NULL is returned and an error message is left in errorMessage. * Otherwise, NULL is returned and an error message is added to errorMessage.
* *
* If use_defaults is true, default values are filled in (from a service file, * If use_defaults is true, default values are filled in (from a service file,
* environment variables, etc). * environment variables, etc).
...@@ -5406,7 +5342,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, ...@@ -5406,7 +5342,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage,
/* Need a modifiable copy of the input string */ /* Need a modifiable copy of the input string */
if ((buf = strdup(conninfo)) == NULL) if ((buf = strdup(conninfo)) == NULL)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
PQconninfoFree(options); PQconninfoFree(options);
return NULL; return NULL;
...@@ -5445,7 +5381,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, ...@@ -5445,7 +5381,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage,
/* Check that there is a following '=' */ /* Check that there is a following '=' */
if (*cp != '=') if (*cp != '=')
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"), libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"),
pname); pname);
PQconninfoFree(options); PQconninfoFree(options);
...@@ -5494,7 +5430,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, ...@@ -5494,7 +5430,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage,
{ {
if (*cp == '\0') if (*cp == '\0')
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("unterminated quoted string in connection info string\n")); libpq_gettext("unterminated quoted string in connection info string\n"));
PQconninfoFree(options); PQconninfoFree(options);
free(buf); free(buf);
...@@ -5551,7 +5487,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, ...@@ -5551,7 +5487,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage,
* *
* If successful, a malloc'd PQconninfoOption array is returned. * If successful, a malloc'd PQconninfoOption array is returned.
* If not successful, NULL is returned and an error message is * If not successful, NULL is returned and an error message is
* left in errorMessage. * appended to errorMessage.
* Defaults are supplied (from a service file, environment variables, etc) * Defaults are supplied (from a service file, environment variables, etc)
* for unspecified options, but only if use_defaults is true. * for unspecified options, but only if use_defaults is true.
* *
...@@ -5630,7 +5566,7 @@ conninfo_array_parse(const char *const *keywords, const char *const *values, ...@@ -5630,7 +5566,7 @@ conninfo_array_parse(const char *const *keywords, const char *const *values,
/* Check for invalid connection option */ /* Check for invalid connection option */
if (option->keyword == NULL) if (option->keyword == NULL)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("invalid connection option \"%s\"\n"), libpq_gettext("invalid connection option \"%s\"\n"),
pname); pname);
PQconninfoFree(options); PQconninfoFree(options);
...@@ -5662,7 +5598,7 @@ conninfo_array_parse(const char *const *keywords, const char *const *values, ...@@ -5662,7 +5598,7 @@ conninfo_array_parse(const char *const *keywords, const char *const *values,
options[k].val = strdup(str_option->val); options[k].val = strdup(str_option->val);
if (!options[k].val) if (!options[k].val)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
PQconninfoFree(options); PQconninfoFree(options);
PQconninfoFree(dbname_options); PQconninfoFree(dbname_options);
...@@ -5691,7 +5627,7 @@ conninfo_array_parse(const char *const *keywords, const char *const *values, ...@@ -5691,7 +5627,7 @@ conninfo_array_parse(const char *const *keywords, const char *const *values,
option->val = strdup(pvalue); option->val = strdup(pvalue);
if (!option->val) if (!option->val)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
PQconninfoFree(options); PQconninfoFree(options);
PQconninfoFree(dbname_options); PQconninfoFree(dbname_options);
...@@ -5763,7 +5699,7 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage) ...@@ -5763,7 +5699,7 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage)
if (!option->val) if (!option->val)
{ {
if (errorMessage) if (errorMessage)
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return false; return false;
} }
...@@ -5787,7 +5723,7 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage) ...@@ -5787,7 +5723,7 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage)
if (!option->val) if (!option->val)
{ {
if (errorMessage) if (errorMessage)
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return false; return false;
} }
...@@ -5805,7 +5741,7 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage) ...@@ -5805,7 +5741,7 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage)
if (!option->val) if (!option->val)
{ {
if (errorMessage) if (errorMessage)
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return false; return false;
} }
...@@ -5906,7 +5842,7 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, ...@@ -5906,7 +5842,7 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri,
initPQExpBuffer(&portbuf); initPQExpBuffer(&portbuf);
if (PQExpBufferDataBroken(hostbuf) || PQExpBufferDataBroken(portbuf)) if (PQExpBufferDataBroken(hostbuf) || PQExpBufferDataBroken(portbuf))
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
goto cleanup; goto cleanup;
} }
...@@ -5915,7 +5851,7 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, ...@@ -5915,7 +5851,7 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri,
buf = strdup(uri); buf = strdup(uri);
if (buf == NULL) if (buf == NULL)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBufferStr(errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
goto cleanup; goto cleanup;
} }
...@@ -5926,7 +5862,7 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, ...@@ -5926,7 +5862,7 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri,
if (prefix_len == 0) if (prefix_len == 0)
{ {
/* Should never happen */ /* Should never happen */
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("invalid URI propagated to internal parser routine: \"%s\"\n"), libpq_gettext("invalid URI propagated to internal parser routine: \"%s\"\n"),
uri); uri);
goto cleanup; goto cleanup;
...@@ -6003,14 +5939,14 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, ...@@ -6003,14 +5939,14 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri,
++p; ++p;
if (!*p) if (!*p)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("end of string reached when looking for matching \"]\" in IPv6 host address in URI: \"%s\"\n"), libpq_gettext("end of string reached when looking for matching \"]\" in IPv6 host address in URI: \"%s\"\n"),
uri); uri);
goto cleanup; goto cleanup;
} }
if (p == host) if (p == host)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("IPv6 host address may not be empty in URI: \"%s\"\n"), libpq_gettext("IPv6 host address may not be empty in URI: \"%s\"\n"),
uri); uri);
goto cleanup; goto cleanup;
...@@ -6025,7 +5961,7 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, ...@@ -6025,7 +5961,7 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri,
*/ */
if (*p && *p != ':' && *p != '/' && *p != '?' && *p != ',') if (*p && *p != ':' && *p != '/' && *p != '?' && *p != ',')
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("unexpected character \"%c\" at position %d in URI (expected \":\" or \"/\"): \"%s\"\n"), libpq_gettext("unexpected character \"%c\" at position %d in URI (expected \":\" or \"/\"): \"%s\"\n"),
*p, (int) (p - buf + 1), uri); *p, (int) (p - buf + 1), uri);
goto cleanup; goto cleanup;
...@@ -6142,6 +6078,7 @@ conninfo_uri_parse_params(char *params, ...@@ -6142,6 +6078,7 @@ conninfo_uri_parse_params(char *params,
char *value = NULL; char *value = NULL;
char *p = params; char *p = params;
bool malloced = false; bool malloced = false;
int oldmsglen;
/* /*
* Scan the params string for '=' and '&', marking the end of keyword * Scan the params string for '=' and '&', marking the end of keyword
...@@ -6154,7 +6091,7 @@ conninfo_uri_parse_params(char *params, ...@@ -6154,7 +6091,7 @@ conninfo_uri_parse_params(char *params,
/* Was there '=' already? */ /* Was there '=' already? */
if (value != NULL) if (value != NULL)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("extra key/value separator \"=\" in URI query parameter: \"%s\"\n"), libpq_gettext("extra key/value separator \"=\" in URI query parameter: \"%s\"\n"),
keyword); keyword);
return false; return false;
...@@ -6174,7 +6111,7 @@ conninfo_uri_parse_params(char *params, ...@@ -6174,7 +6111,7 @@ conninfo_uri_parse_params(char *params,
/* Was there '=' at all? */ /* Was there '=' at all? */
if (value == NULL) if (value == NULL)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("missing key/value separator \"=\" in URI query parameter: \"%s\"\n"), libpq_gettext("missing key/value separator \"=\" in URI query parameter: \"%s\"\n"),
keyword); keyword);
return false; return false;
...@@ -6220,12 +6157,13 @@ conninfo_uri_parse_params(char *params, ...@@ -6220,12 +6157,13 @@ conninfo_uri_parse_params(char *params,
* otherwise. At this point both keyword and value are not * otherwise. At this point both keyword and value are not
* URI-encoded. * URI-encoded.
*/ */
oldmsglen = errorMessage->len;
if (!conninfo_storeval(connOptions, keyword, value, if (!conninfo_storeval(connOptions, keyword, value,
errorMessage, true, false)) errorMessage, true, false))
{ {
/* Insert generic message if conninfo_storeval didn't give one. */ /* Insert generic message if conninfo_storeval didn't give one. */
if (errorMessage->len == 0) if (errorMessage->len == oldmsglen)
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("invalid URI query parameter: \"%s\"\n"), libpq_gettext("invalid URI query parameter: \"%s\"\n"),
keyword); keyword);
/* And fail. */ /* And fail. */
...@@ -6272,7 +6210,7 @@ conninfo_uri_decode(const char *str, PQExpBuffer errorMessage) ...@@ -6272,7 +6210,7 @@ conninfo_uri_decode(const char *str, PQExpBuffer errorMessage)
buf = malloc(strlen(str) + 1); buf = malloc(strlen(str) + 1);
if (buf == NULL) if (buf == NULL)
{ {
printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); appendPQExpBufferStr(errorMessage, libpq_gettext("out of memory\n"));
return NULL; return NULL;
} }
p = buf; p = buf;
...@@ -6299,7 +6237,7 @@ conninfo_uri_decode(const char *str, PQExpBuffer errorMessage) ...@@ -6299,7 +6237,7 @@ conninfo_uri_decode(const char *str, PQExpBuffer errorMessage)
*/ */
if (!(get_hexdigit(*q++, &hi) && get_hexdigit(*q++, &lo))) if (!(get_hexdigit(*q++, &hi) && get_hexdigit(*q++, &lo)))
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("invalid percent-encoded token: \"%s\"\n"), libpq_gettext("invalid percent-encoded token: \"%s\"\n"),
str); str);
free(buf); free(buf);
...@@ -6309,7 +6247,7 @@ conninfo_uri_decode(const char *str, PQExpBuffer errorMessage) ...@@ -6309,7 +6247,7 @@ conninfo_uri_decode(const char *str, PQExpBuffer errorMessage)
c = (hi << 4) | lo; c = (hi << 4) | lo;
if (c == 0) if (c == 0)
{ {
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("forbidden value %%00 in percent-encoded value: \"%s\"\n"), libpq_gettext("forbidden value %%00 in percent-encoded value: \"%s\"\n"),
str); str);
free(buf); free(buf);
...@@ -6404,7 +6342,7 @@ conninfo_storeval(PQconninfoOption *connOptions, ...@@ -6404,7 +6342,7 @@ conninfo_storeval(PQconninfoOption *connOptions,
if (option == NULL) if (option == NULL)
{ {
if (!ignoreMissing) if (!ignoreMissing)
printfPQExpBuffer(errorMessage, appendPQExpBuffer(errorMessage,
libpq_gettext("invalid connection option \"%s\"\n"), libpq_gettext("invalid connection option \"%s\"\n"),
keyword); keyword);
return NULL; return NULL;
...@@ -6422,7 +6360,7 @@ conninfo_storeval(PQconninfoOption *connOptions, ...@@ -6422,7 +6360,7 @@ conninfo_storeval(PQconninfoOption *connOptions,
value_copy = strdup(value); value_copy = strdup(value);
if (value_copy == NULL) if (value_copy == NULL)
{ {
printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); appendPQExpBufferStr(errorMessage, libpq_gettext("out of memory\n"));
return NULL; return NULL;
} }
} }
...@@ -6469,7 +6407,10 @@ PQconninfo(PGconn *conn) ...@@ -6469,7 +6407,10 @@ PQconninfo(PGconn *conn)
if (conn == NULL) if (conn == NULL)
return NULL; return NULL;
/* We don't actually report any errors here, but callees want a buffer */ /*
* We don't actually report any errors here, but callees want a buffer,
* and we prefer not to trash the conn's errorMessage.
*/
initPQExpBuffer(&errorBuf); initPQExpBuffer(&errorBuf);
if (PQExpBufferDataBroken(errorBuf)) if (PQExpBufferDataBroken(errorBuf))
return NULL; /* out of memory already :-( */ return NULL; /* out of memory already :-( */
......
...@@ -53,7 +53,8 @@ static bool static_std_strings = false; ...@@ -53,7 +53,8 @@ static bool static_std_strings = false;
static PGEvent *dupEvents(PGEvent *events, int count, size_t *memSize); static PGEvent *dupEvents(PGEvent *events, int count, size_t *memSize);
static bool pqAddTuple(PGresult *res, PGresAttValue *tup, static bool pqAddTuple(PGresult *res, PGresAttValue *tup,
const char **errmsgp); const char **errmsgp);
static bool PQsendQueryStart(PGconn *conn); static int PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery);
static bool PQsendQueryStart(PGconn *conn, bool newQuery);
static int PQsendQueryGuts(PGconn *conn, static int PQsendQueryGuts(PGconn *conn,
const char *command, const char *command,
const char *stmtName, const char *stmtName,
...@@ -667,25 +668,6 @@ pqSetResultError(PGresult *res, const char *msg) ...@@ -667,25 +668,6 @@ pqSetResultError(PGresult *res, const char *msg)
res->errMsg = NULL; res->errMsg = NULL;
} }
/*
* pqCatenateResultError -
* concatenate a new error message to the one already in a PGresult
*/
void
pqCatenateResultError(PGresult *res, const char *msg)
{
PQExpBufferData errorBuf;
if (!res || !msg)
return;
initPQExpBuffer(&errorBuf);
if (res->errMsg)
appendPQExpBufferStr(&errorBuf, res->errMsg);
appendPQExpBufferStr(&errorBuf, msg);
pqSetResultError(res, errorBuf.data);
termPQExpBuffer(&errorBuf);
}
/* /*
* PQclear - * PQclear -
* free's the memory associated with a PGresult * free's the memory associated with a PGresult
...@@ -759,68 +741,46 @@ pqClearAsyncResult(PGconn *conn) ...@@ -759,68 +741,46 @@ pqClearAsyncResult(PGconn *conn)
/* /*
* This subroutine deletes any existing async result, sets conn->result * This subroutine deletes any existing async result, sets conn->result
* to a PGresult with status PGRES_FATAL_ERROR, and stores the current * to a PGresult with status PGRES_FATAL_ERROR, and stores the current
* contents of conn->errorMessage into that result. It differs from a * contents of conn->errorMessage into that result.
* plain call on PQmakeEmptyPGresult() in that if there is already an
* async result with status PGRES_FATAL_ERROR, the current error message
* is APPENDED to the old error message instead of replacing it. This
* behavior lets us report multiple error conditions properly, if necessary.
* (An example where this is needed is when the backend sends an 'E' message
* and immediately closes the connection --- we want to report both the
* backend error and the connection closure error.)
*/ */
void void
pqSaveErrorResult(PGconn *conn) pqSaveErrorResult(PGconn *conn)
{ {
/*
* If no old async result, just let PQmakeEmptyPGresult make one. Likewise
* if old result is not an error message.
*/
if (conn->result == NULL ||
conn->result->resultStatus != PGRES_FATAL_ERROR ||
conn->result->errMsg == NULL)
{
pqClearAsyncResult(conn); pqClearAsyncResult(conn);
conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
}
else
{
/* Else, concatenate error message to existing async result. */
pqCatenateResultError(conn->result, conn->errorMessage.data);
}
} }
/* /*
* As above, and append conn->write_err_msg to whatever other error we have. * As above, after appending conn->write_err_msg to whatever other error we
* This is used when we've detected a write failure and have exhausted our * have. This is used when we've detected a write failure and have exhausted
* chances of reporting something else instead. * our chances of reporting something else instead.
*/ */
static void static void
pqSaveWriteError(PGconn *conn) pqSaveWriteError(PGconn *conn)
{ {
/* /*
* Ensure conn->result is an error result, and add anything in * If write_err_msg is null because of previous strdup failure, do what we
* conn->errorMessage to it. * can. (It's likely our machinations here will get OOM failures as well,
*/ * but might as well try.)
pqSaveErrorResult(conn);
/*
* Now append write_err_msg to that. If it's null because of previous
* strdup failure, do what we can. (It's likely our machinations here are
* all getting OOM failures as well, but ...)
*/ */
if (conn->write_err_msg && conn->write_err_msg[0] != '\0') if (conn->write_err_msg)
pqCatenateResultError(conn->result, conn->write_err_msg); {
appendPQExpBufferStr(&conn->errorMessage, conn->write_err_msg);
/* Avoid possibly appending the same message twice */
conn->write_err_msg[0] = '\0';
}
else else
pqCatenateResultError(conn->result, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("write to server failed\n")); libpq_gettext("write to server failed\n"));
pqSaveErrorResult(conn);
} }
/* /*
* This subroutine prepares an async result object for return to the caller. * This subroutine prepares an async result object for return to the caller.
* If there is not already an async result object, build an error object * If there is not already an async result object, build an error object
* using whatever is in conn->errorMessage. In any case, clear the async * using whatever is in conn->errorMessage. In any case, clear the async
* result storage and make sure PQerrorMessage will agree with the result's * result storage.
* error string.
*/ */
PGresult * PGresult *
pqPrepareAsyncResult(PGconn *conn) pqPrepareAsyncResult(PGconn *conn)
...@@ -835,16 +795,6 @@ pqPrepareAsyncResult(PGconn *conn) ...@@ -835,16 +795,6 @@ pqPrepareAsyncResult(PGconn *conn)
res = conn->result; res = conn->result;
if (!res) if (!res)
res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
else
{
/*
* Make sure PQerrorMessage agrees with result; it could be different
* if we have concatenated messages.
*/
resetPQExpBuffer(&conn->errorMessage);
appendPQExpBufferStr(&conn->errorMessage,
PQresultErrorMessage(res));
}
/* /*
* Replace conn->result with next_result, if any. In the normal case * Replace conn->result with next_result, if any. In the normal case
...@@ -1229,17 +1179,32 @@ fail: ...@@ -1229,17 +1179,32 @@ fail:
* *
* Returns: 1 if successfully submitted * Returns: 1 if successfully submitted
* 0 if error (conn->errorMessage is set) * 0 if error (conn->errorMessage is set)
*
* PQsendQueryContinue is a non-exported version that behaves identically
* except that it doesn't reset conn->errorMessage.
*/ */
int int
PQsendQuery(PGconn *conn, const char *query) PQsendQuery(PGconn *conn, const char *query)
{ {
if (!PQsendQueryStart(conn)) return PQsendQueryInternal(conn, query, true);
}
int
PQsendQueryContinue(PGconn *conn, const char *query)
{
return PQsendQueryInternal(conn, query, false);
}
static int
PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery)
{
if (!PQsendQueryStart(conn, newQuery))
return 0; return 0;
/* check the argument */ /* check the argument */
if (!query) if (!query)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("command string is a null pointer\n")); libpq_gettext("command string is a null pointer\n"));
return 0; return 0;
} }
...@@ -1291,19 +1256,19 @@ PQsendQueryParams(PGconn *conn, ...@@ -1291,19 +1256,19 @@ PQsendQueryParams(PGconn *conn,
const int *paramFormats, const int *paramFormats,
int resultFormat) int resultFormat)
{ {
if (!PQsendQueryStart(conn)) if (!PQsendQueryStart(conn, true))
return 0; return 0;
/* check the arguments */ /* check the arguments */
if (!command) if (!command)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("command string is a null pointer\n")); libpq_gettext("command string is a null pointer\n"));
return 0; return 0;
} }
if (nParams < 0 || nParams > 65535) if (nParams < 0 || nParams > 65535)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("number of parameters must be between 0 and 65535\n")); libpq_gettext("number of parameters must be between 0 and 65535\n"));
return 0; return 0;
} }
...@@ -1331,25 +1296,25 @@ PQsendPrepare(PGconn *conn, ...@@ -1331,25 +1296,25 @@ PQsendPrepare(PGconn *conn,
const char *stmtName, const char *query, const char *stmtName, const char *query,
int nParams, const Oid *paramTypes) int nParams, const Oid *paramTypes)
{ {
if (!PQsendQueryStart(conn)) if (!PQsendQueryStart(conn, true))
return 0; return 0;
/* check the arguments */ /* check the arguments */
if (!stmtName) if (!stmtName)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("statement name is a null pointer\n")); libpq_gettext("statement name is a null pointer\n"));
return 0; return 0;
} }
if (!query) if (!query)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("command string is a null pointer\n")); libpq_gettext("command string is a null pointer\n"));
return 0; return 0;
} }
if (nParams < 0 || nParams > 65535) if (nParams < 0 || nParams > 65535)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("number of parameters must be between 0 and 65535\n")); libpq_gettext("number of parameters must be between 0 and 65535\n"));
return 0; return 0;
} }
...@@ -1357,7 +1322,7 @@ PQsendPrepare(PGconn *conn, ...@@ -1357,7 +1322,7 @@ PQsendPrepare(PGconn *conn,
/* This isn't gonna work on a 2.0 server */ /* This isn't gonna work on a 2.0 server */
if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("function requires at least protocol version 3.0\n")); libpq_gettext("function requires at least protocol version 3.0\n"));
return 0; return 0;
} }
...@@ -1432,19 +1397,19 @@ PQsendQueryPrepared(PGconn *conn, ...@@ -1432,19 +1397,19 @@ PQsendQueryPrepared(PGconn *conn,
const int *paramFormats, const int *paramFormats,
int resultFormat) int resultFormat)
{ {
if (!PQsendQueryStart(conn)) if (!PQsendQueryStart(conn, true))
return 0; return 0;
/* check the arguments */ /* check the arguments */
if (!stmtName) if (!stmtName)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("statement name is a null pointer\n")); libpq_gettext("statement name is a null pointer\n"));
return 0; return 0;
} }
if (nParams < 0 || nParams > 65535) if (nParams < 0 || nParams > 65535)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("number of parameters must be between 0 and 65535\n")); libpq_gettext("number of parameters must be between 0 and 65535\n"));
return 0; return 0;
} }
...@@ -1464,25 +1429,28 @@ PQsendQueryPrepared(PGconn *conn, ...@@ -1464,25 +1429,28 @@ PQsendQueryPrepared(PGconn *conn,
* Common startup code for PQsendQuery and sibling routines * Common startup code for PQsendQuery and sibling routines
*/ */
static bool static bool
PQsendQueryStart(PGconn *conn) PQsendQueryStart(PGconn *conn, bool newQuery)
{ {
if (!conn) if (!conn)
return false; return false;
/* clear the error string */ /*
* If this is the beginning of a query cycle, reset the error buffer.
*/
if (newQuery)
resetPQExpBuffer(&conn->errorMessage); resetPQExpBuffer(&conn->errorMessage);
/* Don't try to send if we know there's no live connection. */ /* Don't try to send if we know there's no live connection. */
if (conn->status != CONNECTION_OK) if (conn->status != CONNECTION_OK)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("no connection to the server\n")); libpq_gettext("no connection to the server\n"));
return false; return false;
} }
/* Can't send while already busy, either. */ /* Can't send while already busy, either. */
if (conn->asyncStatus != PGASYNC_IDLE) if (conn->asyncStatus != PGASYNC_IDLE)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("another command is already in progress\n")); libpq_gettext("another command is already in progress\n"));
return false; return false;
} }
...@@ -1520,7 +1488,7 @@ PQsendQueryGuts(PGconn *conn, ...@@ -1520,7 +1488,7 @@ PQsendQueryGuts(PGconn *conn,
/* This isn't gonna work on a 2.0 server */ /* This isn't gonna work on a 2.0 server */
if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("function requires at least protocol version 3.0\n")); libpq_gettext("function requires at least protocol version 3.0\n"));
return 0; return 0;
} }
...@@ -1596,7 +1564,7 @@ PQsendQueryGuts(PGconn *conn, ...@@ -1596,7 +1564,7 @@ PQsendQueryGuts(PGconn *conn,
nbytes = paramLengths[i]; nbytes = paramLengths[i];
else else
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("length must be given for binary parameter\n")); libpq_gettext("length must be given for binary parameter\n"));
goto sendFailed; goto sendFailed;
} }
...@@ -1859,7 +1827,7 @@ PQgetResult(PGconn *conn) ...@@ -1859,7 +1827,7 @@ PQgetResult(PGconn *conn)
res = getCopyResult(conn, PGRES_COPY_BOTH); res = getCopyResult(conn, PGRES_COPY_BOTH);
break; break;
default: default:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("unexpected asyncStatus: %d\n"), libpq_gettext("unexpected asyncStatus: %d\n"),
(int) conn->asyncStatus); (int) conn->asyncStatus);
res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
...@@ -1879,7 +1847,7 @@ PQgetResult(PGconn *conn) ...@@ -1879,7 +1847,7 @@ PQgetResult(PGconn *conn)
if (!res->events[i].proc(PGEVT_RESULTCREATE, &evt, if (!res->events[i].proc(PGEVT_RESULTCREATE, &evt,
res->events[i].passThrough)) res->events[i].passThrough))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("PGEventProc \"%s\" failed during PGEVT_RESULTCREATE event\n"), libpq_gettext("PGEventProc \"%s\" failed during PGEVT_RESULTCREATE event\n"),
res->events[i].name); res->events[i].name);
pqSetResultError(res, conn->errorMessage.data); pqSetResultError(res, conn->errorMessage.data);
...@@ -2025,6 +1993,11 @@ PQexecStart(PGconn *conn) ...@@ -2025,6 +1993,11 @@ PQexecStart(PGconn *conn)
if (!conn) if (!conn)
return false; return false;
/*
* Since this is the beginning of a query cycle, reset the error buffer.
*/
resetPQExpBuffer(&conn->errorMessage);
/* /*
* Silently discard any prior query result that application didn't eat. * Silently discard any prior query result that application didn't eat.
* This is probably poor design, but it's here for backward compatibility. * This is probably poor design, but it's here for backward compatibility.
...@@ -2047,7 +2020,7 @@ PQexecStart(PGconn *conn) ...@@ -2047,7 +2020,7 @@ PQexecStart(PGconn *conn)
else else
{ {
/* In older protocols we have to punt */ /* In older protocols we have to punt */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("COPY IN state must be terminated first\n")); libpq_gettext("COPY IN state must be terminated first\n"));
return false; return false;
} }
...@@ -2067,7 +2040,7 @@ PQexecStart(PGconn *conn) ...@@ -2067,7 +2040,7 @@ PQexecStart(PGconn *conn)
else else
{ {
/* In older protocols we have to punt */ /* In older protocols we have to punt */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("COPY OUT state must be terminated first\n")); libpq_gettext("COPY OUT state must be terminated first\n"));
return false; return false;
} }
...@@ -2075,7 +2048,7 @@ PQexecStart(PGconn *conn) ...@@ -2075,7 +2048,7 @@ PQexecStart(PGconn *conn)
else if (resultStatus == PGRES_COPY_BOTH) else if (resultStatus == PGRES_COPY_BOTH)
{ {
/* We don't allow PQexec during COPY BOTH */ /* We don't allow PQexec during COPY BOTH */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("PQexec not allowed during COPY BOTH\n")); libpq_gettext("PQexec not allowed during COPY BOTH\n"));
return false; return false;
} }
...@@ -2099,8 +2072,9 @@ PQexecFinish(PGconn *conn) ...@@ -2099,8 +2072,9 @@ PQexecFinish(PGconn *conn)
/* /*
* For backwards compatibility, return the last result if there are more * For backwards compatibility, return the last result if there are more
* than one --- but merge error messages if we get more than one error * than one. (We used to have logic here to concatenate successive error
* result. * messages, but now that happens automatically, since conn->errorMessage
* will continue to accumulate errors throughout this loop.)
* *
* We have to stop if we see copy in/out/both, however. We will resume * We have to stop if we see copy in/out/both, however. We will resume
* parsing after application performs the data transfer. * parsing after application performs the data transfer.
...@@ -2111,23 +2085,7 @@ PQexecFinish(PGconn *conn) ...@@ -2111,23 +2085,7 @@ PQexecFinish(PGconn *conn)
while ((result = PQgetResult(conn)) != NULL) while ((result = PQgetResult(conn)) != NULL)
{ {
if (lastResult) if (lastResult)
{
if (lastResult->resultStatus == PGRES_FATAL_ERROR &&
result->resultStatus == PGRES_FATAL_ERROR)
{
pqCatenateResultError(lastResult, result->errMsg);
PQclear(result);
result = lastResult;
/*
* Make sure PQerrorMessage agrees with concatenated result
*/
resetPQExpBuffer(&conn->errorMessage);
appendPQExpBufferStr(&conn->errorMessage, result->errMsg);
}
else
PQclear(lastResult); PQclear(lastResult);
}
lastResult = result; lastResult = result;
if (result->resultStatus == PGRES_COPY_IN || if (result->resultStatus == PGRES_COPY_IN ||
result->resultStatus == PGRES_COPY_OUT || result->resultStatus == PGRES_COPY_OUT ||
...@@ -2223,13 +2181,13 @@ PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target) ...@@ -2223,13 +2181,13 @@ PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target)
if (!desc_target) if (!desc_target)
desc_target = ""; desc_target = "";
if (!PQsendQueryStart(conn)) if (!PQsendQueryStart(conn, true))
return 0; return 0;
/* This isn't gonna work on a 2.0 server */ /* This isn't gonna work on a 2.0 server */
if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("function requires at least protocol version 3.0\n")); libpq_gettext("function requires at least protocol version 3.0\n"));
return 0; return 0;
} }
...@@ -2321,7 +2279,7 @@ PQputCopyData(PGconn *conn, const char *buffer, int nbytes) ...@@ -2321,7 +2279,7 @@ PQputCopyData(PGconn *conn, const char *buffer, int nbytes)
if (conn->asyncStatus != PGASYNC_COPY_IN && if (conn->asyncStatus != PGASYNC_COPY_IN &&
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;
} }
...@@ -2388,7 +2346,7 @@ PQputCopyEnd(PGconn *conn, const char *errormsg) ...@@ -2388,7 +2346,7 @@ PQputCopyEnd(PGconn *conn, const char *errormsg)
if (conn->asyncStatus != PGASYNC_COPY_IN && if (conn->asyncStatus != PGASYNC_COPY_IN &&
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;
} }
...@@ -2431,7 +2389,7 @@ PQputCopyEnd(PGconn *conn, const char *errormsg) ...@@ -2431,7 +2389,7 @@ PQputCopyEnd(PGconn *conn, const char *errormsg)
if (errormsg) if (errormsg)
{ {
/* Oops, no way to do this in 2.0 */ /* Oops, no way to do this in 2.0 */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("function requires at least protocol version 3.0\n")); libpq_gettext("function requires at least protocol version 3.0\n"));
return -1; return -1;
} }
...@@ -2450,7 +2408,6 @@ PQputCopyEnd(PGconn *conn, const char *errormsg) ...@@ -2450,7 +2408,6 @@ PQputCopyEnd(PGconn *conn, const char *errormsg)
conn->asyncStatus = PGASYNC_COPY_OUT; conn->asyncStatus = PGASYNC_COPY_OUT;
else else
conn->asyncStatus = PGASYNC_BUSY; conn->asyncStatus = PGASYNC_BUSY;
resetPQExpBuffer(&conn->errorMessage);
/* Try to flush data */ /* Try to flush data */
if (pqFlush(conn) < 0) if (pqFlush(conn) < 0)
...@@ -2478,7 +2435,7 @@ PQgetCopyData(PGconn *conn, char **buffer, int async) ...@@ -2478,7 +2435,7 @@ PQgetCopyData(PGconn *conn, char **buffer, int async)
if (conn->asyncStatus != PGASYNC_COPY_OUT && if (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 -2; return -2;
} }
...@@ -2662,13 +2619,15 @@ PQfn(PGconn *conn, ...@@ -2662,13 +2619,15 @@ PQfn(PGconn *conn,
if (!conn) if (!conn)
return NULL; return NULL;
/* clear the error string */ /*
* Since this is the beginning of a query cycle, reset the error buffer.
*/
resetPQExpBuffer(&conn->errorMessage); resetPQExpBuffer(&conn->errorMessage);
if (conn->sock == PGINVALID_SOCKET || conn->asyncStatus != PGASYNC_IDLE || if (conn->sock == PGINVALID_SOCKET || conn->asyncStatus != PGASYNC_IDLE ||
conn->result != NULL) conn->result != NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("connection in wrong state\n")); libpq_gettext("connection in wrong state\n"));
return NULL; return NULL;
} }
...@@ -3246,7 +3205,11 @@ PQsetnonblocking(PGconn *conn, int arg) ...@@ -3246,7 +3205,11 @@ PQsetnonblocking(PGconn *conn, int arg)
* need to flush the send queue at this point in order to guarantee proper * need to flush the send queue at this point in order to guarantee proper
* behavior. this is ok because either they are making a transition _from_ * behavior. this is ok because either they are making a transition _from_
* or _to_ blocking mode, either way we can block them. * or _to_ blocking mode, either way we can block them.
*
* Clear errorMessage in case pqFlush adds to it.
*/ */
resetPQExpBuffer(&conn->errorMessage);
/* if we are going from blocking to non-blocking flush here */ /* if we are going from blocking to non-blocking flush here */
if (pqFlush(conn)) if (pqFlush(conn))
return -1; return -1;
...@@ -3388,7 +3351,7 @@ PQescapeStringInternal(PGconn *conn, ...@@ -3388,7 +3351,7 @@ PQescapeStringInternal(PGconn *conn,
if (error) if (error)
*error = 1; *error = 1;
if (conn) if (conn)
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("incomplete multibyte character\n")); libpq_gettext("incomplete multibyte character\n"));
for (; i < len; i++) for (; i < len; i++)
{ {
...@@ -3419,6 +3382,9 @@ PQescapeStringConn(PGconn *conn, ...@@ -3419,6 +3382,9 @@ PQescapeStringConn(PGconn *conn,
*error = 1; *error = 1;
return 0; return 0;
} }
resetPQExpBuffer(&conn->errorMessage);
return PQescapeStringInternal(conn, to, from, length, error, return PQescapeStringInternal(conn, to, from, length, error,
conn->client_encoding, conn->client_encoding,
conn->std_strings); conn->std_strings);
...@@ -3455,6 +3421,8 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident) ...@@ -3455,6 +3421,8 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
if (!conn) if (!conn)
return NULL; return NULL;
resetPQExpBuffer(&conn->errorMessage);
/* Scan the string for characters that must be escaped. */ /* Scan the string for characters that must be escaped. */
for (s = str; (s - str) < len && *s != '\0'; ++s) for (s = str; (s - str) < len && *s != '\0'; ++s)
{ {
...@@ -3472,7 +3440,7 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident) ...@@ -3472,7 +3440,7 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
/* Multibyte character overruns allowable length. */ /* Multibyte character overruns allowable length. */
if ((s - str) + charlen > len || memchr(s, 0, charlen) != NULL) if ((s - str) + charlen > len || memchr(s, 0, charlen) != NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("incomplete multibyte character\n")); libpq_gettext("incomplete multibyte character\n"));
return NULL; return NULL;
} }
...@@ -3490,7 +3458,7 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident) ...@@ -3490,7 +3458,7 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
result = rp = (char *) malloc(result_size); result = rp = (char *) malloc(result_size);
if (rp == NULL) if (rp == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return NULL; return NULL;
} }
...@@ -3655,7 +3623,7 @@ PQescapeByteaInternal(PGconn *conn, ...@@ -3655,7 +3623,7 @@ PQescapeByteaInternal(PGconn *conn,
if (rp == NULL) if (rp == NULL)
{ {
if (conn) if (conn)
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return NULL; return NULL;
} }
...@@ -3717,6 +3685,9 @@ PQescapeByteaConn(PGconn *conn, ...@@ -3717,6 +3685,9 @@ PQescapeByteaConn(PGconn *conn,
{ {
if (!conn) if (!conn)
return NULL; return NULL;
resetPQExpBuffer(&conn->errorMessage);
return PQescapeByteaInternal(conn, from, from_length, to_length, return PQescapeByteaInternal(conn, from, from_length, to_length,
conn->std_strings, conn->std_strings,
(conn->sversion >= 90000)); (conn->sversion >= 90000));
......
...@@ -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,7 +93,7 @@ pg_GSS_load_servicename(PGconn *conn) ...@@ -94,7 +93,7 @@ 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,7 +106,7 @@ pg_GSS_load_servicename(PGconn *conn) ...@@ -107,7 +106,7 @@ 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;
} }
......
...@@ -61,11 +61,8 @@ lo_open(PGconn *conn, Oid lobjId, int mode) ...@@ -61,11 +61,8 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
PQArgBlock argv[2]; PQArgBlock argv[2];
PGresult *res; PGresult *res;
if (conn == NULL || conn->lobjfuncs == NULL)
{
if (lo_initialize(conn) < 0) if (lo_initialize(conn) < 0)
return -1; return -1;
}
argv[0].isint = 1; argv[0].isint = 1;
argv[0].len = 4; argv[0].len = 4;
...@@ -103,11 +100,8 @@ lo_close(PGconn *conn, int fd) ...@@ -103,11 +100,8 @@ lo_close(PGconn *conn, int fd)
int retval; int retval;
int result_len; int result_len;
if (conn == NULL || conn->lobjfuncs == NULL)
{
if (lo_initialize(conn) < 0) if (lo_initialize(conn) < 0)
return -1; return -1;
}
argv[0].isint = 1; argv[0].isint = 1;
argv[0].len = 4; argv[0].len = 4;
...@@ -141,17 +135,15 @@ lo_truncate(PGconn *conn, int fd, size_t len) ...@@ -141,17 +135,15 @@ lo_truncate(PGconn *conn, int fd, size_t len)
int retval; int retval;
int result_len; int result_len;
if (conn == NULL || conn->lobjfuncs == NULL)
{
if (lo_initialize(conn) < 0) if (lo_initialize(conn) < 0)
return -1; return -1;
}
/* Must check this on-the-fly because it's not there pre-8.3 */ /* Must check this on-the-fly because it's not there pre-8.3 */
if (conn->lobjfuncs->fn_lo_truncate == 0) if (conn->lobjfuncs->fn_lo_truncate == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lo_truncate\n")); libpq_gettext("cannot determine OID of function %s\n"),
"lo_truncate");
return -1; return -1;
} }
...@@ -166,7 +158,7 @@ lo_truncate(PGconn *conn, int fd, size_t len) ...@@ -166,7 +158,7 @@ lo_truncate(PGconn *conn, int fd, size_t len)
*/ */
if (len > (size_t) INT_MAX) if (len > (size_t) INT_MAX)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("argument of lo_truncate exceeds integer range\n")); libpq_gettext("argument of lo_truncate exceeds integer range\n"));
return -1; return -1;
} }
...@@ -209,16 +201,14 @@ lo_truncate64(PGconn *conn, int fd, pg_int64 len) ...@@ -209,16 +201,14 @@ lo_truncate64(PGconn *conn, int fd, pg_int64 len)
int retval; int retval;
int result_len; int result_len;
if (conn == NULL || conn->lobjfuncs == NULL)
{
if (lo_initialize(conn) < 0) if (lo_initialize(conn) < 0)
return -1; return -1;
}
if (conn->lobjfuncs->fn_lo_truncate64 == 0) if (conn->lobjfuncs->fn_lo_truncate64 == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lo_truncate64\n")); libpq_gettext("cannot determine OID of function %s\n"),
"lo_truncate64");
return -1; return -1;
} }
...@@ -261,11 +251,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len) ...@@ -261,11 +251,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
PGresult *res; PGresult *res;
int result_len; int result_len;
if (conn == NULL || conn->lobjfuncs == NULL)
{
if (lo_initialize(conn) < 0) if (lo_initialize(conn) < 0)
return -1; return -1;
}
/* /*
* Long ago, somebody thought it'd be a good idea to declare this function * Long ago, somebody thought it'd be a good idea to declare this function
...@@ -275,7 +262,7 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len) ...@@ -275,7 +262,7 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
*/ */
if (len > (size_t) INT_MAX) if (len > (size_t) INT_MAX)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("argument of lo_read exceeds integer range\n")); libpq_gettext("argument of lo_read exceeds integer range\n"));
return -1; return -1;
} }
...@@ -316,11 +303,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len) ...@@ -316,11 +303,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
int result_len; int result_len;
int retval; int retval;
if (conn == NULL || conn->lobjfuncs == NULL)
{
if (lo_initialize(conn) < 0) if (lo_initialize(conn) < 0)
return -1; return -1;
}
/* /*
* Long ago, somebody thought it'd be a good idea to declare this function * Long ago, somebody thought it'd be a good idea to declare this function
...@@ -330,7 +314,7 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len) ...@@ -330,7 +314,7 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
*/ */
if (len > (size_t) INT_MAX) if (len > (size_t) INT_MAX)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("argument of lo_write exceeds integer range\n")); libpq_gettext("argument of lo_write exceeds integer range\n"));
return -1; return -1;
} }
...@@ -369,11 +353,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence) ...@@ -369,11 +353,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
int retval; int retval;
int result_len; int result_len;
if (conn == NULL || conn->lobjfuncs == NULL)
{
if (lo_initialize(conn) < 0) if (lo_initialize(conn) < 0)
return -1; return -1;
}
argv[0].isint = 1; argv[0].isint = 1;
argv[0].len = 4; argv[0].len = 4;
...@@ -413,16 +394,14 @@ lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence) ...@@ -413,16 +394,14 @@ lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence)
pg_int64 retval; pg_int64 retval;
int result_len; int result_len;
if (conn == NULL || conn->lobjfuncs == NULL)
{
if (lo_initialize(conn) < 0) if (lo_initialize(conn) < 0)
return -1; return -1;
}
if (conn->lobjfuncs->fn_lo_lseek64 == 0) if (conn->lobjfuncs->fn_lo_lseek64 == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lo_lseek64\n")); libpq_gettext("cannot determine OID of function %s\n"),
"lo_lseek64");
return -1; return -1;
} }
...@@ -469,11 +448,8 @@ lo_creat(PGconn *conn, int mode) ...@@ -469,11 +448,8 @@ lo_creat(PGconn *conn, int mode)
int retval; int retval;
int result_len; int result_len;
if (conn == NULL || conn->lobjfuncs == NULL)
{
if (lo_initialize(conn) < 0) if (lo_initialize(conn) < 0)
return InvalidOid; return InvalidOid;
}
argv[0].isint = 1; argv[0].isint = 1;
argv[0].len = 4; argv[0].len = 4;
...@@ -508,17 +484,15 @@ lo_create(PGconn *conn, Oid lobjId) ...@@ -508,17 +484,15 @@ lo_create(PGconn *conn, Oid lobjId)
int retval; int retval;
int result_len; int result_len;
if (conn == NULL || conn->lobjfuncs == NULL)
{
if (lo_initialize(conn) < 0) if (lo_initialize(conn) < 0)
return InvalidOid; return InvalidOid;
}
/* Must check this on-the-fly because it's not there pre-8.1 */ /* Must check this on-the-fly because it's not there pre-8.1 */
if (conn->lobjfuncs->fn_lo_create == 0) if (conn->lobjfuncs->fn_lo_create == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lo_create\n")); libpq_gettext("cannot determine OID of function %s\n"),
"lo_create");
return InvalidOid; return InvalidOid;
} }
...@@ -552,11 +526,8 @@ lo_tell(PGconn *conn, int fd) ...@@ -552,11 +526,8 @@ lo_tell(PGconn *conn, int fd)
PGresult *res; PGresult *res;
int result_len; int result_len;
if (conn == NULL || conn->lobjfuncs == NULL)
{
if (lo_initialize(conn) < 0) if (lo_initialize(conn) < 0)
return -1; return -1;
}
argv[0].isint = 1; argv[0].isint = 1;
argv[0].len = 4; argv[0].len = 4;
...@@ -588,16 +559,14 @@ lo_tell64(PGconn *conn, int fd) ...@@ -588,16 +559,14 @@ lo_tell64(PGconn *conn, int fd)
PGresult *res; PGresult *res;
int result_len; int result_len;
if (conn == NULL || conn->lobjfuncs == NULL)
{
if (lo_initialize(conn) < 0) if (lo_initialize(conn) < 0)
return -1; return -1;
}
if (conn->lobjfuncs->fn_lo_tell64 == 0) if (conn->lobjfuncs->fn_lo_tell64 == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lo_tell64\n")); libpq_gettext("cannot determine OID of function %s\n"),
"lo_tell64");
return -1; return -1;
} }
...@@ -632,11 +601,8 @@ lo_unlink(PGconn *conn, Oid lobjId) ...@@ -632,11 +601,8 @@ lo_unlink(PGconn *conn, Oid lobjId)
int result_len; int result_len;
int retval; int retval;
if (conn == NULL || conn->lobjfuncs == NULL)
{
if (lo_initialize(conn) < 0) if (lo_initialize(conn) < 0)
return -1; return -1;
}
argv[0].isint = 1; argv[0].isint = 1;
argv[0].len = 4; argv[0].len = 4;
...@@ -696,13 +662,19 @@ lo_import_internal(PGconn *conn, const char *filename, Oid oid) ...@@ -696,13 +662,19 @@ lo_import_internal(PGconn *conn, const char *filename, Oid oid)
int lobj; int lobj;
char sebuf[PG_STRERROR_R_BUFLEN]; char sebuf[PG_STRERROR_R_BUFLEN];
if (conn == NULL)
return InvalidOid;
/* Since this is the beginning of a query cycle, reset the error buffer */
resetPQExpBuffer(&conn->errorMessage);
/* /*
* open the file to be read in * open the file to be read in
*/ */
fd = open(filename, O_RDONLY | PG_BINARY, 0666); fd = open(filename, O_RDONLY | PG_BINARY, 0666);
if (fd < 0) if (fd < 0)
{ /* error */ { /* error */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not open file \"%s\": %s\n"), libpq_gettext("could not open file \"%s\": %s\n"),
filename, strerror_r(errno, sebuf, sizeof(sebuf))); filename, strerror_r(errno, sebuf, sizeof(sebuf)));
return InvalidOid; return InvalidOid;
...@@ -757,6 +729,7 @@ lo_import_internal(PGconn *conn, const char *filename, Oid oid) ...@@ -757,6 +729,7 @@ lo_import_internal(PGconn *conn, const char *filename, Oid oid)
(void) lo_close(conn, lobj); (void) lo_close(conn, lobj);
(void) close(fd); (void) close(fd);
/* deliberately overwrite any error from lo_close */
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not read from file \"%s\": %s\n"), libpq_gettext("could not read from file \"%s\": %s\n"),
filename, filename,
...@@ -811,6 +784,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename) ...@@ -811,6 +784,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
int save_errno = errno; int save_errno = errno;
(void) lo_close(conn, lobj); (void) lo_close(conn, lobj);
/* deliberately overwrite any error from lo_close */
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not open file \"%s\": %s\n"), libpq_gettext("could not open file \"%s\": %s\n"),
filename, filename,
...@@ -831,6 +805,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename) ...@@ -831,6 +805,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
(void) lo_close(conn, lobj); (void) lo_close(conn, lobj);
(void) close(fd); (void) close(fd);
/* deliberately overwrite any error from lo_close */
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not write to file \"%s\": %s\n"), libpq_gettext("could not write to file \"%s\": %s\n"),
filename, filename,
...@@ -855,7 +830,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename) ...@@ -855,7 +830,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
/* if we already failed, don't overwrite that msg with a close error */ /* if we already failed, don't overwrite that msg with a close error */
if (close(fd) != 0 && result >= 0) if (close(fd) != 0 && result >= 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not write to file \"%s\": %s\n"), libpq_gettext("could not write to file \"%s\": %s\n"),
filename, strerror_r(errno, sebuf, sizeof(sebuf))); filename, strerror_r(errno, sebuf, sizeof(sebuf)));
result = -1; result = -1;
...@@ -868,9 +843,11 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename) ...@@ -868,9 +843,11 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
/* /*
* lo_initialize * lo_initialize
* *
* Initialize the large object interface for an existing connection. * Initialize for a new large-object operation on an existing connection.
* We ask the backend about the functions OID's in pg_proc for all * Return 0 if OK, -1 on failure.
* functions that are required for large object operations. *
* If we haven't previously done so, we collect the function OIDs from
* pg_proc for all functions that are required for large object operations.
*/ */
static int static int
lo_initialize(PGconn *conn) lo_initialize(PGconn *conn)
...@@ -882,16 +859,25 @@ lo_initialize(PGconn *conn) ...@@ -882,16 +859,25 @@ lo_initialize(PGconn *conn)
const char *fname; const char *fname;
Oid foid; Oid foid;
if (!conn) /* Nothing we can do with no connection */
if (conn == NULL)
return -1; return -1;
/* Since this is the beginning of a query cycle, reset the error buffer */
resetPQExpBuffer(&conn->errorMessage);
/* Nothing else to do if we already collected info */
if (conn->lobjfuncs != NULL)
return 0;
/* /*
* Allocate the structure to hold the functions OID's * Allocate the structure to hold the function OIDs. We don't store it
* into the PGconn until it's successfully filled.
*/ */
lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs)); lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
if (lobjfuncs == NULL) if (lobjfuncs == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return -1; return -1;
} }
...@@ -942,7 +928,7 @@ lo_initialize(PGconn *conn) ...@@ -942,7 +928,7 @@ lo_initialize(PGconn *conn)
{ {
free(lobjfuncs); free(lobjfuncs);
PQclear(res); PQclear(res);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("query to initialize large object functions did not return data\n")); libpq_gettext("query to initialize large object functions did not return data\n"));
return -1; return -1;
} }
...@@ -991,57 +977,65 @@ lo_initialize(PGconn *conn) ...@@ -991,57 +977,65 @@ lo_initialize(PGconn *conn)
*/ */
if (lobjfuncs->fn_lo_open == 0) if (lobjfuncs->fn_lo_open == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lo_open\n")); libpq_gettext("cannot determine OID of function %s\n"),
"lo_open");
free(lobjfuncs); free(lobjfuncs);
return -1; return -1;
} }
if (lobjfuncs->fn_lo_close == 0) if (lobjfuncs->fn_lo_close == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lo_close\n")); libpq_gettext("cannot determine OID of function %s\n"),
"lo_close");
free(lobjfuncs); free(lobjfuncs);
return -1; return -1;
} }
if (lobjfuncs->fn_lo_creat == 0) if (lobjfuncs->fn_lo_creat == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lo_creat\n")); libpq_gettext("cannot determine OID of function %s\n"),
"lo_creat");
free(lobjfuncs); free(lobjfuncs);
return -1; return -1;
} }
if (lobjfuncs->fn_lo_unlink == 0) if (lobjfuncs->fn_lo_unlink == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lo_unlink\n")); libpq_gettext("cannot determine OID of function %s\n"),
"lo_unlink");
free(lobjfuncs); free(lobjfuncs);
return -1; return -1;
} }
if (lobjfuncs->fn_lo_lseek == 0) if (lobjfuncs->fn_lo_lseek == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lo_lseek\n")); libpq_gettext("cannot determine OID of function %s\n"),
"lo_lseek");
free(lobjfuncs); free(lobjfuncs);
return -1; return -1;
} }
if (lobjfuncs->fn_lo_tell == 0) if (lobjfuncs->fn_lo_tell == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lo_tell\n")); libpq_gettext("cannot determine OID of function %s\n"),
"lo_tell");
free(lobjfuncs); free(lobjfuncs);
return -1; return -1;
} }
if (lobjfuncs->fn_lo_read == 0) if (lobjfuncs->fn_lo_read == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function loread\n")); libpq_gettext("cannot determine OID of function %s\n"),
"loread");
free(lobjfuncs); free(lobjfuncs);
return -1; return -1;
} }
if (lobjfuncs->fn_lo_write == 0) if (lobjfuncs->fn_lo_write == 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lowrite\n")); libpq_gettext("cannot determine OID of function %s\n"),
"lowrite");
free(lobjfuncs); free(lobjfuncs);
return -1; return -1;
} }
......
...@@ -379,7 +379,7 @@ pqCheckOutBufferSpace(size_t bytes_needed, PGconn *conn) ...@@ -379,7 +379,7 @@ 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,7 +473,7 @@ pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn) ...@@ -473,7 +473,7 @@ 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,7 +619,7 @@ pqReadData(PGconn *conn) ...@@ -619,7 +619,7 @@ 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,7 +798,7 @@ retry4: ...@@ -798,7 +798,7 @@ 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"));
...@@ -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,7 +1056,7 @@ pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time) ...@@ -1056,7 +1056,7 @@ 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,7 +1101,7 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time) ...@@ -1101,7 +1101,7 @@ 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,7 +493,7 @@ pqParseInput2(PGconn *conn) ...@@ -493,7 +493,7 @@ 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,7 +528,7 @@ pqParseInput2(PGconn *conn) ...@@ -528,7 +528,7 @@ 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,11 +1042,10 @@ pqGetErrorNotice2(PGconn *conn, bool isError) ...@@ -1042,11 +1042,10 @@ 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,7 +1202,7 @@ pqGetCopyData2(PGconn *conn, char **buffer, int async) ...@@ -1203,7 +1202,7 @@ 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;
} }
...@@ -1349,7 +1348,7 @@ pqEndcopy2(PGconn *conn) ...@@ -1349,7 +1348,7 @@ 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,7 +202,7 @@ pqParseInput3(PGconn *conn) ...@@ -202,7 +202,7 @@ 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,7 +229,7 @@ pqParseInput3(PGconn *conn) ...@@ -229,7 +229,7 @@ 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,7 +246,7 @@ pqParseInput3(PGconn *conn) ...@@ -246,7 +246,7 @@ 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,7 +326,7 @@ pqParseInput3(PGconn *conn) ...@@ -326,7 +326,7 @@ 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,7 +361,7 @@ pqParseInput3(PGconn *conn) ...@@ -361,7 +361,7 @@ 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 */
...@@ -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,7 +950,7 @@ pqGetErrorNotice3(PGconn *conn, bool isError) ...@@ -950,7 +950,7 @@ 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,7 +1695,7 @@ pqGetCopyData3(PGconn *conn, char **buffer, int async) ...@@ -1695,7 +1695,7 @@ 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;
} }
...@@ -1728,7 +1728,7 @@ pqGetline3(PGconn *conn, char *s, int maxlen) ...@@ -1728,7 +1728,7 @@ 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,7 +1834,7 @@ pqEndcopy3(PGconn *conn) ...@@ -1834,7 +1834,7 @@ 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,7 +94,7 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn, ...@@ -94,7 +94,7 @@ 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,7 +106,7 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn, ...@@ -106,7 +106,7 @@ 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;
} }
...@@ -120,7 +120,7 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn, ...@@ -120,7 +120,7 @@ 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,7 +167,7 @@ pq_verify_peer_name_matches_certificate(PGconn *conn) ...@@ -167,7 +167,7 @@ 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,13 +192,13 @@ pq_verify_peer_name_matches_certificate(PGconn *conn) ...@@ -192,13 +192,13 @@ 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,7 +106,7 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len) ...@@ -106,7 +106,7 @@ 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,7 +205,7 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len) ...@@ -205,7 +205,7 @@ 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;
...@@ -213,7 +213,7 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len) ...@@ -213,7 +213,7 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len)
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,7 +399,7 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len) ...@@ -399,7 +399,7 @@ 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 */
...@@ -500,7 +500,7 @@ pqsecure_open_gss(PGconn *conn) ...@@ -500,7 +500,7 @@ 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;
} }
...@@ -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));
......
...@@ -181,7 +181,7 @@ rloop: ...@@ -181,7 +181,7 @@ rloop:
if (n < 0) if (n < 0)
{ {
/* Not supposed to happen, so we don't translate the msg */ /* Not supposed to happen, so we don't translate the msg */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
"SSL_read failed but did not provide error information\n"); "SSL_read failed but did not provide error information\n");
/* assume the connection is broken */ /* assume the connection is broken */
result_errno = ECONNRESET; result_errno = ECONNRESET;
...@@ -205,19 +205,19 @@ rloop: ...@@ -205,19 +205,19 @@ rloop:
result_errno = SOCK_ERRNO; result_errno = SOCK_ERRNO;
if (result_errno == EPIPE || if (result_errno == EPIPE ||
result_errno == ECONNRESET) result_errno == 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"));
else else
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: %s\n"), libpq_gettext("SSL SYSCALL error: %s\n"),
SOCK_STRERROR(result_errno, SOCK_STRERROR(result_errno,
sebuf, sizeof(sebuf))); sebuf, sizeof(sebuf)));
} }
else else
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: EOF detected\n")); libpq_gettext("SSL SYSCALL error: EOF detected\n"));
/* assume the connection is broken */ /* assume the connection is broken */
result_errno = ECONNRESET; result_errno = ECONNRESET;
...@@ -228,7 +228,7 @@ rloop: ...@@ -228,7 +228,7 @@ rloop:
{ {
char *errm = SSLerrmessage(ecode); char *errm = SSLerrmessage(ecode);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL error: %s\n"), errm); libpq_gettext("SSL error: %s\n"), errm);
SSLerrfree(errm); SSLerrfree(errm);
/* assume the connection is broken */ /* assume the connection is broken */
...@@ -243,13 +243,13 @@ rloop: ...@@ -243,13 +243,13 @@ rloop:
* a clean connection closure, so we should not report it as a * a clean connection closure, so we should not report it as a
* server crash. * server crash.
*/ */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("SSL connection has been closed unexpectedly\n")); libpq_gettext("SSL connection has been closed unexpectedly\n"));
result_errno = ECONNRESET; result_errno = ECONNRESET;
n = -1; n = -1;
break; break;
default: default:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("unrecognized SSL error code: %d\n"), libpq_gettext("unrecognized SSL error code: %d\n"),
err); err);
/* assume the connection is broken */ /* assume the connection is broken */
...@@ -290,7 +290,7 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len) ...@@ -290,7 +290,7 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len)
if (n < 0) if (n < 0)
{ {
/* Not supposed to happen, so we don't translate the msg */ /* Not supposed to happen, so we don't translate the msg */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
"SSL_write failed but did not provide error information\n"); "SSL_write failed but did not provide error information\n");
/* assume the connection is broken */ /* assume the connection is broken */
result_errno = ECONNRESET; result_errno = ECONNRESET;
...@@ -312,19 +312,19 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len) ...@@ -312,19 +312,19 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len)
{ {
result_errno = SOCK_ERRNO; result_errno = SOCK_ERRNO;
if (result_errno == EPIPE || result_errno == ECONNRESET) if (result_errno == EPIPE || result_errno == 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"));
else else
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: %s\n"), libpq_gettext("SSL SYSCALL error: %s\n"),
SOCK_STRERROR(result_errno, SOCK_STRERROR(result_errno,
sebuf, sizeof(sebuf))); sebuf, sizeof(sebuf)));
} }
else else
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: EOF detected\n")); libpq_gettext("SSL SYSCALL error: EOF detected\n"));
/* assume the connection is broken */ /* assume the connection is broken */
result_errno = ECONNRESET; result_errno = ECONNRESET;
...@@ -335,7 +335,7 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len) ...@@ -335,7 +335,7 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len)
{ {
char *errm = SSLerrmessage(ecode); char *errm = SSLerrmessage(ecode);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL error: %s\n"), errm); libpq_gettext("SSL error: %s\n"), errm);
SSLerrfree(errm); SSLerrfree(errm);
/* assume the connection is broken */ /* assume the connection is broken */
...@@ -350,13 +350,13 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len) ...@@ -350,13 +350,13 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len)
* a clean connection closure, so we should not report it as a * a clean connection closure, so we should not report it as a
* server crash. * server crash.
*/ */
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("SSL connection has been closed unexpectedly\n")); libpq_gettext("SSL connection has been closed unexpectedly\n"));
result_errno = ECONNRESET; result_errno = ECONNRESET;
n = -1; n = -1;
break; break;
default: default:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("unrecognized SSL error code: %d\n"), libpq_gettext("unrecognized SSL error code: %d\n"),
err); err);
/* assume the connection is broken */ /* assume the connection is broken */
...@@ -396,7 +396,7 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) ...@@ -396,7 +396,7 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len)
if (!OBJ_find_sigid_algs(X509_get_signature_nid(peer_cert), if (!OBJ_find_sigid_algs(X509_get_signature_nid(peer_cert),
&algo_nid, NULL)) &algo_nid, NULL))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("could not determine server certificate signature algorithm\n")); libpq_gettext("could not determine server certificate signature algorithm\n"));
return NULL; return NULL;
} }
...@@ -417,7 +417,7 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) ...@@ -417,7 +417,7 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len)
algo_type = EVP_get_digestbynid(algo_nid); algo_type = EVP_get_digestbynid(algo_nid);
if (algo_type == NULL) if (algo_type == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not find digest for NID %s\n"), libpq_gettext("could not find digest for NID %s\n"),
OBJ_nid2sn(algo_nid)); OBJ_nid2sn(algo_nid));
return NULL; return NULL;
...@@ -427,7 +427,7 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) ...@@ -427,7 +427,7 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len)
if (!X509_digest(peer_cert, algo_type, hash, &hash_size)) if (!X509_digest(peer_cert, algo_type, hash, &hash_size))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("could not generate peer certificate hash\n")); libpq_gettext("could not generate peer certificate hash\n"));
return NULL; return NULL;
} }
...@@ -436,7 +436,7 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) ...@@ -436,7 +436,7 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len)
cert_hash = malloc(hash_size); cert_hash = malloc(hash_size);
if (cert_hash == NULL) if (cert_hash == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return NULL; return NULL;
} }
...@@ -484,7 +484,7 @@ openssl_verify_peer_name_matches_certificate_name(PGconn *conn, ASN1_STRING *nam ...@@ -484,7 +484,7 @@ openssl_verify_peer_name_matches_certificate_name(PGconn *conn, ASN1_STRING *nam
/* Should not happen... */ /* Should not happen... */
if (name_entry == NULL) if (name_entry == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("SSL certificate's name entry is missing\n")); libpq_gettext("SSL certificate's name entry is missing\n"));
return -1; return -1;
} }
...@@ -811,7 +811,7 @@ initialize_SSL(PGconn *conn) ...@@ -811,7 +811,7 @@ initialize_SSL(PGconn *conn)
{ {
char *err = SSLerrmessage(ERR_get_error()); char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not create SSL context: %s\n"), libpq_gettext("could not create SSL context: %s\n"),
err); err);
SSLerrfree(err); SSLerrfree(err);
...@@ -850,7 +850,7 @@ initialize_SSL(PGconn *conn) ...@@ -850,7 +850,7 @@ initialize_SSL(PGconn *conn)
if (ssl_min_ver == -1) if (ssl_min_ver == -1)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("invalid value \"%s\" for minimum SSL protocol version\n"), libpq_gettext("invalid value \"%s\" for minimum SSL protocol version\n"),
conn->ssl_min_protocol_version); conn->ssl_min_protocol_version);
SSL_CTX_free(SSL_context); SSL_CTX_free(SSL_context);
...@@ -861,7 +861,7 @@ initialize_SSL(PGconn *conn) ...@@ -861,7 +861,7 @@ initialize_SSL(PGconn *conn)
{ {
char *err = SSLerrmessage(ERR_get_error()); char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not set minimum SSL protocol version: %s\n"), libpq_gettext("could not set minimum SSL protocol version: %s\n"),
err); err);
SSLerrfree(err); SSLerrfree(err);
...@@ -879,7 +879,7 @@ initialize_SSL(PGconn *conn) ...@@ -879,7 +879,7 @@ initialize_SSL(PGconn *conn)
if (ssl_max_ver == -1) if (ssl_max_ver == -1)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("invalid value \"%s\" for maximum SSL protocol version\n"), libpq_gettext("invalid value \"%s\" for maximum SSL protocol version\n"),
conn->ssl_max_protocol_version); conn->ssl_max_protocol_version);
SSL_CTX_free(SSL_context); SSL_CTX_free(SSL_context);
...@@ -890,7 +890,7 @@ initialize_SSL(PGconn *conn) ...@@ -890,7 +890,7 @@ initialize_SSL(PGconn *conn)
{ {
char *err = SSLerrmessage(ERR_get_error()); char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not set maximum SSL protocol version: %s\n"), libpq_gettext("could not set maximum SSL protocol version: %s\n"),
err); err);
SSLerrfree(err); SSLerrfree(err);
...@@ -926,7 +926,7 @@ initialize_SSL(PGconn *conn) ...@@ -926,7 +926,7 @@ initialize_SSL(PGconn *conn)
{ {
char *err = SSLerrmessage(ERR_get_error()); char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not read root certificate file \"%s\": %s\n"), libpq_gettext("could not read root certificate file \"%s\": %s\n"),
fnbuf, err); fnbuf, err);
SSLerrfree(err); SSLerrfree(err);
...@@ -970,11 +970,11 @@ initialize_SSL(PGconn *conn) ...@@ -970,11 +970,11 @@ initialize_SSL(PGconn *conn)
* that it seems worth having a specialized error message for it. * that it seems worth having a specialized error message for it.
*/ */
if (fnbuf[0] == '\0') if (fnbuf[0] == '\0')
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get home directory to locate root certificate file\n" libpq_gettext("could not get home directory to locate root certificate file\n"
"Either provide the file or change sslmode to disable server certificate verification.\n")); "Either provide the file or change sslmode to disable server certificate verification.\n"));
else else
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("root certificate file \"%s\" does not exist\n" libpq_gettext("root certificate file \"%s\" does not exist\n"
"Either provide the file or change sslmode to disable server certificate verification.\n"), fnbuf); "Either provide the file or change sslmode to disable server certificate verification.\n"), fnbuf);
SSL_CTX_free(SSL_context); SSL_CTX_free(SSL_context);
...@@ -1005,7 +1005,7 @@ initialize_SSL(PGconn *conn) ...@@ -1005,7 +1005,7 @@ initialize_SSL(PGconn *conn)
*/ */
if (errno != ENOENT && errno != ENOTDIR) if (errno != ENOENT && errno != ENOTDIR)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not open certificate file \"%s\": %s\n"), libpq_gettext("could not open certificate file \"%s\": %s\n"),
fnbuf, strerror_r(errno, sebuf, sizeof(sebuf))); fnbuf, strerror_r(errno, sebuf, sizeof(sebuf)));
SSL_CTX_free(SSL_context); SSL_CTX_free(SSL_context);
...@@ -1024,7 +1024,7 @@ initialize_SSL(PGconn *conn) ...@@ -1024,7 +1024,7 @@ initialize_SSL(PGconn *conn)
{ {
char *err = SSLerrmessage(ERR_get_error()); char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not read certificate file \"%s\": %s\n"), libpq_gettext("could not read certificate file \"%s\": %s\n"),
fnbuf, err); fnbuf, err);
SSLerrfree(err); SSLerrfree(err);
...@@ -1049,7 +1049,7 @@ initialize_SSL(PGconn *conn) ...@@ -1049,7 +1049,7 @@ initialize_SSL(PGconn *conn)
{ {
char *err = SSLerrmessage(ERR_get_error()); char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not establish SSL connection: %s\n"), libpq_gettext("could not establish SSL connection: %s\n"),
err); err);
SSLerrfree(err); SSLerrfree(err);
...@@ -1087,7 +1087,7 @@ initialize_SSL(PGconn *conn) ...@@ -1087,7 +1087,7 @@ initialize_SSL(PGconn *conn)
if (engine_str == NULL) if (engine_str == NULL)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("out of memory\n")); libpq_gettext("out of memory\n"));
return -1; return -1;
} }
...@@ -1103,7 +1103,7 @@ initialize_SSL(PGconn *conn) ...@@ -1103,7 +1103,7 @@ initialize_SSL(PGconn *conn)
{ {
char *err = SSLerrmessage(ERR_get_error()); char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not load SSL engine \"%s\": %s\n"), libpq_gettext("could not load SSL engine \"%s\": %s\n"),
engine_str, err); engine_str, err);
SSLerrfree(err); SSLerrfree(err);
...@@ -1115,7 +1115,7 @@ initialize_SSL(PGconn *conn) ...@@ -1115,7 +1115,7 @@ initialize_SSL(PGconn *conn)
{ {
char *err = SSLerrmessage(ERR_get_error()); char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not initialize SSL engine \"%s\": %s\n"), libpq_gettext("could not initialize SSL engine \"%s\": %s\n"),
engine_str, err); engine_str, err);
SSLerrfree(err); SSLerrfree(err);
...@@ -1131,7 +1131,7 @@ initialize_SSL(PGconn *conn) ...@@ -1131,7 +1131,7 @@ initialize_SSL(PGconn *conn)
{ {
char *err = SSLerrmessage(ERR_get_error()); char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not read private SSL key \"%s\" from engine \"%s\": %s\n"), libpq_gettext("could not read private SSL key \"%s\" from engine \"%s\": %s\n"),
engine_colon, engine_str, err); engine_colon, engine_str, err);
SSLerrfree(err); SSLerrfree(err);
...@@ -1145,7 +1145,7 @@ initialize_SSL(PGconn *conn) ...@@ -1145,7 +1145,7 @@ initialize_SSL(PGconn *conn)
{ {
char *err = SSLerrmessage(ERR_get_error()); char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not load private SSL key \"%s\" from engine \"%s\": %s\n"), libpq_gettext("could not load private SSL key \"%s\" from engine \"%s\": %s\n"),
engine_colon, engine_str, err); engine_colon, engine_str, err);
SSLerrfree(err); SSLerrfree(err);
...@@ -1182,7 +1182,7 @@ initialize_SSL(PGconn *conn) ...@@ -1182,7 +1182,7 @@ initialize_SSL(PGconn *conn)
if (stat(fnbuf, &buf) != 0) if (stat(fnbuf, &buf) != 0)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("certificate present, but not private key file \"%s\"\n"), libpq_gettext("certificate present, but not private key file \"%s\"\n"),
fnbuf); fnbuf);
return -1; return -1;
...@@ -1190,7 +1190,7 @@ initialize_SSL(PGconn *conn) ...@@ -1190,7 +1190,7 @@ initialize_SSL(PGconn *conn)
#ifndef WIN32 #ifndef WIN32
if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO)) if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO))
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("private key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"), libpq_gettext("private key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"),
fnbuf); fnbuf);
return -1; return -1;
...@@ -1215,7 +1215,7 @@ initialize_SSL(PGconn *conn) ...@@ -1215,7 +1215,7 @@ initialize_SSL(PGconn *conn)
*/ */
if (SSL_use_PrivateKey_file(conn->ssl, fnbuf, SSL_FILETYPE_ASN1) != 1) if (SSL_use_PrivateKey_file(conn->ssl, fnbuf, SSL_FILETYPE_ASN1) != 1)
{ {
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not load private key file \"%s\": %s\n"), libpq_gettext("could not load private key file \"%s\": %s\n"),
fnbuf, err); fnbuf, err);
SSLerrfree(err); SSLerrfree(err);
...@@ -1233,7 +1233,7 @@ initialize_SSL(PGconn *conn) ...@@ -1233,7 +1233,7 @@ initialize_SSL(PGconn *conn)
{ {
char *err = SSLerrmessage(ERR_get_error()); char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("certificate does not match private key file \"%s\": %s\n"), libpq_gettext("certificate does not match private key file \"%s\": %s\n"),
fnbuf, err); fnbuf, err);
SSLerrfree(err); SSLerrfree(err);
...@@ -1287,11 +1287,11 @@ open_client_SSL(PGconn *conn) ...@@ -1287,11 +1287,11 @@ open_client_SSL(PGconn *conn)
char sebuf[PG_STRERROR_R_BUFLEN]; char sebuf[PG_STRERROR_R_BUFLEN];
if (r == -1) if (r == -1)
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: %s\n"), libpq_gettext("SSL SYSCALL error: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
else else
printfPQExpBuffer(&conn->errorMessage, appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: EOF detected\n")); libpq_gettext("SSL SYSCALL error: EOF detected\n"));
pgtls_close(conn); pgtls_close(conn);
return PGRES_POLLING_FAILED; return PGRES_POLLING_FAILED;
...@@ -1300,7 +1300,7 @@ open_client_SSL(PGconn *conn) ...@@ -1300,7 +1300,7 @@ open_client_SSL(PGconn *conn)
{ {
char *err = SSLerrmessage(ecode); char *err = SSLerrmessage(ecode);
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL error: %s\n"), libpq_gettext("SSL error: %s\n"),
err); err);
SSLerrfree(err); SSLerrfree(err);
...@@ -1350,7 +1350,7 @@ open_client_SSL(PGconn *conn) ...@@ -1350,7 +1350,7 @@ open_client_SSL(PGconn *conn)
} }
default: default:
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("unrecognized SSL error code: %d\n"), libpq_gettext("unrecognized SSL error code: %d\n"),
err); err);
pgtls_close(conn); pgtls_close(conn);
...@@ -1369,7 +1369,7 @@ open_client_SSL(PGconn *conn) ...@@ -1369,7 +1369,7 @@ open_client_SSL(PGconn *conn)
{ {
char *err = SSLerrmessage(ERR_get_error()); char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("certificate could not be obtained: %s\n"), libpq_gettext("certificate could not be obtained: %s\n"),
err); err);
SSLerrfree(err); SSLerrfree(err);
......
...@@ -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