diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2021-01-11 13:12:09 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2021-01-11 13:12:09 -0500 |
commit | ffa2e4670123124b92f037d335a1e844c3782d3f (patch) | |
tree | d7a1d1c6779c862d5673e24cb3ce3a824d55446f /src/interfaces/libpq/fe-connect.c | |
parent | ce6a71fa5300cf00adf32c9daee302c523609709 (diff) |
In libpq, always append new error messages to conn->errorMessage.
Previously, we had an undisciplined mish-mash of printfPQExpBuffer and
appendPQExpBuffer calls to report errors within libpq. This commit
establishes a uniform rule that appendPQExpBuffer[Str] should be used.
conn->errorMessage is reset only at the start of an application request,
and then accumulates messages till we're done. We can remove no less
than three different ad-hoc mechanisms that were used to get the effect
of concatenation of error messages within a sequence of operations.
Although this makes things quite a bit cleaner conceptually, the main
reason to do it is to make the world safer for the multiple-target-host
feature that was added awhile back. Previously, there were many cases
in which an error occurring during an individual host connection attempt
would wipe out the record of what had happened during previous attempts.
(The reporting is still inadequate, in that it can be hard to tell which
host got the failure, but that seems like a matter for a separate commit.)
Currently, lo_import and lo_export contain exceptions to the "never
use printfPQExpBuffer" rule. If we changed them, we'd risk reporting
an incidental lo_close failure before the actual read or write
failure, which would be confusing, not least because lo_close happened
after the main failure. We could improve this by inventing an
internal version of lo_close that doesn't reset the errorMessage; but
we'd also need a version of PQfn() that does that, and it didn't quite
seem worth the trouble for now.
Discussion: https://postgr.es/m/BN6PR05MB3492948E4FD76C156E747E8BC9160@BN6PR05MB3492.namprd05.prod.outlook.com
Diffstat (limited to 'src/interfaces/libpq/fe-connect.c')
-rw-r--r-- | src/interfaces/libpq/fe-connect.c | 317 |
1 files changed, 129 insertions, 188 deletions
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 :-( */ |