diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/interfaces/libpq/fe-auth-scram.c | 124 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-auth.c | 169 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-connect.c | 317 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-exec.c | 281 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-gssapi-common.c | 9 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-lobj.c | 210 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-misc.c | 54 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-protocol2.c | 36 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-protocol3.c | 51 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-secure-common.c | 24 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-secure-gssapi.c | 28 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-secure-openssl.c | 124 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-secure.c | 28 | ||||
-rw-r--r-- | src/interfaces/libpq/libpq-int.h | 18 |
14 files changed, 699 insertions, 774 deletions
diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c index b76f0befd0b..002469540a9 100644 --- a/src/interfaces/libpq/fe-auth-scram.c +++ b/src/interfaces/libpq/fe-auth-scram.c @@ -208,14 +208,14 @@ pg_fe_scram_exchange(void *opaq, char *input, int inputlen, { if (inputlen == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("malformed SCRAM message (empty message)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("malformed SCRAM message (empty message)\n")); goto error; } if (inputlen != strlen(input)) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("malformed SCRAM message (length mismatch)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("malformed SCRAM message (length mismatch)\n")); goto error; } } @@ -258,15 +258,15 @@ pg_fe_scram_exchange(void *opaq, char *input, int inputlen, */ if (!verify_server_signature(state, success)) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not verify server signature\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not verify server signature\n")); goto error; } if (!*success) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("incorrect server signature\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("incorrect server signature\n")); } *done = true; state->state = FE_SCRAM_FINISHED; @@ -274,8 +274,8 @@ pg_fe_scram_exchange(void *opaq, char *input, int inputlen, default: /* shouldn't happen */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid SCRAM exchange state\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("invalid SCRAM exchange state\n")); goto error; } return; @@ -287,6 +287,11 @@ error: /* * 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 * 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) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("malformed SCRAM message (attribute \"%c\" expected)\n"), attr); return NULL; @@ -305,7 +310,7 @@ read_attr_value(char **input, char attr, PQExpBuffer errorMessage) if (*begin != '=') { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("malformed SCRAM message (expected character \"=\" for attribute \"%c\")\n"), attr); return NULL; @@ -346,8 +351,8 @@ build_client_first_message(fe_scram_state *state) */ if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN)) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not generate nonce\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not generate nonce\n")); return NULL; } @@ -356,16 +361,16 @@ build_client_first_message(fe_scram_state *state) state->client_nonce = malloc(encoded_len + 1); if (state->client_nonce == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return NULL; } encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN, state->client_nonce, encoded_len); if (encoded_len < 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not encode nonce\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not encode nonce\n")); return NULL; } state->client_nonce[encoded_len] = '\0'; @@ -431,8 +436,8 @@ build_client_first_message(fe_scram_state *state) oom_error: termPQExpBuffer(&buf); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return NULL; } @@ -508,8 +513,8 @@ build_client_final_message(fe_scram_state *state) free(cbind_data); free(cbind_input); termPQExpBuffer(&buf); - printfPQExpBuffer(&conn->errorMessage, - "could not encode cbind data for channel binding\n"); + appendPQExpBufferStr(&conn->errorMessage, + "could not encode cbind data for channel binding\n"); return NULL; } buf.len += encoded_cbind_len; @@ -523,8 +528,8 @@ build_client_final_message(fe_scram_state *state) * Shouldn't happen. */ termPQExpBuffer(&buf); - printfPQExpBuffer(&conn->errorMessage, - "channel binding not supported by this build\n"); + appendPQExpBufferStr(&conn->errorMessage, + "channel binding not supported by this build\n"); return NULL; #endif /* HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH */ } @@ -553,8 +558,8 @@ build_client_final_message(fe_scram_state *state) client_proof)) { termPQExpBuffer(&buf); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not calculate client proof\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not calculate client proof\n")); return NULL; } @@ -569,8 +574,8 @@ build_client_final_message(fe_scram_state *state) if (encoded_len < 0) { termPQExpBuffer(&buf); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not encode client proof\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not encode client proof\n")); return NULL; } buf.len += encoded_len; @@ -585,8 +590,8 @@ build_client_final_message(fe_scram_state *state) oom_error: termPQExpBuffer(&buf); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return NULL; } @@ -606,8 +611,8 @@ read_server_first_message(fe_scram_state *state, char *input) state->server_first_message = strdup(input); if (state->server_first_message == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return false; } @@ -616,7 +621,7 @@ read_server_first_message(fe_scram_state *state, char *input) &conn->errorMessage); if (nonce == NULL) { - /* read_attr_value() has generated an error string */ + /* read_attr_value() has appended an error string */ return false; } @@ -624,31 +629,31 @@ read_server_first_message(fe_scram_state *state, char *input) if (strlen(nonce) < strlen(state->client_nonce) || memcmp(nonce, state->client_nonce, strlen(state->client_nonce)) != 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid SCRAM response (nonce mismatch)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("invalid SCRAM response (nonce mismatch)\n")); return false; } state->nonce = strdup(nonce); if (state->nonce == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return false; } encoded_salt = read_attr_value(&input, 's', &conn->errorMessage); if (encoded_salt == NULL) { - /* read_attr_value() has generated an error string */ + /* read_attr_value() has appended an error string */ return false; } decoded_salt_len = pg_b64_dec_len(strlen(encoded_salt)); state->salt = malloc(decoded_salt_len); if (state->salt == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return false; } state->saltlen = pg_b64_decode(encoded_salt, @@ -657,28 +662,28 @@ read_server_first_message(fe_scram_state *state, char *input) decoded_salt_len); if (state->saltlen < 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("malformed SCRAM message (invalid salt)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("malformed SCRAM message (invalid salt)\n")); return false; } iterations_str = read_attr_value(&input, 'i', &conn->errorMessage); if (iterations_str == NULL) { - /* read_attr_value() has generated an error string */ + /* read_attr_value() has appended an error string */ return false; } state->iterations = strtol(iterations_str, &endptr, 10); if (*endptr != '\0' || state->iterations < 1) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("malformed SCRAM message (invalid iteration count)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("malformed SCRAM message (invalid iteration count)\n")); return false; } if (*input != '\0') - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("malformed SCRAM message (garbage at end of server-first-message)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("malformed SCRAM message (garbage at end of server-first-message)\n")); return true; } @@ -697,8 +702,8 @@ read_server_final_message(fe_scram_state *state, char *input) state->server_final_message = strdup(input); if (!state->server_final_message) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return false; } @@ -708,7 +713,12 @@ read_server_final_message(fe_scram_state *state, char *input) char *errmsg = read_attr_value(&input, 'e', &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"), errmsg); return false; @@ -719,20 +729,20 @@ read_server_final_message(fe_scram_state *state, char *input) &conn->errorMessage); if (encoded_server_signature == NULL) { - /* read_attr_value() has generated an error message */ + /* read_attr_value() has appended an error message */ return false; } if (*input != '\0') - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("malformed SCRAM message (garbage at end of server-final-message)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("malformed SCRAM message (garbage at end of server-final-message)\n")); server_signature_len = pg_b64_dec_len(strlen(encoded_server_signature)); decoded_server_signature = malloc(server_signature_len); if (!decoded_server_signature) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return false; } @@ -743,8 +753,8 @@ read_server_final_message(fe_scram_state *state, char *input) if (server_signature_len != SCRAM_KEY_LEN) { free(decoded_server_signature); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("malformed SCRAM message (invalid server signature)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("malformed SCRAM message (invalid server signature)\n")); return false; } memcpy(state->ServerSignature, decoded_server_signature, SCRAM_KEY_LEN); diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index a25fe4dd17a..168b3df52bf 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -72,7 +72,7 @@ pg_GSS_continue(PGconn *conn, int payloadlen) ginbuf.value = malloc(payloadlen); if (!ginbuf.value) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory allocating GSSAPI buffer (%d)\n"), payloadlen); return STATUS_ERROR; @@ -154,15 +154,15 @@ pg_GSS_startup(PGconn *conn, int payloadlen) if (!(host && host[0] != '\0')) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("host name must be specified\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("host name must be specified\n")); return STATUS_ERROR; } if (conn->gctx) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("duplicate GSS authentication request\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("duplicate GSS authentication request\n")); return STATUS_ERROR; } @@ -195,10 +195,10 @@ pg_SSPI_error(PGconn *conn, const char *mprefix, SECURITY_STATUS r) FORMAT_MESSAGE_FROM_SYSTEM, NULL, r, 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); else - printfPQExpBuffer(&conn->errorMessage, "%s: %s (%x)\n", + appendPQExpBuffer(&conn->errorMessage, "%s: %s (%x)\n", mprefix, sysmsg, (unsigned int) r); } @@ -226,7 +226,7 @@ pg_SSPI_continue(PGconn *conn, int payloadlen) inputbuf = malloc(payloadlen); if (!inputbuf) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory allocating SSPI buffer (%d)\n"), payloadlen); return STATUS_ERROR; @@ -286,7 +286,8 @@ pg_SSPI_continue(PGconn *conn, int payloadlen) conn->sspictx = malloc(sizeof(CtxtHandle)); 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; } memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle)); @@ -305,7 +306,8 @@ pg_SSPI_continue(PGconn *conn, int payloadlen) * authentication. Keep check in case it shows up with other * 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; } @@ -345,8 +347,8 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen) if (conn->sspictx) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("duplicate SSPI authentication request\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("duplicate SSPI authentication request\n")); return STATUS_ERROR; } @@ -356,7 +358,8 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen) conn->sspicred = malloc(sizeof(CredHandle)); 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; } @@ -384,14 +387,15 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen) */ if (!(host && host[0] != '\0')) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("host name must be specified\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("host name must be specified\n")); return STATUS_ERROR; } conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(host) + 2); if (!conn->sspitarget) { - printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return STATUS_ERROR; } sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, host); @@ -425,15 +429,15 @@ pg_SASL_init(PGconn *conn, int payloadlen) if (conn->channel_binding[0] == 'r' && /* require */ !conn->ssl_in_use) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("channel binding required, but SSL not in use\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("channel binding required, but SSL not in use\n")); goto error; } if (conn->sasl_state) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("duplicate SASL authentication request\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("duplicate SASL authentication request\n")); goto error; } @@ -448,8 +452,8 @@ pg_SASL_init(PGconn *conn, int payloadlen) { if (pqGets(&mechanism_buf, conn)) { - printfPQExpBuffer(&conn->errorMessage, - "fe_sendauth: invalid authentication request from server: invalid list of authentication mechanisms\n"); + appendPQExpBufferStr(&conn->errorMessage, + "fe_sendauth: invalid authentication request from server: invalid list of authentication mechanisms\n"); goto error; } if (PQExpBufferDataBroken(mechanism_buf)) @@ -488,8 +492,8 @@ pg_SASL_init(PGconn *conn, int payloadlen) */ if (conn->channel_binding[0] == 'r') /* require */ { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("channel binding is required, but client does not support it\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("channel binding is required, but client does not support it\n")); goto error; } #endif @@ -505,8 +509,8 @@ pg_SASL_init(PGconn *conn, int payloadlen) * the client and server supported it. The SCRAM exchange * checks for that, to prevent downgrade attacks. */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server offered SCRAM-SHA-256-PLUS authentication over a non-SSL connection\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server offered SCRAM-SHA-256-PLUS authentication over a non-SSL connection\n")); goto error; } } @@ -517,16 +521,16 @@ pg_SASL_init(PGconn *conn, int payloadlen) if (!selected_mechanism) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("none of the server's SASL authentication mechanisms are supported\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("none of the server's SASL authentication mechanisms are supported\n")); goto error; } if (conn->channel_binding[0] == 'r' && /* require */ strcmp(selected_mechanism, SCRAM_SHA_256_PLUS_NAME) != 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("channel binding is required, but server did not offer an authentication method that supports channel binding\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("channel binding is required, but server did not offer an authentication method that supports channel binding\n")); goto error; } @@ -546,8 +550,8 @@ pg_SASL_init(PGconn *conn, int payloadlen) password = conn->pgpass; if (password == NULL || password[0] == '\0') { - printfPQExpBuffer(&conn->errorMessage, - PQnoPasswordSupplied); + appendPQExpBufferStr(&conn->errorMessage, + PQnoPasswordSupplied); goto error; } @@ -607,8 +611,8 @@ oom_error: termPQExpBuffer(&mechanism_buf); if (initialresponse) free(initialresponse); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return STATUS_ERROR; } @@ -631,7 +635,7 @@ pg_SASL_continue(PGconn *conn, int payloadlen, bool final) challenge = malloc(payloadlen + 1); if (!challenge) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory allocating SASL buffer (%d)\n"), payloadlen); return STATUS_ERROR; @@ -656,8 +660,8 @@ pg_SASL_continue(PGconn *conn, int payloadlen, bool final) if (outputlen != 0) free(output); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("AuthenticationSASLFinal received from server, but SASL authentication was not completed\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("AuthenticationSASLFinal received from server, but SASL authentication was not completed\n")); return STATUS_ERROR; } if (outputlen != 0) @@ -726,15 +730,15 @@ pg_local_sendauth(PGconn *conn) { char sebuf[PG_STRERROR_R_BUFLEN]; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, "pg_local_sendauth: sendmsg: %s\n", strerror_r(errno, sebuf, sizeof(sebuf))); return STATUS_ERROR; } return STATUS_OK; #else - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SCM_CRED authentication method not supported\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SCM_CRED authentication method not supported\n")); return STATUS_ERROR; #endif } @@ -766,8 +770,8 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq) crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1)); if (!crypt_pwd) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return STATUS_ERROR; } @@ -832,14 +836,14 @@ check_expected_areq(AuthRequest areq, PGconn *conn) case AUTH_REQ_OK: if (!pg_fe_scram_channel_bound(conn->sasl_state)) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("channel binding required, but server authenticated client without channel binding\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("channel binding required, but server authenticated client without channel binding\n")); result = false; } break; default: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("channel binding required but not supported by server's authentication request\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("channel binding required but not supported by server's authentication request\n")); result = false; break; } @@ -862,6 +866,8 @@ check_expected_areq(AuthRequest areq, PGconn *conn) int pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) { + int oldmsglen; + if (!check_expected_areq(areq, conn)) return STATUS_ERROR; @@ -871,13 +877,13 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) break; case AUTH_REQ_KRB4: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("Kerberos 4 authentication not supported\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("Kerberos 4 authentication not supported\n")); return STATUS_ERROR; case AUTH_REQ_KRB5: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("Kerberos 5 authentication not supported\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("Kerberos 5 authentication not supported\n")); return STATUS_ERROR; #if defined(ENABLE_GSS) || defined(ENABLE_SSPI) @@ -947,8 +953,8 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) /* No GSSAPI *or* SSPI support */ case AUTH_REQ_GSS: case AUTH_REQ_GSS_CONT: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("GSSAPI authentication not supported\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("GSSAPI authentication not supported\n")); return STATUS_ERROR; #endif /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */ @@ -979,16 +985,16 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) */ #if !defined(ENABLE_GSS) case AUTH_REQ_SSPI: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSPI authentication not supported\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSPI authentication not supported\n")); return STATUS_ERROR; #endif /* !define(ENABLE_GSS) */ #endif /* ENABLE_SSPI */ case AUTH_REQ_CRYPT: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("Crypt authentication not supported\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("Crypt authentication not supported\n")); return STATUS_ERROR; case AUTH_REQ_MD5: @@ -1002,14 +1008,14 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) password = conn->pgpass; if (password == NULL || password[0] == '\0') { - printfPQExpBuffer(&conn->errorMessage, - PQnoPasswordSupplied); + appendPQExpBufferStr(&conn->errorMessage, + PQnoPasswordSupplied); return STATUS_ERROR; } if (pg_password_sendauth(conn, password, areq) != STATUS_OK) { - printfPQExpBuffer(&conn->errorMessage, - "fe_sendauth: error sending password authentication\n"); + appendPQExpBufferStr(&conn->errorMessage, + "fe_sendauth: error sending password authentication\n"); return STATUS_ERROR; } break; @@ -1032,17 +1038,18 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) case AUTH_REQ_SASL_FIN: if (conn->sasl_state == NULL) { - printfPQExpBuffer(&conn->errorMessage, - "fe_sendauth: invalid authentication request from server: AUTH_REQ_SASL_CONT without AUTH_REQ_SASL\n"); + appendPQExpBufferStr(&conn->errorMessage, + "fe_sendauth: invalid authentication request from server: AUTH_REQ_SASL_CONT without AUTH_REQ_SASL\n"); return STATUS_ERROR; } + oldmsglen = conn->errorMessage.len; if (pg_SASL_continue(conn, payloadlen, (areq == AUTH_REQ_SASL_FIN)) != STATUS_OK) { - /* Use error message, if set already */ - if (conn->errorMessage.len == 0) - printfPQExpBuffer(&conn->errorMessage, - "fe_sendauth: error in SASL authentication\n"); + /* Use this message if pg_SASL_continue didn't supply one */ + if (conn->errorMessage.len == oldmsglen) + appendPQExpBufferStr(&conn->errorMessage, + "fe_sendauth: error in SASL authentication\n"); return STATUS_ERROR; } break; @@ -1053,7 +1060,7 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) break; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("authentication method %u not supported\n"), areq); return STATUS_ERROR; } @@ -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 * 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 * pg_fe_getauthname(PQExpBuffer errorMessage) @@ -1100,7 +1107,7 @@ pg_fe_getauthname(PQExpBuffer errorMessage) if (GetUserName(username, &namesize)) name = username; else if (errorMessage) - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("user name lookup failure: error code %lu\n"), GetLastError()); #else @@ -1110,12 +1117,12 @@ pg_fe_getauthname(PQExpBuffer errorMessage) else if (errorMessage) { if (pwerr != 0) - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("could not look up local user ID %d: %s\n"), (int) user_id, strerror_r(pwerr, pwdbuf, sizeof(pwdbuf))); else - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("local user with ID %d does not exist\n"), (int) user_id); } @@ -1125,8 +1132,8 @@ pg_fe_getauthname(PQExpBuffer errorMessage) { result = strdup(name); if (result == NULL && errorMessage) - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); } pgunlock_thread(); @@ -1196,6 +1203,8 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, if (!conn) return NULL; + resetPQExpBuffer(&conn->errorMessage); + /* If no algorithm was given, ask the server. */ if (algorithm == NULL) { @@ -1217,8 +1226,8 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, if (PQntuples(res) != 1 || PQnfields(res) != 1) { PQclear(res); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("unexpected shape of result set returned for SHOW\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("unexpected shape of result set returned for SHOW\n")); return NULL; } val = PQgetvalue(res, 0, 0); @@ -1226,8 +1235,8 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, if (strlen(val) > MAX_ALGORITHM_NAME_LEN) { PQclear(res); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("password_encryption value too long\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("password_encryption value too long\n")); return NULL; } strcpy(algobuf, val); @@ -1266,15 +1275,15 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, } else { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized password encryption algorithm \"%s\"\n"), algorithm); return NULL; } if (!crypt_pwd) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return crypt_pwd; } diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index a834ce8cf05..61a1fa6a14a 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -755,7 +755,9 @@ PQconnectStartParams(const char *const *keywords, 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(); if (conn == NULL) @@ -831,7 +833,9 @@ PQconnectStart(const char *conninfo) 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(); if (conn == NULL) @@ -889,8 +893,8 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions) *connmember = strdup(tmp); if (*connmember == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return false; } } @@ -1072,7 +1076,7 @@ connectOptions2(PGconn *conn) if (more || i != conn->nconnhost) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not match %d host names to %d hostaddr values\n"), count_comma_separated_elems(conn->pghost), conn->nconnhost); return false; @@ -1153,7 +1157,7 @@ connectOptions2(PGconn *conn) else if (more || i != conn->nconnhost) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not match %d port numbers to %d hosts\n"), count_comma_separated_elems(conn->pgport), conn->nconnhost); return false; @@ -1246,7 +1250,7 @@ connectOptions2(PGconn *conn) && strcmp(conn->channel_binding, "require") != 0) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid %s value: \"%s\"\n"), "channel_binding", conn->channel_binding); return false; @@ -1272,7 +1276,7 @@ connectOptions2(PGconn *conn) && strcmp(conn->sslmode, "verify-full") != 0) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid %s value: \"%s\"\n"), "sslmode", conn->sslmode); return false; @@ -1293,7 +1297,7 @@ connectOptions2(PGconn *conn) case 'r': /* "require" */ case 'v': /* "verify-ca" or "verify-full" */ conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("sslmode value \"%s\" invalid when SSL support is not compiled in\n"), conn->sslmode); return false; @@ -1314,7 +1318,7 @@ connectOptions2(PGconn *conn) if (!sslVerifyProtocolVersion(conn->ssl_min_protocol_version)) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid %s value: \"%s\"\n"), "ssl_min_protocol_version", conn->ssl_min_protocol_version); @@ -1323,7 +1327,7 @@ connectOptions2(PGconn *conn) if (!sslVerifyProtocolVersion(conn->ssl_max_protocol_version)) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid %s value: \"%s\"\n"), "ssl_max_protocol_version", conn->ssl_max_protocol_version); @@ -1341,8 +1345,8 @@ connectOptions2(PGconn *conn) conn->ssl_max_protocol_version)) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid SSL protocol version range\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("invalid SSL protocol version range\n")); return false; } @@ -1356,7 +1360,7 @@ connectOptions2(PGconn *conn) strcmp(conn->gssencmode, "require") != 0) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid %s value: \"%s\"\n"), "gssencmode", conn->gssencmode); @@ -1366,7 +1370,7 @@ connectOptions2(PGconn *conn) if (strcmp(conn->gssencmode, "require") == 0) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("gssencmode value \"%s\" invalid when GSSAPI support is not compiled in\n"), conn->gssencmode); return false; @@ -1401,7 +1405,7 @@ connectOptions2(PGconn *conn) && strcmp(conn->target_session_attrs, "read-write") != 0) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid %s value: \"%s\"\n"), "target_settion_attrs", conn->target_session_attrs); @@ -1420,8 +1424,8 @@ connectOptions2(PGconn *conn) oom_error: conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return false; } @@ -1487,7 +1491,9 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, 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(); if (conn == NULL) @@ -1596,8 +1602,8 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, oom_error: conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return conn; } @@ -2017,8 +2023,8 @@ connectDBStart(PGconn *conn) */ if (!pg_link_canary_is_frontend()) { - printfPQExpBuffer(&conn->errorMessage, - "libpq is incorrectly linked to backend functions\n"); + appendPQExpBufferStr(&conn->errorMessage, + "libpq is incorrectly linked to backend functions\n"); goto connect_errReturn; } @@ -2027,14 +2033,6 @@ connectDBStart(PGconn *conn) 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 * a bit of a cheat, but PQconnectPoll will advance it to 0 before * anything else looks at it.) @@ -2139,12 +2137,6 @@ connectDBComplete(PGconn *conn) switch (flag) { case PGRES_POLLING_OK: - - /* - * Reset stored error messages since we now have a working - * connection - */ - resetPQExpBuffer(&conn->errorMessage); return 1; /* success! */ case PGRES_POLLING_READING: @@ -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 * @@ -2264,7 +2216,6 @@ PQconnectPoll(PGconn *conn) PGresult *res; char sebuf[PG_STRERROR_R_BUFLEN]; int optval; - PQExpBufferData savedMessage; if (conn == NULL) return PGRES_POLLING_FAILED; @@ -2954,12 +2905,8 @@ keep_going: /* We will come back to here until there is EnvironmentOptions); if (!startpacket) { - /* - * will not appendbuffer here, since it's likely to also - * run out of memory - */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); goto error_return; } @@ -3448,7 +3395,6 @@ keep_going: /* We will come back to here until there is * avoid the Kerberos code doing a hostname look-up. */ res = pg_fe_sendauth(areq, msgLength, conn); - conn->errorMessage.len = strlen(conn->errorMessage.data); /* OK, we have processed the message; mark data consumed */ conn->inStart = conn->inCursor; @@ -3576,24 +3522,16 @@ keep_going: /* We will come back to here until there is strcmp(conn->target_session_attrs, "read-write") == 0) { /* - * Save existing error messages across the PQsendQuery - * attempt. This is necessary because PQsendQuery is - * going to reset conn->errorMessage, so we would lose - * error messages related to previous hosts we have tried - * and failed to connect to. + * We use PQsendQueryContinue so that conn->errorMessage + * does not get cleared. We need to preserve any error + * messages related to previous hosts we have tried and + * failed to connect to. */ - if (!saveErrorMessage(conn, &savedMessage)) - goto error_return; - conn->status = CONNECTION_OK; - if (!PQsendQuery(conn, - "SHOW transaction_read_only")) - { - restoreErrorMessage(conn, &savedMessage); + if (!PQsendQueryContinue(conn, + "SHOW transaction_read_only")) goto error_return; - } conn->status = CONNECTION_CHECK_WRITABLE; - restoreErrorMessage(conn, &savedMessage); return PGRES_POLLING_READING; } @@ -3673,20 +3611,13 @@ keep_going: /* We will come back to here until there is const char *displayed_host; const char *displayed_port; - if (!saveErrorMessage(conn, &savedMessage)) - goto error_return; - conn->status = CONNECTION_OK; if (!PQconsumeInput(conn)) - { - restoreErrorMessage(conn, &savedMessage); goto error_return; - } if (PQisBusy(conn)) { conn->status = CONNECTION_CHECK_WRITABLE; - restoreErrorMessage(conn, &savedMessage); return PGRES_POLLING_READING; } @@ -3701,7 +3632,6 @@ keep_going: /* We will come back to here until there is { /* Not writable; fail this connection. */ PQclear(res); - restoreErrorMessage(conn, &savedMessage); /* Append error report to conn->errorMessage. */ if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS) @@ -3732,7 +3662,6 @@ keep_going: /* We will come back to here until there is /* Session is read-write, so we're good. */ PQclear(res); - termPQExpBuffer(&savedMessage); /* * Finish reading any remaining messages before being @@ -3748,7 +3677,6 @@ keep_going: /* We will come back to here until there is */ if (res) PQclear(res); - restoreErrorMessage(conn, &savedMessage); /* Append error report to conn->errorMessage. */ if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS) @@ -4157,6 +4085,9 @@ closePGconn(PGconn *conn) /* * 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); conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just absent */ @@ -4212,7 +4143,7 @@ PQreset(PGconn *conn) conn->events[i].passThrough)) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("PGEventProc \"%s\" failed during PGEVT_CONNRESET event\n"), conn->events[i].name); break; @@ -4272,7 +4203,7 @@ PQresetPoll(PGconn *conn) conn->events[i].passThrough)) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("PGEventProc \"%s\" failed during PGEVT_CONNRESET event\n"), conn->events[i].name); return PGRES_POLLING_FAILED; @@ -4569,7 +4500,7 @@ pqPacketSend(PGconn *conn, char pack_type, * 2 if a connection could not be established, and * 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 ldapServiceLookup(const char *purl, PQconninfoOption *options, @@ -4607,7 +4538,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, if ((url = strdup(purl)) == NULL) { - printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, libpq_gettext("out of memory\n")); return 3; } @@ -4619,7 +4550,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, 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); free(url); return 3; @@ -4634,7 +4565,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, p = strchr(url + strlen(LDAP_URL), '/'); if (p == NULL || *(p + 1) == '\0' || *(p + 1) == '?') { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": missing distinguished name\n"), purl); free(url); @@ -4646,7 +4577,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, /* attribute */ 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"), purl); free(url); @@ -4658,7 +4589,9 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, /* scope */ 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); return 3; } @@ -4668,8 +4601,9 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, /* filter */ if ((p = strchr(scopestr, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') { - printfPQExpBuffer(errorMessage, - libpq_gettext("invalid LDAP URL \"%s\": no filter\n"), purl); + appendPQExpBuffer(errorMessage, + libpq_gettext("invalid LDAP URL \"%s\": no filter\n"), + purl); free(url); return 3; } @@ -4689,7 +4623,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, lport = strtol(portstr, &endptr, 10); if (*portstr == '\0' || *endptr != '\0' || errno || lport < 0 || lport > 65535) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": invalid port number\n"), purl); free(url); @@ -4701,7 +4635,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, /* Allow only one attribute */ if (strchr(attrs[0], ',') != NULL) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": must have exactly one attribute\n"), purl); free(url); @@ -4717,7 +4651,9 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, scope = LDAP_SCOPE_SUBTREE; 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); return 3; } @@ -4725,8 +4661,8 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, /* initialize LDAP structure */ if ((ld = ldap_init(hostname, port)) == NULL) { - printfPQExpBuffer(errorMessage, - libpq_gettext("could not create LDAP structure\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("could not create LDAP structure\n")); free(url); return 3; } @@ -4801,7 +4737,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, { if (res != NULL) ldap_msgfree(res); - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("lookup on LDAP server failed: %s\n"), ldap_err2string(rc)); ldap_unbind(ld); @@ -4812,9 +4748,9 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, /* complain if there was not exactly one result */ if ((rc = ldap_count_entries(ld, res)) != 1) { - printfPQExpBuffer(errorMessage, - rc ? libpq_gettext("more than one entry found on LDAP lookup\n") - : libpq_gettext("no entry found on LDAP lookup\n")); + appendPQExpBufferStr(errorMessage, + rc ? libpq_gettext("more than one entry found on LDAP lookup\n") + : libpq_gettext("no entry found on LDAP lookup\n")); ldap_msgfree(res); ldap_unbind(ld); free(url); @@ -4825,8 +4761,8 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, if ((entry = ldap_first_entry(ld, res)) == NULL) { /* should never happen */ - printfPQExpBuffer(errorMessage, - libpq_gettext("no entry found on LDAP lookup\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("no entry found on LDAP lookup\n")); ldap_msgfree(res); ldap_unbind(ld); free(url); @@ -4836,8 +4772,8 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, /* get values */ if ((values = ldap_get_values_len(ld, entry, attrs[0])) == NULL) { - printfPQExpBuffer(errorMessage, - libpq_gettext("attribute has no values on LDAP lookup\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("attribute has no values on LDAP lookup\n")); ldap_msgfree(res); ldap_unbind(ld); free(url); @@ -4849,8 +4785,8 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, if (values[0] == NULL) { - printfPQExpBuffer(errorMessage, - libpq_gettext("attribute has no values on LDAP lookup\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("attribute has no values on LDAP lookup\n")); ldap_value_free_len(values); ldap_unbind(ld); return 1; @@ -4862,8 +4798,8 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, size += values[i]->bv_len + 1; if ((result = malloc(size)) == NULL) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); ldap_value_free_len(values); ldap_unbind(ld); return 3; @@ -4901,7 +4837,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, } else if (ld_is_nl_cr(*p)) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"), optname); free(result); @@ -4920,7 +4856,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, } else if (!ld_is_sp_tab(*p)) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"), optname); free(result); @@ -4981,8 +4917,8 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, options[i].val = strdup(optval); if (!options[i].val) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); free(result); return 3; } @@ -4993,7 +4929,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, } if (!found_keyword) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid connection option \"%s\"\n"), optname); free(result); @@ -5009,8 +4945,8 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, if (state == 5 || state == 6) { - printfPQExpBuffer(errorMessage, - libpq_gettext("unterminated quoted string in connection info string\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("unterminated quoted string in connection info string\n")); return 3; } @@ -5090,7 +5026,7 @@ next_file: last_file: if (!group_found) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("definition of service \"%s\" not found\n"), service); return 3; } @@ -5117,7 +5053,7 @@ parseServiceFile(const char *serviceFile, f = fopen(serviceFile, "r"); if (f == NULL) { - printfPQExpBuffer(errorMessage, libpq_gettext("service file \"%s\" not found\n"), + appendPQExpBuffer(errorMessage, libpq_gettext("service file \"%s\" not found\n"), serviceFile); return 1; } @@ -5193,7 +5129,7 @@ parseServiceFile(const char *serviceFile, val = strchr(line, '='); if (val == NULL) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("syntax error in service file \"%s\", line %d\n"), serviceFile, linenr); @@ -5204,7 +5140,7 @@ parseServiceFile(const char *serviceFile, if (strcmp(key, "service") == 0) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("nested service specifications not supported in service file \"%s\", line %d\n"), serviceFile, linenr); @@ -5225,8 +5161,8 @@ parseServiceFile(const char *serviceFile, options[i].val = strdup(val); if (!options[i].val) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); result = 3; goto exit; } @@ -5237,7 +5173,7 @@ parseServiceFile(const char *serviceFile, if (!found_keyword) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("syntax error in service file \"%s\", line %d\n"), serviceFile, linenr); @@ -5307,8 +5243,8 @@ conninfo_init(PQExpBuffer errorMessage) options = (PQconninfoOption *) malloc(sizeof(PQconninfoOption) * sizeof(PQconninfoOptions) / sizeof(PQconninfoOptions[0])); if (options == NULL) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); return NULL; } opt_dest = options; @@ -5328,7 +5264,7 @@ conninfo_init(PQExpBuffer errorMessage) * Connection string parser * * 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, * environment variables, etc). @@ -5406,8 +5342,8 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, /* Need a modifiable copy of the input string */ if ((buf = strdup(conninfo)) == NULL) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); PQconninfoFree(options); return NULL; } @@ -5445,7 +5381,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, /* Check that there is a following '=' */ if (*cp != '=') { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"), pname); PQconninfoFree(options); @@ -5494,8 +5430,8 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, { if (*cp == '\0') { - printfPQExpBuffer(errorMessage, - libpq_gettext("unterminated quoted string in connection info string\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("unterminated quoted string in connection info string\n")); PQconninfoFree(options); free(buf); return NULL; @@ -5551,7 +5487,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, * * If successful, a malloc'd PQconninfoOption array is returned. * 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) * 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, /* Check for invalid connection option */ if (option->keyword == NULL) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid connection option \"%s\"\n"), pname); PQconninfoFree(options); @@ -5662,8 +5598,8 @@ conninfo_array_parse(const char *const *keywords, const char *const *values, options[k].val = strdup(str_option->val); if (!options[k].val) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); PQconninfoFree(options); PQconninfoFree(dbname_options); return NULL; @@ -5691,8 +5627,8 @@ conninfo_array_parse(const char *const *keywords, const char *const *values, option->val = strdup(pvalue); if (!option->val) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); PQconninfoFree(options); PQconninfoFree(dbname_options); return NULL; @@ -5763,8 +5699,8 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage) if (!option->val) { if (errorMessage) - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); return false; } continue; @@ -5787,8 +5723,8 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage) if (!option->val) { if (errorMessage) - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); return false; } continue; @@ -5805,8 +5741,8 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage) if (!option->val) { if (errorMessage) - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); return false; } continue; @@ -5906,8 +5842,8 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, initPQExpBuffer(&portbuf); if (PQExpBufferDataBroken(hostbuf) || PQExpBufferDataBroken(portbuf)) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); goto cleanup; } @@ -5915,8 +5851,8 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, buf = strdup(uri); if (buf == NULL) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); goto cleanup; } start = buf; @@ -5926,7 +5862,7 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, if (prefix_len == 0) { /* Should never happen */ - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid URI propagated to internal parser routine: \"%s\"\n"), uri); goto cleanup; @@ -6003,14 +5939,14 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, ++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"), uri); goto cleanup; } if (p == host) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("IPv6 host address may not be empty in URI: \"%s\"\n"), uri); goto cleanup; @@ -6025,7 +5961,7 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, */ if (*p && *p != ':' && *p != '/' && *p != '?' && *p != ',') { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("unexpected character \"%c\" at position %d in URI (expected \":\" or \"/\"): \"%s\"\n"), *p, (int) (p - buf + 1), uri); goto cleanup; @@ -6142,6 +6078,7 @@ conninfo_uri_parse_params(char *params, char *value = NULL; char *p = params; bool malloced = false; + int oldmsglen; /* * Scan the params string for '=' and '&', marking the end of keyword @@ -6154,7 +6091,7 @@ conninfo_uri_parse_params(char *params, /* Was there '=' already? */ if (value != NULL) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("extra key/value separator \"=\" in URI query parameter: \"%s\"\n"), keyword); return false; @@ -6174,7 +6111,7 @@ conninfo_uri_parse_params(char *params, /* Was there '=' at all? */ if (value == NULL) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("missing key/value separator \"=\" in URI query parameter: \"%s\"\n"), keyword); return false; @@ -6220,12 +6157,13 @@ conninfo_uri_parse_params(char *params, * otherwise. At this point both keyword and value are not * URI-encoded. */ + oldmsglen = errorMessage->len; if (!conninfo_storeval(connOptions, keyword, value, errorMessage, true, false)) { /* Insert generic message if conninfo_storeval didn't give one. */ - if (errorMessage->len == 0) - printfPQExpBuffer(errorMessage, + if (errorMessage->len == oldmsglen) + appendPQExpBuffer(errorMessage, libpq_gettext("invalid URI query parameter: \"%s\"\n"), keyword); /* And fail. */ @@ -6272,7 +6210,7 @@ conninfo_uri_decode(const char *str, PQExpBuffer errorMessage) buf = malloc(strlen(str) + 1); if (buf == NULL) { - printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, libpq_gettext("out of memory\n")); return NULL; } p = buf; @@ -6299,7 +6237,7 @@ conninfo_uri_decode(const char *str, PQExpBuffer errorMessage) */ if (!(get_hexdigit(*q++, &hi) && get_hexdigit(*q++, &lo))) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid percent-encoded token: \"%s\"\n"), str); free(buf); @@ -6309,7 +6247,7 @@ conninfo_uri_decode(const char *str, PQExpBuffer errorMessage) c = (hi << 4) | lo; if (c == 0) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("forbidden value %%00 in percent-encoded value: \"%s\"\n"), str); free(buf); @@ -6404,7 +6342,7 @@ conninfo_storeval(PQconninfoOption *connOptions, if (option == NULL) { if (!ignoreMissing) - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid connection option \"%s\"\n"), keyword); return NULL; @@ -6422,7 +6360,7 @@ conninfo_storeval(PQconninfoOption *connOptions, value_copy = strdup(value); if (value_copy == NULL) { - printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, libpq_gettext("out of memory\n")); return NULL; } } @@ -6469,7 +6407,10 @@ PQconninfo(PGconn *conn) if (conn == 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); if (PQExpBufferDataBroken(errorBuf)) return NULL; /* out of memory already :-( */ diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index d48f0fd587b..e7307533876 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -53,7 +53,8 @@ static bool static_std_strings = false; static PGEvent *dupEvents(PGEvent *events, int count, size_t *memSize); static bool pqAddTuple(PGresult *res, PGresAttValue *tup, 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, const char *command, const char *stmtName, @@ -668,25 +669,6 @@ pqSetResultError(PGresult *res, const char *msg) } /* - * 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 - * free's the memory associated with a PGresult */ @@ -759,68 +741,46 @@ pqClearAsyncResult(PGconn *conn) /* * This subroutine deletes any existing async result, sets conn->result * to a PGresult with status PGRES_FATAL_ERROR, and stores the current - * contents of conn->errorMessage into that result. It differs from a - * 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.) + * contents of conn->errorMessage into that result. */ void 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); - conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); - } - else - { - /* Else, concatenate error message to existing async result. */ - pqCatenateResultError(conn->result, conn->errorMessage.data); - } + pqClearAsyncResult(conn); + conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); } /* - * As above, and append conn->write_err_msg to whatever other error we have. - * This is used when we've detected a write failure and have exhausted our - * chances of reporting something else instead. + * As above, after appending conn->write_err_msg to whatever other error we + * have. This is used when we've detected a write failure and have exhausted + * our chances of reporting something else instead. */ static void pqSaveWriteError(PGconn *conn) { /* - * Ensure conn->result is an error result, and add anything in - * conn->errorMessage to it. + * If write_err_msg is null because of previous strdup failure, do what we + * 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') - pqCatenateResultError(conn->result, conn->write_err_msg); + if (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 - pqCatenateResultError(conn->result, - libpq_gettext("write to server failed\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("write to server failed\n")); + + pqSaveErrorResult(conn); } /* * 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 * using whatever is in conn->errorMessage. In any case, clear the async - * result storage and make sure PQerrorMessage will agree with the result's - * error string. + * result storage. */ PGresult * pqPrepareAsyncResult(PGconn *conn) @@ -835,16 +795,6 @@ pqPrepareAsyncResult(PGconn *conn) res = conn->result; if (!res) 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 @@ -1229,18 +1179,33 @@ fail: * * Returns: 1 if successfully submitted * 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 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; /* check the argument */ if (!query) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("command string is a null pointer\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("command string is a null pointer\n")); return 0; } @@ -1291,20 +1256,20 @@ PQsendQueryParams(PGconn *conn, const int *paramFormats, int resultFormat) { - if (!PQsendQueryStart(conn)) + if (!PQsendQueryStart(conn, true)) return 0; /* check the arguments */ if (!command) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("command string is a null pointer\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("command string is a null pointer\n")); return 0; } if (nParams < 0 || nParams > 65535) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("number of parameters must be between 0 and 65535\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("number of parameters must be between 0 and 65535\n")); return 0; } @@ -1331,34 +1296,34 @@ PQsendPrepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes) { - if (!PQsendQueryStart(conn)) + if (!PQsendQueryStart(conn, true)) return 0; /* check the arguments */ if (!stmtName) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("statement name is a null pointer\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("statement name is a null pointer\n")); return 0; } if (!query) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("command string is a null pointer\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("command string is a null pointer\n")); return 0; } if (nParams < 0 || nParams > 65535) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("number of parameters must be between 0 and 65535\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("number of parameters must be between 0 and 65535\n")); return 0; } /* This isn't gonna work on a 2.0 server */ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("function requires at least protocol version 3.0\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("function requires at least protocol version 3.0\n")); return 0; } @@ -1432,20 +1397,20 @@ PQsendQueryPrepared(PGconn *conn, const int *paramFormats, int resultFormat) { - if (!PQsendQueryStart(conn)) + if (!PQsendQueryStart(conn, true)) return 0; /* check the arguments */ if (!stmtName) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("statement name is a null pointer\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("statement name is a null pointer\n")); return 0; } if (nParams < 0 || nParams > 65535) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("number of parameters must be between 0 and 65535\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("number of parameters must be between 0 and 65535\n")); return 0; } @@ -1464,26 +1429,29 @@ PQsendQueryPrepared(PGconn *conn, * Common startup code for PQsendQuery and sibling routines */ static bool -PQsendQueryStart(PGconn *conn) +PQsendQueryStart(PGconn *conn, bool newQuery) { if (!conn) return false; - /* clear the error string */ - resetPQExpBuffer(&conn->errorMessage); + /* + * If this is the beginning of a query cycle, reset the error buffer. + */ + if (newQuery) + resetPQExpBuffer(&conn->errorMessage); /* Don't try to send if we know there's no live connection. */ if (conn->status != CONNECTION_OK) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no connection to the server\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("no connection to the server\n")); return false; } /* Can't send while already busy, either. */ if (conn->asyncStatus != PGASYNC_IDLE) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("another command is already in progress\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("another command is already in progress\n")); return false; } @@ -1520,8 +1488,8 @@ PQsendQueryGuts(PGconn *conn, /* This isn't gonna work on a 2.0 server */ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("function requires at least protocol version 3.0\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("function requires at least protocol version 3.0\n")); return 0; } @@ -1596,8 +1564,8 @@ PQsendQueryGuts(PGconn *conn, nbytes = paramLengths[i]; else { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("length must be given for binary parameter\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("length must be given for binary parameter\n")); goto sendFailed; } } @@ -1859,7 +1827,7 @@ PQgetResult(PGconn *conn) res = getCopyResult(conn, PGRES_COPY_BOTH); break; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unexpected asyncStatus: %d\n"), (int) conn->asyncStatus); res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); @@ -1879,7 +1847,7 @@ PQgetResult(PGconn *conn) if (!res->events[i].proc(PGEVT_RESULTCREATE, &evt, res->events[i].passThrough)) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("PGEventProc \"%s\" failed during PGEVT_RESULTCREATE event\n"), res->events[i].name); pqSetResultError(res, conn->errorMessage.data); @@ -2026,6 +1994,11 @@ PQexecStart(PGconn *conn) 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. * This is probably poor design, but it's here for backward compatibility. */ @@ -2047,8 +2020,8 @@ PQexecStart(PGconn *conn) else { /* In older protocols we have to punt */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("COPY IN state must be terminated first\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("COPY IN state must be terminated first\n")); return false; } } @@ -2067,16 +2040,16 @@ PQexecStart(PGconn *conn) else { /* In older protocols we have to punt */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("COPY OUT state must be terminated first\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("COPY OUT state must be terminated first\n")); return false; } } else if (resultStatus == PGRES_COPY_BOTH) { /* We don't allow PQexec during COPY BOTH */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("PQexec not allowed during COPY BOTH\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("PQexec not allowed during COPY BOTH\n")); return false; } /* check for loss of connection, too */ @@ -2099,8 +2072,9 @@ PQexecFinish(PGconn *conn) /* * For backwards compatibility, return the last result if there are more - * than one --- but merge error messages if we get more than one error - * result. + * than one. (We used to have logic here to concatenate successive error + * 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 * parsing after application performs the data transfer. @@ -2111,23 +2085,7 @@ PQexecFinish(PGconn *conn) while ((result = PQgetResult(conn)) != NULL) { 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; if (result->resultStatus == PGRES_COPY_IN || result->resultStatus == PGRES_COPY_OUT || @@ -2223,14 +2181,14 @@ PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target) if (!desc_target) desc_target = ""; - if (!PQsendQueryStart(conn)) + if (!PQsendQueryStart(conn, true)) return 0; /* This isn't gonna work on a 2.0 server */ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("function requires at least protocol version 3.0\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("function requires at least protocol version 3.0\n")); return 0; } @@ -2321,8 +2279,8 @@ PQputCopyData(PGconn *conn, const char *buffer, int nbytes) if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_BOTH) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("no COPY in progress\n")); return -1; } @@ -2388,8 +2346,8 @@ PQputCopyEnd(PGconn *conn, const char *errormsg) if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_BOTH) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("no COPY in progress\n")); return -1; } @@ -2431,8 +2389,8 @@ PQputCopyEnd(PGconn *conn, const char *errormsg) if (errormsg) { /* Oops, no way to do this in 2.0 */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("function requires at least protocol version 3.0\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("function requires at least protocol version 3.0\n")); return -1; } else @@ -2450,7 +2408,6 @@ PQputCopyEnd(PGconn *conn, const char *errormsg) conn->asyncStatus = PGASYNC_COPY_OUT; else conn->asyncStatus = PGASYNC_BUSY; - resetPQExpBuffer(&conn->errorMessage); /* Try to flush data */ if (pqFlush(conn) < 0) @@ -2478,8 +2435,8 @@ PQgetCopyData(PGconn *conn, char **buffer, int async) if (conn->asyncStatus != PGASYNC_COPY_OUT && conn->asyncStatus != PGASYNC_COPY_BOTH) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("no COPY in progress\n")); return -2; } if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) @@ -2662,14 +2619,16 @@ PQfn(PGconn *conn, if (!conn) return NULL; - /* clear the error string */ + /* + * Since this is the beginning of a query cycle, reset the error buffer. + */ resetPQExpBuffer(&conn->errorMessage); if (conn->sock == PGINVALID_SOCKET || conn->asyncStatus != PGASYNC_IDLE || conn->result != NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("connection in wrong state\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("connection in wrong state\n")); return NULL; } @@ -3246,7 +3205,11 @@ PQsetnonblocking(PGconn *conn, int arg) * 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_ * 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 (pqFlush(conn)) return -1; @@ -3388,8 +3351,8 @@ PQescapeStringInternal(PGconn *conn, if (error) *error = 1; if (conn) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("incomplete multibyte character\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("incomplete multibyte character\n")); for (; i < len; i++) { if (((size_t) (target - to)) / 2 >= length) @@ -3419,6 +3382,9 @@ PQescapeStringConn(PGconn *conn, *error = 1; return 0; } + + resetPQExpBuffer(&conn->errorMessage); + return PQescapeStringInternal(conn, to, from, length, error, conn->client_encoding, conn->std_strings); @@ -3455,6 +3421,8 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident) if (!conn) return NULL; + resetPQExpBuffer(&conn->errorMessage); + /* Scan the string for characters that must be escaped. */ for (s = str; (s - str) < len && *s != '\0'; ++s) { @@ -3472,8 +3440,8 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident) /* Multibyte character overruns allowable length. */ if ((s - str) + charlen > len || memchr(s, 0, charlen) != NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("incomplete multibyte character\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("incomplete multibyte character\n")); return NULL; } @@ -3490,8 +3458,8 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident) result = rp = (char *) malloc(result_size); if (rp == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return NULL; } @@ -3655,8 +3623,8 @@ PQescapeByteaInternal(PGconn *conn, if (rp == NULL) { if (conn) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return NULL; } @@ -3717,6 +3685,9 @@ PQescapeByteaConn(PGconn *conn, { if (!conn) return NULL; + + resetPQExpBuffer(&conn->errorMessage); + return PQescapeByteaInternal(conn, from, from_length, to_length, conn->std_strings, (conn->sversion >= 90000)); diff --git a/src/interfaces/libpq/fe-gssapi-common.c b/src/interfaces/libpq/fe-gssapi-common.c index c2e79bb55c5..b26fbf8a9f9 100644 --- a/src/interfaces/libpq/fe-gssapi-common.c +++ b/src/interfaces/libpq/fe-gssapi-common.c @@ -46,7 +46,6 @@ void pg_GSS_error(const char *mprefix, PGconn *conn, OM_uint32 maj_stat, OM_uint32 min_stat) { - resetPQExpBuffer(&conn->errorMessage); appendPQExpBuffer(&conn->errorMessage, "%s:", mprefix); pg_GSS_error_int(&conn->errorMessage, maj_stat, GSS_C_GSS_CODE); appendPQExpBufferChar(&conn->errorMessage, ':'); @@ -94,8 +93,8 @@ pg_GSS_load_servicename(PGconn *conn) host = PQhost(conn); if (!(host && host[0] != '\0')) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("host name must be specified\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("host name must be specified\n")); return STATUS_ERROR; } @@ -107,8 +106,8 @@ pg_GSS_load_servicename(PGconn *conn) temp_gbuf.value = (char *) malloc(maxlen); if (!temp_gbuf.value) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return STATUS_ERROR; } snprintf(temp_gbuf.value, maxlen, "%s@%s", diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c index 432935061f0..b9c52eb50c2 100644 --- a/src/interfaces/libpq/fe-lobj.c +++ b/src/interfaces/libpq/fe-lobj.c @@ -61,11 +61,8 @@ lo_open(PGconn *conn, Oid lobjId, int mode) PQArgBlock argv[2]; PGresult *res; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; argv[0].isint = 1; argv[0].len = 4; @@ -103,11 +100,8 @@ lo_close(PGconn *conn, int fd) int retval; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; argv[0].isint = 1; argv[0].len = 4; @@ -141,17 +135,15 @@ lo_truncate(PGconn *conn, int fd, size_t len) int retval; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; /* Must check this on-the-fly because it's not there pre-8.3 */ if (conn->lobjfuncs->fn_lo_truncate == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_truncate\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_truncate"); return -1; } @@ -166,8 +158,8 @@ lo_truncate(PGconn *conn, int fd, size_t len) */ if (len > (size_t) INT_MAX) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("argument of lo_truncate exceeds integer range\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("argument of lo_truncate exceeds integer range\n")); return -1; } @@ -209,16 +201,14 @@ lo_truncate64(PGconn *conn, int fd, pg_int64 len) int retval; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; if (conn->lobjfuncs->fn_lo_truncate64 == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_truncate64\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_truncate64"); return -1; } @@ -261,11 +251,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len) PGresult *res; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; /* * Long ago, somebody thought it'd be a good idea to declare this function @@ -275,8 +262,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len) */ if (len > (size_t) INT_MAX) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("argument of lo_read exceeds integer range\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("argument of lo_read exceeds integer range\n")); return -1; } @@ -316,11 +303,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len) int result_len; int retval; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; /* * Long ago, somebody thought it'd be a good idea to declare this function @@ -330,8 +314,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len) */ if (len > (size_t) INT_MAX) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("argument of lo_write exceeds integer range\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("argument of lo_write exceeds integer range\n")); return -1; } @@ -369,11 +353,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence) int retval; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; argv[0].isint = 1; argv[0].len = 4; @@ -413,16 +394,14 @@ lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence) pg_int64 retval; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; if (conn->lobjfuncs->fn_lo_lseek64 == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_lseek64\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_lseek64"); return -1; } @@ -469,11 +448,8 @@ lo_creat(PGconn *conn, int mode) int retval; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return InvalidOid; - } + if (lo_initialize(conn) < 0) + return InvalidOid; argv[0].isint = 1; argv[0].len = 4; @@ -508,17 +484,15 @@ lo_create(PGconn *conn, Oid lobjId) int retval; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return InvalidOid; - } + if (lo_initialize(conn) < 0) + return InvalidOid; /* Must check this on-the-fly because it's not there pre-8.1 */ if (conn->lobjfuncs->fn_lo_create == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_create\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_create"); return InvalidOid; } @@ -552,11 +526,8 @@ lo_tell(PGconn *conn, int fd) PGresult *res; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; argv[0].isint = 1; argv[0].len = 4; @@ -588,16 +559,14 @@ lo_tell64(PGconn *conn, int fd) PGresult *res; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; if (conn->lobjfuncs->fn_lo_tell64 == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_tell64\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_tell64"); return -1; } @@ -632,11 +601,8 @@ lo_unlink(PGconn *conn, Oid lobjId) int result_len; int retval; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; argv[0].isint = 1; argv[0].len = 4; @@ -696,13 +662,19 @@ lo_import_internal(PGconn *conn, const char *filename, Oid oid) int lobj; 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 */ fd = open(filename, O_RDONLY | PG_BINARY, 0666); if (fd < 0) { /* error */ - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open file \"%s\": %s\n"), filename, strerror_r(errno, sebuf, sizeof(sebuf))); return InvalidOid; @@ -757,6 +729,7 @@ lo_import_internal(PGconn *conn, const char *filename, Oid oid) (void) lo_close(conn, lobj); (void) close(fd); + /* deliberately overwrite any error from lo_close */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read from file \"%s\": %s\n"), filename, @@ -811,6 +784,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename) int save_errno = errno; (void) lo_close(conn, lobj); + /* deliberately overwrite any error from lo_close */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open file \"%s\": %s\n"), filename, @@ -831,6 +805,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename) (void) lo_close(conn, lobj); (void) close(fd); + /* deliberately overwrite any error from lo_close */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not write to file \"%s\": %s\n"), 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 (close(fd) != 0 && result >= 0) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not write to file \"%s\": %s\n"), filename, strerror_r(errno, sebuf, sizeof(sebuf))); result = -1; @@ -868,9 +843,11 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename) /* * lo_initialize * - * Initialize the large object interface for an existing connection. - * We ask the backend about the functions OID's in pg_proc for all - * functions that are required for large object operations. + * Initialize for a new large-object operation on an existing connection. + * Return 0 if OK, -1 on failure. + * + * 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 lo_initialize(PGconn *conn) @@ -882,17 +859,26 @@ lo_initialize(PGconn *conn) const char *fname; Oid foid; - if (!conn) + /* Nothing we can do with no connection */ + if (conn == NULL) 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)); if (lobjfuncs == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return -1; } MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs)); @@ -942,8 +928,8 @@ lo_initialize(PGconn *conn) { free(lobjfuncs); PQclear(res); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("query to initialize large object functions did not return data\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("query to initialize large object functions did not return data\n")); return -1; } @@ -991,57 +977,65 @@ lo_initialize(PGconn *conn) */ if (lobjfuncs->fn_lo_open == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_open\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_open"); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_close == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_close\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_close"); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_creat == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_creat\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_creat"); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_unlink == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_unlink\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_unlink"); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_lseek == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_lseek\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_lseek"); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_tell == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_tell\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_tell"); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_read == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function loread\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "loread"); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_write == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lowrite\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lowrite"); free(lobjfuncs); return -1; } diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index 6094f048f30..2bfb6acd895 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -379,8 +379,8 @@ pqCheckOutBufferSpace(size_t bytes_needed, PGconn *conn) } /* realloc failed. Probably out of memory */ - printfPQExpBuffer(&conn->errorMessage, - "cannot allocate memory for output buffer\n"); + appendPQExpBufferStr(&conn->errorMessage, + "cannot allocate memory for output buffer\n"); return EOF; } @@ -473,8 +473,8 @@ pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn) } /* realloc failed. Probably out of memory */ - printfPQExpBuffer(&conn->errorMessage, - "cannot allocate memory for input buffer\n"); + appendPQExpBufferStr(&conn->errorMessage, + "cannot allocate memory for input buffer\n"); return EOF; } @@ -619,8 +619,8 @@ pqReadData(PGconn *conn) if (conn->sock == PGINVALID_SOCKET) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("connection not open\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("connection not open\n")); return -1; } @@ -798,10 +798,10 @@ retry4: * means the connection has been closed. Cope. */ definitelyEOF: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server closed the connection unexpectedly\n" - "\tThis probably means the server terminated abnormally\n" - "\tbefore or while processing the request.\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request.\n")); /* Come here if lower-level code already set a suitable errorMessage */ definitelyFailed: @@ -836,6 +836,7 @@ pqSendSome(PGconn *conn, int len) { char *ptr = conn->outBuffer; int remaining = conn->outCount; + int oldmsglen = conn->errorMessage.len; int result = 0; /* @@ -862,13 +863,10 @@ pqSendSome(PGconn *conn, int len) if (conn->sock == PGINVALID_SOCKET) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("connection not open\n")); 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) */ - conn->write_err_msg = strdup(conn->errorMessage.data); - resetPQExpBuffer(&conn->errorMessage); + conn->write_err_msg = strdup(libpq_gettext("connection not open\n")); /* Discard queued data; no chance it'll ever be sent */ conn->outCount = 0; return 0; @@ -915,14 +913,16 @@ pqSendSome(PGconn *conn, int len) * Transfer error message to conn->write_err_msg, if * possible (strdup failure is OK, we'll cope later). * - * Note: this assumes that pqsecure_write and its children - * will overwrite not append to conn->errorMessage. If - * 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. + * We only want to transfer whatever has been appended to + * conn->errorMessage since we entered this routine. */ - conn->write_err_msg = strdup(conn->errorMessage.data); - resetPQExpBuffer(&conn->errorMessage); + if (!PQExpBufferBroken(&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 */ conn->outCount = 0; @@ -1056,8 +1056,8 @@ pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time) if (result == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("timeout expired\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("timeout expired\n")); return 1; } @@ -1101,8 +1101,8 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time) return -1; if (conn->sock == PGINVALID_SOCKET) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid socket\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("invalid socket\n")); return -1; } @@ -1124,7 +1124,7 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time) { char sebuf[PG_STRERROR_R_BUFLEN]; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("select() failed: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); } diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c index ad6587f924e..6efa53d8b71 100644 --- a/src/interfaces/libpq/fe-protocol2.c +++ b/src/interfaces/libpq/fe-protocol2.c @@ -83,7 +83,7 @@ pqSetenvPoll(PGconn *conn) return PGRES_POLLING_OK; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid setenv state %c, probably indicative of memory corruption\n"), conn->setenv_state); goto error_return; @@ -380,7 +380,7 @@ pqSetenvPoll(PGconn *conn) } default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid state %c, " "probably indicative of memory corruption\n"), conn->setenv_state); @@ -493,8 +493,8 @@ pqParseInput2(PGconn *conn) PGRES_COMMAND_OK); if (!conn->result) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); pqSaveErrorResult(conn); } } @@ -528,8 +528,8 @@ pqParseInput2(PGconn *conn) PGRES_EMPTY_QUERY); if (!conn->result) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); pqSaveErrorResult(conn); } } @@ -622,7 +622,7 @@ pqParseInput2(PGconn *conn) * never arrives from the server during protocol 2.0. */ default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unexpected response from server; first received character was \"%c\"\n"), id); /* build an error result holding the error message */ @@ -754,7 +754,7 @@ advance_and_error: if (!errmsg) errmsg = libpq_gettext("out of memory for query result"); - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); + appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); /* * XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can @@ -929,7 +929,7 @@ set_error_result: if (!errmsg) errmsg = libpq_gettext("out of memory for query result"); - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); + appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); /* * XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can @@ -1042,12 +1042,11 @@ pqGetErrorNotice2(PGconn *conn, bool isError) { pqClearAsyncResult(conn); /* redundant, but be safe */ conn->result = res; - resetPQExpBuffer(&conn->errorMessage); if (res && !PQExpBufferDataBroken(workBuf) && res->errMsg) appendPQExpBufferStr(&conn->errorMessage, res->errMsg); else - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); if (conn->xactStatus == PQTRANS_INTRANS) conn->xactStatus = PQTRANS_INERROR; } @@ -1203,8 +1202,8 @@ pqGetCopyData2(PGconn *conn, char **buffer, int async) *buffer = (char *) malloc(msgLength + 1); if (*buffer == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return -2; } memcpy(*buffer, &conn->inBuffer[conn->inStart], msgLength); @@ -1349,8 +1348,8 @@ pqEndcopy2(PGconn *conn) if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_OUT) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("no COPY in progress\n")); return 1; } @@ -1367,7 +1366,6 @@ pqEndcopy2(PGconn *conn) /* Return to active duty */ conn->asyncStatus = PGASYNC_BUSY; - resetPQExpBuffer(&conn->errorMessage); /* Wait for the completion response */ result = PQgetResult(conn); @@ -1526,7 +1524,7 @@ pqFunctionCall2(PGconn *conn, Oid fnid, else { /* The backend violates the protocol. */ - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("protocol error: id=0x%x\n"), id); pqSaveErrorResult(conn); @@ -1558,7 +1556,7 @@ pqFunctionCall2(PGconn *conn, Oid fnid, return PQmakeEmptyPGresult(conn, status); default: /* The backend violates the protocol. */ - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("protocol error: id=0x%x\n"), id); pqSaveErrorResult(conn); diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index a4d6ee26749..e4ee9d69d25 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -202,8 +202,8 @@ pqParseInput3(PGconn *conn) PGRES_COMMAND_OK); if (!conn->result) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); pqSaveErrorResult(conn); } } @@ -229,8 +229,8 @@ pqParseInput3(PGconn *conn) PGRES_EMPTY_QUERY); if (!conn->result) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); pqSaveErrorResult(conn); } } @@ -246,8 +246,8 @@ pqParseInput3(PGconn *conn) PGRES_COMMAND_OK); if (!conn->result) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); pqSaveErrorResult(conn); } } @@ -326,8 +326,8 @@ pqParseInput3(PGconn *conn) PGRES_COMMAND_OK); if (!conn->result) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); pqSaveErrorResult(conn); } } @@ -361,8 +361,8 @@ pqParseInput3(PGconn *conn) else { /* Set up to report error at end of query */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)\n")); pqSaveErrorResult(conn); /* Discard the unexpected message */ conn->inCursor += msgLength; @@ -404,7 +404,7 @@ pqParseInput3(PGconn *conn) */ break; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unexpected response from server; first received character was \"%c\"\n"), id); /* build an error result holding the error message */ @@ -425,7 +425,7 @@ pqParseInput3(PGconn *conn) else { /* Trouble --- report it */ - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("message contents do not agree with length in message type \"%c\"\n"), id); /* build an error result holding the error message */ @@ -445,7 +445,7 @@ pqParseInput3(PGconn *conn) static void 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"), id, msgLength); /* build an error result holding the error message */ @@ -621,7 +621,7 @@ advance_and_error: if (!errmsg) errmsg = libpq_gettext("out of memory for query result"); - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); + appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); pqSaveErrorResult(conn); /* @@ -721,7 +721,7 @@ advance_and_error: */ if (!errmsg) errmsg = libpq_gettext("out of memory"); - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); + appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); pqSaveErrorResult(conn); /* @@ -848,7 +848,7 @@ set_error_result: if (!errmsg) errmsg = libpq_gettext("out of memory for query result"); - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); + appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); pqSaveErrorResult(conn); /* @@ -950,8 +950,8 @@ pqGetErrorNotice3(PGconn *conn, bool isError) pqClearAsyncResult(conn); /* redundant, but be safe */ conn->result = res; if (PQExpBufferDataBroken(workBuf)) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); else appendPQExpBufferStr(&conn->errorMessage, workBuf.data); } @@ -1695,8 +1695,8 @@ pqGetCopyData3(PGconn *conn, char **buffer, int async) *buffer = (char *) malloc(msgLength + 1); if (*buffer == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return -2; } memcpy(*buffer, &conn->inBuffer[conn->inCursor], msgLength); @@ -1728,8 +1728,8 @@ pqGetline3(PGconn *conn, char *s, int maxlen) conn->asyncStatus != PGASYNC_COPY_BOTH) || conn->copy_is_binary) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("PQgetline: not doing text COPY OUT\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("PQgetline: not doing text COPY OUT\n")); *s = '\0'; return EOF; } @@ -1834,8 +1834,8 @@ pqEndcopy3(PGconn *conn) conn->asyncStatus != PGASYNC_COPY_OUT && conn->asyncStatus != PGASYNC_COPY_BOTH) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("no COPY in progress\n")); return 1; } @@ -1868,7 +1868,6 @@ pqEndcopy3(PGconn *conn) /* Return to active duty */ conn->asyncStatus = PGASYNC_BUSY; - resetPQExpBuffer(&conn->errorMessage); /* * Non blocking connections may have to abort at this point. If everyone @@ -2091,7 +2090,7 @@ pqFunctionCall3(PGconn *conn, Oid fnid, break; default: /* The backend violates the protocol. */ - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("protocol error: id=0x%x\n"), id); pqSaveErrorResult(conn); diff --git a/src/interfaces/libpq/fe-secure-common.c b/src/interfaces/libpq/fe-secure-common.c index 45d36359a5d..afa5d133e15 100644 --- a/src/interfaces/libpq/fe-secure-common.c +++ b/src/interfaces/libpq/fe-secure-common.c @@ -94,8 +94,8 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn, if (!(host && host[0] != '\0')) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("host name must be specified\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("host name must be specified\n")); return -1; } @@ -106,8 +106,8 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn, name = malloc(namelen + 1); if (name == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return -1; } memcpy(name, namedata, namelen); @@ -120,8 +120,8 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn, if (namelen != strlen(name)) { free(name); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL certificate's name contains embedded null\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSL certificate's name contains embedded null\n")); return -1; } @@ -167,8 +167,8 @@ pq_verify_peer_name_matches_certificate(PGconn *conn) /* Check that we have a hostname to compare with. */ if (!(host && host[0] != '\0')) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("host name must be specified for a verified SSL connection\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("host name must be specified for a verified SSL connection\n")); return false; } @@ -184,7 +184,7 @@ pq_verify_peer_name_matches_certificate(PGconn *conn) */ 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", "server certificate for \"%s\" (and %d other names) does not match host name \"%s\"\n", names_examined - 1), @@ -192,14 +192,14 @@ pq_verify_peer_name_matches_certificate(PGconn *conn) } else if (names_examined == 1) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("server certificate for \"%s\" does not match host name \"%s\"\n"), first_name, host); } else { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not get server's host name from server certificate\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not get server's host name from server certificate\n")); } } diff --git a/src/interfaces/libpq/fe-secure-gssapi.c b/src/interfaces/libpq/fe-secure-gssapi.c index 8c0ba69b7c0..c783a53734e 100644 --- a/src/interfaces/libpq/fe-secure-gssapi.c +++ b/src/interfaces/libpq/fe-secure-gssapi.c @@ -78,7 +78,7 @@ * * On success, returns the number of data bytes consumed (possibly less than * 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) * once the socket is ready. */ @@ -106,8 +106,8 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len) */ if (len < PqGSSSendConsumed) { - printfPQExpBuffer(&conn->errorMessage, - "GSSAPI caller failed to retransmit all data needing to be retried\n"); + appendPQExpBufferStr(&conn->errorMessage, + "GSSAPI caller failed to retransmit all data needing to be retried\n"); errno = EINVAL; return -1; } @@ -205,15 +205,15 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len) if (conf_state == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("outgoing GSSAPI message would not use confidentiality\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("outgoing GSSAPI message would not use confidentiality\n")); errno = EIO; /* for lack of a better idea */ goto cleanup; } 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"), (size_t) output.length, PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)); @@ -258,7 +258,7 @@ cleanup: * * Returns the number of data bytes read, or on failure, returns -1 * 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. */ ssize_t @@ -350,7 +350,7 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len) 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"), (size_t) input.length, PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)); @@ -399,8 +399,8 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len) if (conf_state == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("incoming GSSAPI message did not use confidentiality\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("incoming GSSAPI message did not use confidentiality\n")); ret = -1; errno = EIO; /* for lack of a better idea */ goto cleanup; @@ -500,8 +500,8 @@ pqsecure_open_gss(PGconn *conn) PqGSSResultBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE); if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return PGRES_POLLING_FAILED; } PqGSSSendLength = PqGSSSendNext = PqGSSSendConsumed = 0; @@ -578,7 +578,7 @@ pqsecure_open_gss(PGconn *conn) PqGSSRecvLength += ret; - printfPQExpBuffer(&conn->errorMessage, "%s\n", PqGSSRecvBuffer + 1); + appendPQExpBuffer(&conn->errorMessage, "%s\n", PqGSSRecvBuffer + 1); return PGRES_POLLING_FAILED; } @@ -592,7 +592,7 @@ pqsecure_open_gss(PGconn *conn) input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer); 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"), (size_t) input.length, PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)); diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index d63e4bb2797..075f754e1fb 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -181,8 +181,8 @@ rloop: if (n < 0) { /* Not supposed to happen, so we don't translate the msg */ - printfPQExpBuffer(&conn->errorMessage, - "SSL_read failed but did not provide error information\n"); + appendPQExpBufferStr(&conn->errorMessage, + "SSL_read failed but did not provide error information\n"); /* assume the connection is broken */ result_errno = ECONNRESET; } @@ -205,20 +205,20 @@ rloop: result_errno = SOCK_ERRNO; if (result_errno == EPIPE || result_errno == ECONNRESET) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server closed the connection unexpectedly\n" - "\tThis probably means the server terminated abnormally\n" - "\tbefore or while processing the request.\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request.\n")); else - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); } else { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL SYSCALL error: EOF detected\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSL SYSCALL error: EOF detected\n")); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; @@ -228,7 +228,7 @@ rloop: { char *errm = SSLerrmessage(ecode); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), errm); SSLerrfree(errm); /* assume the connection is broken */ @@ -243,13 +243,13 @@ rloop: * a clean connection closure, so we should not report it as a * server crash. */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL connection has been closed unexpectedly\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSL connection has been closed unexpectedly\n")); result_errno = ECONNRESET; n = -1; break; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); /* assume the connection is broken */ @@ -290,8 +290,8 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len) if (n < 0) { /* Not supposed to happen, so we don't translate the msg */ - printfPQExpBuffer(&conn->errorMessage, - "SSL_write failed but did not provide error information\n"); + appendPQExpBufferStr(&conn->errorMessage, + "SSL_write failed but did not provide error information\n"); /* assume the connection is broken */ result_errno = ECONNRESET; } @@ -312,20 +312,20 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len) { result_errno = SOCK_ERRNO; if (result_errno == EPIPE || result_errno == ECONNRESET) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server closed the connection unexpectedly\n" - "\tThis probably means the server terminated abnormally\n" - "\tbefore or while processing the request.\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request.\n")); else - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); } else { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL SYSCALL error: EOF detected\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSL SYSCALL error: EOF detected\n")); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; @@ -335,7 +335,7 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len) { char *errm = SSLerrmessage(ecode); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), errm); SSLerrfree(errm); /* assume the connection is broken */ @@ -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 * server crash. */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL connection has been closed unexpectedly\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSL connection has been closed unexpectedly\n")); result_errno = ECONNRESET; n = -1; break; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); /* assume the connection is broken */ @@ -396,8 +396,8 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) if (!OBJ_find_sigid_algs(X509_get_signature_nid(peer_cert), &algo_nid, NULL)) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not determine server certificate signature algorithm\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not determine server certificate signature algorithm\n")); return NULL; } @@ -417,7 +417,7 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) algo_type = EVP_get_digestbynid(algo_nid); if (algo_type == NULL) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not find digest for NID %s\n"), OBJ_nid2sn(algo_nid)); return NULL; @@ -427,8 +427,8 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) if (!X509_digest(peer_cert, algo_type, hash, &hash_size)) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not generate peer certificate hash\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not generate peer certificate hash\n")); return NULL; } @@ -436,8 +436,8 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) cert_hash = malloc(hash_size); if (cert_hash == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return NULL; } memcpy(cert_hash, hash, hash_size); @@ -484,8 +484,8 @@ openssl_verify_peer_name_matches_certificate_name(PGconn *conn, ASN1_STRING *nam /* Should not happen... */ if (name_entry == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL certificate's name entry is missing\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSL certificate's name entry is missing\n")); return -1; } @@ -811,7 +811,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not create SSL context: %s\n"), err); SSLerrfree(err); @@ -850,7 +850,7 @@ initialize_SSL(PGconn *conn) if (ssl_min_ver == -1) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid value \"%s\" for minimum SSL protocol version\n"), conn->ssl_min_protocol_version); SSL_CTX_free(SSL_context); @@ -861,7 +861,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set minimum SSL protocol version: %s\n"), err); SSLerrfree(err); @@ -879,7 +879,7 @@ initialize_SSL(PGconn *conn) if (ssl_max_ver == -1) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid value \"%s\" for maximum SSL protocol version\n"), conn->ssl_max_protocol_version); SSL_CTX_free(SSL_context); @@ -890,7 +890,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set maximum SSL protocol version: %s\n"), err); SSLerrfree(err); @@ -926,7 +926,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read root certificate file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); @@ -970,11 +970,11 @@ initialize_SSL(PGconn *conn) * that it seems worth having a specialized error message for it. */ if (fnbuf[0] == '\0') - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, 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")); else - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("root certificate file \"%s\" does not exist\n" "Either provide the file or change sslmode to disable server certificate verification.\n"), fnbuf); SSL_CTX_free(SSL_context); @@ -1005,7 +1005,7 @@ initialize_SSL(PGconn *conn) */ if (errno != ENOENT && errno != ENOTDIR) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open certificate file \"%s\": %s\n"), fnbuf, strerror_r(errno, sebuf, sizeof(sebuf))); SSL_CTX_free(SSL_context); @@ -1024,7 +1024,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read certificate file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); @@ -1049,7 +1049,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not establish SSL connection: %s\n"), err); SSLerrfree(err); @@ -1087,8 +1087,8 @@ initialize_SSL(PGconn *conn) if (engine_str == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return -1; } @@ -1103,7 +1103,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not load SSL engine \"%s\": %s\n"), engine_str, err); SSLerrfree(err); @@ -1115,7 +1115,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not initialize SSL engine \"%s\": %s\n"), engine_str, err); SSLerrfree(err); @@ -1131,7 +1131,7 @@ initialize_SSL(PGconn *conn) { 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"), engine_colon, engine_str, err); SSLerrfree(err); @@ -1145,7 +1145,7 @@ initialize_SSL(PGconn *conn) { 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"), engine_colon, engine_str, err); SSLerrfree(err); @@ -1182,7 +1182,7 @@ initialize_SSL(PGconn *conn) if (stat(fnbuf, &buf) != 0) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate present, but not private key file \"%s\"\n"), fnbuf); return -1; @@ -1190,7 +1190,7 @@ initialize_SSL(PGconn *conn) #ifndef WIN32 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"), fnbuf); return -1; @@ -1215,7 +1215,7 @@ initialize_SSL(PGconn *conn) */ 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"), fnbuf, err); SSLerrfree(err); @@ -1233,7 +1233,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate does not match private key file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); @@ -1287,12 +1287,12 @@ open_client_SSL(PGconn *conn) char sebuf[PG_STRERROR_R_BUFLEN]; if (r == -1) - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); else - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL SYSCALL error: EOF detected\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSL SYSCALL error: EOF detected\n")); pgtls_close(conn); return PGRES_POLLING_FAILED; } @@ -1300,7 +1300,7 @@ open_client_SSL(PGconn *conn) { char *err = SSLerrmessage(ecode); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), err); SSLerrfree(err); @@ -1350,7 +1350,7 @@ open_client_SSL(PGconn *conn) } default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); pgtls_close(conn); @@ -1369,7 +1369,7 @@ open_client_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate could not be obtained: %s\n"), err); SSLerrfree(err); diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c index 373c59cb0d6..67b1e785129 100644 --- a/src/interfaces/libpq/fe-secure.c +++ b/src/interfaces/libpq/fe-secure.c @@ -205,8 +205,8 @@ pqsecure_close(PGconn *conn) /* * Read data from a secure connection. * - * On failure, this function is responsible for putting a suitable message - * into conn->errorMessage. The caller must still inspect errno, but only + * On failure, this function is responsible for appending a suitable message + * to conn->errorMessage. The caller must still inspect errno, but only * to determine whether to continue/retry after error. */ ssize_t @@ -263,14 +263,14 @@ pqsecure_raw_read(PGconn *conn, void *ptr, size_t len) case EPIPE: case ECONNRESET: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server closed the connection unexpectedly\n" - "\tThis probably means the server terminated abnormally\n" - "\tbefore or while processing the request.\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request.\n")); break; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive data from server: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); @@ -287,8 +287,8 @@ pqsecure_raw_read(PGconn *conn, void *ptr, size_t len) /* * Write data to a secure connection. * - * On failure, this function is responsible for putting a suitable message - * into conn->errorMessage. The caller must still inspect errno, but only + * On failure, this function is responsible for appending a suitable message + * to conn->errorMessage. The caller must still inspect errno, but only * to determine whether to continue/retry after error. */ ssize_t @@ -376,14 +376,14 @@ retry_masked: /* FALL THRU */ case ECONNRESET: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server closed the connection unexpectedly\n" - "\tThis probably means the server terminated abnormally\n" - "\tbefore or while processing the request.\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request.\n")); break; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send data to server: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index e1018adb9e5..4db498369c7 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -522,7 +522,11 @@ struct pg_conn * connection */ #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 */ /* Buffer for receiving various parts of messages */ @@ -600,7 +604,6 @@ extern pgthreadlock_t pg_g_threadlock; /* === in fe-exec.c === */ 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 char *pqResultStrdup(PGresult *res, const char *str); extern void pqClearAsyncResult(PGconn *conn); @@ -612,6 +615,7 @@ extern void pqSaveMessageField(PGresult *res, char code, extern void pqSaveParameterStatus(PGconn *conn, const char *name, const char *value); extern int pqRowProcessor(PGconn *conn, const char **errmsgp); +extern int PQsendQueryContinue(PGconn *conn, const char *query); /* === in fe-protocol2.c === */ @@ -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 * 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); @@ -725,8 +729,8 @@ extern void pgtls_close(PGconn *conn); /* * Read data from a secure connection. * - * On failure, this function is responsible for putting a suitable message - * into conn->errorMessage. The caller must still inspect errno, but only + * On failure, this function is responsible for appending a suitable message + * to conn->errorMessage. The caller must still inspect errno, but only * to determine whether to continue/retry after error. */ extern ssize_t pgtls_read(PGconn *conn, void *ptr, size_t len); @@ -739,8 +743,8 @@ extern bool pgtls_read_pending(PGconn *conn); /* * Write data to a secure connection. * - * On failure, this function is responsible for putting a suitable message - * into conn->errorMessage. The caller must still inspect errno, but only + * On failure, this function is responsible for appending a suitable message + * to conn->errorMessage. The caller must still inspect errno, but only * to determine whether to continue/retry after error. */ extern ssize_t pgtls_write(PGconn *conn, const void *ptr, size_t len); |