From de4cb33dcc98c7c71f21349eba650105a3385cbd Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 23 Sep 2022 16:26:16 -0400 Subject: [PATCH v2] WIP: libpq_append_error Discussion: https://www.postgresql.org/message-id/flat/7c0232ef-7b44-68db-599d-b327d0640a77@enterprisedb.com --- src/interfaces/libpq/fe-connect.c | 271 +++++++++++------------------ src/interfaces/libpq/fe-exec.c | 110 ++++-------- src/interfaces/libpq/fe-misc.c | 15 ++ src/interfaces/libpq/libpq-int.h | 2 + src/interfaces/libpq/nls.mk | 4 +- src/interfaces/libpq/pqexpbuffer.c | 27 ++- src/interfaces/libpq/pqexpbuffer.h | 2 + 7 files changed, 186 insertions(+), 245 deletions(-) diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 746e9b4f1efc..b99c4549d08e 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -896,8 +896,7 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions) *connmember = strdup(tmp); if (*connmember == NULL) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("out of memory\n")); + libpq_append_error(conn, "out of memory"); return false; } } @@ -1079,9 +1078,8 @@ connectOptions2(PGconn *conn) if (more || i != conn->nconnhost) { conn->status = CONNECTION_BAD; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not match %d host names to %d hostaddr values\n"), - count_comma_separated_elems(conn->pghost), conn->nconnhost); + libpq_append_error(conn, "could not match %d host names to %d hostaddr values", + count_comma_separated_elems(conn->pghost), conn->nconnhost); return false; } } @@ -1160,9 +1158,8 @@ connectOptions2(PGconn *conn) else if (more || i != conn->nconnhost) { conn->status = CONNECTION_BAD; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not match %d port numbers to %d hosts\n"), - count_comma_separated_elems(conn->pgport), conn->nconnhost); + libpq_append_error(conn, "could not match %d port numbers to %d hosts", + count_comma_separated_elems(conn->pgport), conn->nconnhost); return false; } } @@ -1250,9 +1247,8 @@ connectOptions2(PGconn *conn) && strcmp(conn->channel_binding, "require") != 0) { conn->status = CONNECTION_BAD; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid %s value: \"%s\"\n"), - "channel_binding", conn->channel_binding); + libpq_append_error(conn, "invalid %s value: \"%s\"", + "channel_binding", conn->channel_binding); return false; } } @@ -1276,9 +1272,8 @@ connectOptions2(PGconn *conn) && strcmp(conn->sslmode, "verify-full") != 0) { conn->status = CONNECTION_BAD; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid %s value: \"%s\"\n"), - "sslmode", conn->sslmode); + libpq_append_error(conn, "invalid %s value: \"%s\"", + "sslmode", conn->sslmode); return false; } @@ -1297,9 +1292,8 @@ connectOptions2(PGconn *conn) case 'r': /* "require" */ case 'v': /* "verify-ca" or "verify-full" */ conn->status = CONNECTION_BAD; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("sslmode value \"%s\" invalid when SSL support is not compiled in\n"), - conn->sslmode); + libpq_append_error(conn, "sslmode value \"%s\" invalid when SSL support is not compiled in", + conn->sslmode); return false; } #endif @@ -1318,19 +1312,17 @@ connectOptions2(PGconn *conn) if (!sslVerifyProtocolVersion(conn->ssl_min_protocol_version)) { conn->status = CONNECTION_BAD; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid %s value: \"%s\"\n"), - "ssl_min_protocol_version", - conn->ssl_min_protocol_version); + libpq_append_error(conn, "invalid %s value: \"%s\"", + "ssl_min_protocol_version", + conn->ssl_min_protocol_version); return false; } if (!sslVerifyProtocolVersion(conn->ssl_max_protocol_version)) { conn->status = CONNECTION_BAD; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid %s value: \"%s\"\n"), - "ssl_max_protocol_version", - conn->ssl_max_protocol_version); + libpq_append_error(conn, "invalid %s value: \"%s\"", + "ssl_max_protocol_version", + conn->ssl_max_protocol_version); return false; } @@ -1345,8 +1337,7 @@ connectOptions2(PGconn *conn) conn->ssl_max_protocol_version)) { conn->status = CONNECTION_BAD; - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("invalid SSL protocol version range\n")); + libpq_append_error(conn, "invalid SSL protocol version range"); return false; } @@ -1360,19 +1351,15 @@ connectOptions2(PGconn *conn) strcmp(conn->gssencmode, "require") != 0) { conn->status = CONNECTION_BAD; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid %s value: \"%s\"\n"), - "gssencmode", - conn->gssencmode); + libpq_append_error(conn, "invalid %s value: \"%s\"", "gssencmode", conn->gssencmode); return false; } #ifndef ENABLE_GSS if (strcmp(conn->gssencmode, "require") == 0) { conn->status = CONNECTION_BAD; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("gssencmode value \"%s\" invalid when GSSAPI support is not compiled in\n"), - conn->gssencmode); + libpq_append_error(conn, "gssencmode value \"%s\" invalid when GSSAPI support is not compiled in", + conn->gssencmode); return false; } #endif @@ -1404,10 +1391,9 @@ connectOptions2(PGconn *conn) else { conn->status = CONNECTION_BAD; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid %s value: \"%s\"\n"), - "target_session_attrs", - conn->target_session_attrs); + libpq_append_error(conn, "invalid %s value: \"%s\"", + "target_session_attrs", + conn->target_session_attrs); return false; } } @@ -1437,8 +1423,7 @@ connectOptions2(PGconn *conn) oom_error: conn->status = CONNECTION_BAD; - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("out of memory\n")); + libpq_append_error(conn, "out of memory"); return false; } @@ -1600,8 +1585,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, oom_error: conn->status = CONNECTION_BAD; - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("out of memory\n")); + libpq_append_error(conn, "out of memory"); return conn; } @@ -1624,9 +1608,8 @@ connectNoDelay(PGconn *conn) { char sebuf[PG_STRERROR_R_BUFLEN]; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not set socket to TCP no delay mode: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "could not set socket to TCP no delay mode: %s", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } #endif @@ -1738,11 +1721,9 @@ connectFailureMessage(PGconn *conn, int errorno) SOCK_STRERROR(errorno, sebuf, sizeof(sebuf))); if (conn->raddr.addr.ss_family == AF_UNIX) - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("\tIs the server running locally and accepting connections on that socket?\n")); + libpq_append_error(conn, "\tIs the server running locally and accepting connections on that socket?"); else - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("\tIs the server running on that host and accepting TCP/IP connections?\n")); + libpq_append_error(conn, "\tIs the server running on that host and accepting TCP/IP connections?"); } /* @@ -1805,9 +1786,8 @@ parse_int_param(const char *value, int *result, PGconn *conn, return true; error: - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid integer value \"%s\" for connection option \"%s\"\n"), - value, context); + libpq_append_error(conn, "invalid integer value \"%s\" for connection option \"%s\"", + value, context); return false; } @@ -1835,11 +1815,10 @@ setKeepalivesIdle(PGconn *conn) { char sebuf[PG_STRERROR_R_BUFLEN]; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("%s(%s) failed: %s\n"), - "setsockopt", - PG_TCP_KEEPALIVE_IDLE_STR, - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "%s(%s) failed: %s", + "setsockopt", + PG_TCP_KEEPALIVE_IDLE_STR, + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } #endif @@ -1870,11 +1849,10 @@ setKeepalivesInterval(PGconn *conn) { char sebuf[PG_STRERROR_R_BUFLEN]; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("%s(%s) failed: %s\n"), - "setsockopt", - "TCP_KEEPINTVL", - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "%s(%s) failed: %s", + "setsockopt", + "TCP_KEEPINTVL", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } #endif @@ -1906,11 +1884,10 @@ setKeepalivesCount(PGconn *conn) { char sebuf[PG_STRERROR_R_BUFLEN]; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("%s(%s) failed: %s\n"), - "setsockopt", - "TCP_KEEPCNT", - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "%s(%s) failed: %s", + "setsockopt", + "TCP_KEEPCNT", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } #endif @@ -1971,8 +1948,7 @@ prepKeepalivesWin32(PGconn *conn) if (!setKeepalivesWin32(conn->sock, idle, interval)) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("%s(%s) failed: error code %d\n"), + libpq_append_error(conn, "%s(%s) failed: error code %d", "WSAIoctl", "SIO_KEEPALIVE_VALS", WSAGetLastError()); return 0; @@ -2006,11 +1982,10 @@ setTCPUserTimeout(PGconn *conn) { char sebuf[256]; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("%s(%s) failed: %s\n"), - "setsockopt", - "TCP_USER_TIMEOUT", - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "%s(%s) failed: %s", + "setsockopt", + "TCP_USER_TIMEOUT", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } #endif @@ -2286,8 +2261,7 @@ PQconnectPoll(PGconn *conn) break; default: - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("invalid connection state, probably indicative of memory corruption\n")); + libpq_append_error(conn, "invalid connection state, probably indicative of memory corruption"); goto error_return; } @@ -2365,9 +2339,7 @@ PQconnectPoll(PGconn *conn) if (thisport < 1 || thisport > 65535) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid port number: \"%s\"\n"), - ch->port); + libpq_append_error(conn, "invalid port number: \"%s\"", ch->port); goto keep_going; } } @@ -2381,9 +2353,8 @@ PQconnectPoll(PGconn *conn) &conn->addrlist); if (ret || !conn->addrlist) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not translate host name \"%s\" to address: %s\n"), - ch->host, gai_strerror(ret)); + libpq_append_error(conn, "could not translate host name \"%s\" to address: %s", + ch->host, gai_strerror(ret)); goto keep_going; } break; @@ -2394,9 +2365,8 @@ PQconnectPoll(PGconn *conn) &conn->addrlist); if (ret || !conn->addrlist) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not parse network address \"%s\": %s\n"), - ch->hostaddr, gai_strerror(ret)); + libpq_append_error(conn, "could not parse network address \"%s\": %s", + ch->hostaddr, gai_strerror(ret)); goto keep_going; } break; @@ -2406,10 +2376,9 @@ PQconnectPoll(PGconn *conn) UNIXSOCK_PATH(portstr, thisport, ch->host); if (strlen(portstr) >= UNIXSOCK_PATH_BUFLEN) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("Unix-domain socket path \"%s\" is too long (maximum %d bytes)\n"), - portstr, - (int) (UNIXSOCK_PATH_BUFLEN - 1)); + libpq_append_error(conn, "Unix-domain socket path \"%s\" is too long (maximum %d bytes)", + portstr, + (int) (UNIXSOCK_PATH_BUFLEN - 1)); goto keep_going; } @@ -2421,9 +2390,8 @@ PQconnectPoll(PGconn *conn) &conn->addrlist); if (ret || !conn->addrlist) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not translate Unix-domain socket path \"%s\" to address: %s\n"), - portstr, gai_strerror(ret)); + libpq_append_error(conn, "could not translate Unix-domain socket path \"%s\" to address: %s", + portstr, gai_strerror(ret)); goto keep_going; } break; @@ -2544,9 +2512,8 @@ PQconnectPoll(PGconn *conn) goto keep_going; } emitHostIdentityInfo(conn, host_addr); - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not create socket: %s\n"), - SOCK_STRERROR(errorno, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "could not create socket: %s", + SOCK_STRERROR(errorno, sebuf, sizeof(sebuf))); goto error_return; } @@ -2575,9 +2542,8 @@ PQconnectPoll(PGconn *conn) } if (!pg_set_noblock(conn->sock)) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not set socket to nonblocking mode: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "could not set socket to nonblocking mode: %s", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); conn->try_next_addr = true; goto keep_going; } @@ -2585,9 +2551,8 @@ PQconnectPoll(PGconn *conn) #ifdef F_SETFD if (fcntl(conn->sock, F_SETFD, FD_CLOEXEC) == -1) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not set socket to close-on-exec mode: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "could not set socket to close-on-exec mode: %s", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); conn->try_next_addr = true; goto keep_going; } @@ -2603,8 +2568,7 @@ PQconnectPoll(PGconn *conn) if (usekeepalives < 0) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("keepalives parameter must be an integer\n")); + libpq_append_error(conn, "keepalives parameter must be an integer"); err = 1; } else if (usekeepalives == 0) @@ -2616,11 +2580,10 @@ PQconnectPoll(PGconn *conn) SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("%s(%s) failed: %s\n"), - "setsockopt", - "SO_KEEPALIVE", - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "%s(%s) failed: %s", + "setsockopt", + "SO_KEEPALIVE", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); err = 1; } else if (!setKeepalivesIdle(conn) @@ -2744,9 +2707,8 @@ PQconnectPoll(PGconn *conn) if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR, (char *) &optval, &optlen) == -1) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not get socket error status: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "could not get socket error status: %s", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); goto error_return; } else if (optval != 0) @@ -2772,9 +2734,8 @@ PQconnectPoll(PGconn *conn) (struct sockaddr *) &conn->laddr.addr, &conn->laddr.salen) < 0) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not get client address from socket: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "could not get client address from socket: %s", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); goto error_return; } @@ -2811,12 +2772,10 @@ PQconnectPoll(PGconn *conn) * stub */ if (errno == ENOSYS) - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("requirepeer parameter is not supported on this platform\n")); + libpq_append_error(conn, "requirepeer parameter is not supported on this platform"); else - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not get peer credentials: %s\n"), - strerror_r(errno, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "could not get peer credentials: %s", + strerror_r(errno, sebuf, sizeof(sebuf))); goto error_return; } @@ -2828,9 +2787,8 @@ PQconnectPoll(PGconn *conn) if (strcmp(remote_username, conn->requirepeer) != 0) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("requirepeer specifies \"%s\", but actual peer user name is \"%s\"\n"), - conn->requirepeer, remote_username); + libpq_append_error(conn, "requirepeer specifies \"%s\", but actual peer user name is \"%s\"", + conn->requirepeer, remote_username); free(remote_username); goto error_return; } @@ -2870,9 +2828,8 @@ PQconnectPoll(PGconn *conn) if (pqPacketSend(conn, 0, &pv, sizeof(pv)) != STATUS_OK) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not send GSSAPI negotiation packet: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "could not send GSSAPI negotiation packet: %s", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); goto error_return; } @@ -2882,8 +2839,8 @@ PQconnectPoll(PGconn *conn) } else if (!conn->gctx && conn->gssencmode[0] == 'r') { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("GSSAPI encryption required but was impossible (possibly no credential cache, no server support, or using a local socket)\n")); + libpq_append_error(conn, + "GSSAPI encryption required but was impossible (possibly no credential cache, no server support, or using a local socket)"); goto error_return; } #endif @@ -2924,9 +2881,8 @@ PQconnectPoll(PGconn *conn) pv = pg_hton32(NEGOTIATE_SSL_CODE); if (pqPacketSend(conn, 0, &pv, sizeof(pv)) != STATUS_OK) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not send SSL negotiation packet: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "could not send SSL negotiation packet: %s", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); goto error_return; } /* Ok, wait for response */ @@ -2942,8 +2898,7 @@ PQconnectPoll(PGconn *conn) EnvironmentOptions); if (!startpacket) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("out of memory\n")); + libpq_append_error(conn, "out of memory"); goto error_return; } @@ -2955,9 +2910,8 @@ PQconnectPoll(PGconn *conn) */ if (pqPacketSend(conn, 0, startpacket, packetlen) != STATUS_OK) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not send startup packet: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + libpq_append_error(conn, "could not send startup packet: %s", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); free(startpacket); goto error_return; } @@ -3031,8 +2985,7 @@ PQconnectPoll(PGconn *conn) * "verify-full" */ { /* Require SSL, but server does not want it */ - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("server does not support SSL, but SSL was required\n")); + libpq_append_error(conn, "server does not support SSL, but SSL was required"); goto error_return; } /* Otherwise, proceed with normal startup */ @@ -3058,9 +3011,8 @@ PQconnectPoll(PGconn *conn) } else { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("received invalid response to SSL negotiation: %c\n"), - SSLok); + libpq_append_error(conn, "received invalid response to SSL negotiation: %c", + SSLok); goto error_return; } } @@ -3079,8 +3031,7 @@ PQconnectPoll(PGconn *conn) */ if (conn->inCursor != conn->inEnd) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("received unencrypted data after SSL response\n")); + libpq_append_error(conn, "received unencrypted data after SSL response"); goto error_return; } @@ -3160,8 +3111,7 @@ PQconnectPoll(PGconn *conn) /* Server doesn't want GSSAPI; fall back if we can */ if (conn->gssencmode[0] == 'r') { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("server doesn't support GSSAPI encryption, but it was required\n")); + libpq_append_error(conn, "server doesn't support GSSAPI encryption, but it was required"); goto error_return; } @@ -3172,9 +3122,8 @@ PQconnectPoll(PGconn *conn) } else if (gss_ok != 'G') { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("received invalid response to GSSAPI negotiation: %c\n"), - gss_ok); + libpq_append_error(conn, "received invalid response to GSSAPI negotiation: %c", + gss_ok); goto error_return; } } @@ -3191,8 +3140,7 @@ PQconnectPoll(PGconn *conn) */ if (conn->inCursor != conn->inEnd) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("received unencrypted data after GSSAPI encryption response\n")); + libpq_append_error(conn, "received unencrypted data after GSSAPI encryption response"); goto error_return; } @@ -3251,9 +3199,8 @@ PQconnectPoll(PGconn *conn) */ if (!(beresp == 'R' || beresp == 'E')) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("expected authentication request from server, but received %c\n"), - beresp); + libpq_append_error(conn, "expected authentication request from server, but received %c", + beresp); goto error_return; } @@ -3276,9 +3223,8 @@ PQconnectPoll(PGconn *conn) */ if (beresp == 'R' && (msgLength < 8 || msgLength > 2000)) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("expected authentication request from server, but received %c\n"), - beresp); + libpq_append_error(conn, "expected authentication request from server, but received %c", + beresp); goto error_return; } @@ -3483,8 +3429,7 @@ PQconnectPoll(PGconn *conn) if (res) { if (res->resultStatus != PGRES_FATAL_ERROR) - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("unexpected message from server during startup\n")); + libpq_append_error(conn, "unexpected message from server during startup"); else if (conn->send_appname && (conn->appname || conn->fbappname)) { @@ -3575,11 +3520,9 @@ PQconnectPoll(PGconn *conn) { /* Wrong server state, reject and try the next host */ if (conn->target_server_type == SERVER_TYPE_READ_WRITE) - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("session is read-only\n")); + libpq_append_error(conn, "session is read-only"); else - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("session is not read-only\n")); + libpq_append_error(conn, "session is not read-only"); /* Close connection politely. */ conn->status = CONNECTION_OK; @@ -3632,11 +3575,9 @@ PQconnectPoll(PGconn *conn) { /* Wrong server state, reject and try the next host */ if (conn->target_server_type == SERVER_TYPE_PRIMARY) - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("server is in hot standby mode\n")); + libpq_append_error(conn, "server is in hot standby mode"); else - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("server is not in hot standby mode\n")); + libpq_append_error(conn, "server is not in hot standby mode"); /* Close connection politely. */ conn->status = CONNECTION_OK; diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 0274c1b156c6..5bc5d963aa68 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -1316,8 +1316,7 @@ pqAllocCmdQueueEntry(PGconn *conn) entry = (PGcmdQueueEntry *) malloc(sizeof(PGcmdQueueEntry)); if (entry == NULL) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("out of memory\n")); + libpq_append_error(conn, "out of memory"); return NULL; } } @@ -1440,8 +1439,7 @@ PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery) /* check the argument */ if (!query) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("command string is a null pointer\n")); + libpq_append_error(conn, "command string is a null pointer"); return 0; } @@ -1511,15 +1509,13 @@ PQsendQueryParams(PGconn *conn, /* check the arguments */ if (!command) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("command string is a null pointer\n")); + libpq_append_error(conn, "command string is a null pointer"); return 0; } if (nParams < 0 || nParams > PQ_QUERY_PARAM_MAX_LIMIT) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("number of parameters must be between 0 and %d\n"), - PQ_QUERY_PARAM_MAX_LIMIT); + libpq_append_error(conn, "number of parameters must be between 0 and %d", + PQ_QUERY_PARAM_MAX_LIMIT); return 0; } @@ -1554,21 +1550,18 @@ PQsendPrepare(PGconn *conn, /* check the arguments */ if (!stmtName) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("statement name is a null pointer\n")); + libpq_append_error(conn, "statement name is a null pointer"); return 0; } if (!query) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("command string is a null pointer\n")); + libpq_append_error(conn, "command string is a null pointer"); return 0; } if (nParams < 0 || nParams > PQ_QUERY_PARAM_MAX_LIMIT) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("number of parameters must be between 0 and %d\n"), - PQ_QUERY_PARAM_MAX_LIMIT); + libpq_append_error(conn, "number of parameters must be between 0 and %d", + PQ_QUERY_PARAM_MAX_LIMIT); return 0; } @@ -1656,15 +1649,13 @@ PQsendQueryPrepared(PGconn *conn, /* check the arguments */ if (!stmtName) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("statement name is a null pointer\n")); + libpq_append_error(conn, "statement name is a null pointer"); return 0; } if (nParams < 0 || nParams > PQ_QUERY_PARAM_MAX_LIMIT) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("number of parameters must be between 0 and %d\n"), - PQ_QUERY_PARAM_MAX_LIMIT); + libpq_append_error(conn, "number of parameters must be between 0 and %d", + PQ_QUERY_PARAM_MAX_LIMIT); return 0; } @@ -1700,8 +1691,7 @@ PQsendQueryStart(PGconn *conn, bool newQuery) /* Don't try to send if we know there's no live connection. */ if (conn->status != CONNECTION_OK) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("no connection to the server\n")); + libpq_append_error(conn, "no connection to the server"); return false; } @@ -1709,8 +1699,7 @@ PQsendQueryStart(PGconn *conn, bool newQuery) if (conn->asyncStatus != PGASYNC_IDLE && conn->pipelineStatus == PQ_PIPELINE_OFF) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("another command is already in progress\n")); + libpq_append_error(conn, "another command is already in progress"); return false; } @@ -1740,8 +1729,7 @@ PQsendQueryStart(PGconn *conn, bool newQuery) case PGASYNC_COPY_IN: case PGASYNC_COPY_OUT: case PGASYNC_COPY_BOTH: - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("cannot queue commands during COPY\n")); + libpq_append_error(conn, "cannot queue commands during COPY"); return false; } } @@ -1858,8 +1846,7 @@ PQsendQueryGuts(PGconn *conn, nbytes = paramLengths[i]; else { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("length must be given for binary parameter\n")); + libpq_append_error(conn, "length must be given for binary parameter"); goto sendFailed; } } @@ -2181,9 +2168,7 @@ PQgetResult(PGconn *conn) res = getCopyResult(conn, PGRES_COPY_BOTH); break; default: - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("unexpected asyncStatus: %d\n"), - (int) conn->asyncStatus); + libpq_append_error(conn, "unexpected asyncStatus: %d", (int) conn->asyncStatus); pqSaveErrorResult(conn); conn->asyncStatus = PGASYNC_IDLE; /* try to restore valid state */ res = pqPrepareAsyncResult(conn); @@ -2339,8 +2324,7 @@ PQexecStart(PGconn *conn) if (conn->pipelineStatus != PQ_PIPELINE_OFF) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("synchronous command execution functions are not allowed in pipeline mode\n")); + libpq_append_error(conn, "synchronous command execution functions are not allowed in pipeline mode"); return false; } @@ -2373,8 +2357,7 @@ PQexecStart(PGconn *conn) else if (resultStatus == PGRES_COPY_BOTH) { /* We don't allow PQexec during COPY BOTH */ - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("PQexec not allowed during COPY BOTH\n")); + libpq_append_error(conn, "PQexec not allowed during COPY BOTH"); return false; } /* check for loss of connection, too */ @@ -2600,8 +2583,7 @@ PQputCopyData(PGconn *conn, const char *buffer, int nbytes) if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_BOTH) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); + libpq_append_error(conn, "no COPY in progress"); return -1; } @@ -2656,8 +2638,7 @@ PQputCopyEnd(PGconn *conn, const char *errormsg) if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_BOTH) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); + libpq_append_error(conn, "no COPY in progress"); return -1; } @@ -2725,8 +2706,7 @@ PQgetCopyData(PGconn *conn, char **buffer, int async) if (conn->asyncStatus != PGASYNC_COPY_OUT && conn->asyncStatus != PGASYNC_COPY_BOTH) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); + libpq_append_error(conn, "no COPY in progress"); return -2; } return pqGetCopyData3(conn, buffer, async); @@ -2905,17 +2885,14 @@ PQfn(PGconn *conn, if (conn->pipelineStatus != PQ_PIPELINE_OFF) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("%s not allowed in pipeline mode\n"), - "PQfn"); + libpq_append_error(conn, "%s not allowed in pipeline mode", "PQfn"); return NULL; } if (conn->sock == PGINVALID_SOCKET || conn->asyncStatus != PGASYNC_IDLE || pgHavePendingResult(conn)) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("connection in wrong state\n")); + libpq_append_error(conn, "connection in wrong state"); return NULL; } @@ -2958,8 +2935,7 @@ PQenterPipelineMode(PGconn *conn) if (conn->asyncStatus != PGASYNC_IDLE) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("cannot enter pipeline mode, connection not idle\n")); + libpq_append_error(conn, "cannot enter pipeline mode, connection not idle"); return 0; } @@ -2995,13 +2971,11 @@ PQexitPipelineMode(PGconn *conn) case PGASYNC_READY: case PGASYNC_READY_MORE: /* there are some uncollected results */ - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("cannot exit pipeline mode with uncollected results\n")); + libpq_append_error(conn, "cannot exit pipeline mode with uncollected results"); return 0; case PGASYNC_BUSY: - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("cannot exit pipeline mode while busy\n")); + libpq_append_error(conn, "cannot exit pipeline mode while busy"); return 0; case PGASYNC_IDLE: @@ -3012,15 +2986,13 @@ PQexitPipelineMode(PGconn *conn) case PGASYNC_COPY_IN: case PGASYNC_COPY_OUT: case PGASYNC_COPY_BOTH: - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("cannot exit pipeline mode while in COPY\n")); + libpq_append_error(conn, "cannot exit pipeline mode while in COPY"); } /* still work to process */ if (conn->cmd_queue_head != NULL) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("cannot exit pipeline mode with uncollected results\n")); + libpq_append_error(conn, "cannot exit pipeline mode with uncollected results"); return 0; } @@ -3135,8 +3107,7 @@ pqPipelineProcessQueue(PGconn *conn) conn->result = PQmakeEmptyPGresult(conn, PGRES_PIPELINE_ABORTED); if (!conn->result) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("out of memory\n")); + libpq_append_error(conn, "out of memory"); pqSaveErrorResult(conn); return; } @@ -3179,8 +3150,7 @@ PQpipelineSync(PGconn *conn) if (conn->pipelineStatus == PQ_PIPELINE_OFF) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("cannot send pipeline when not in pipeline mode\n")); + libpq_append_error(conn, "cannot send pipeline when not in pipeline mode"); return 0; } @@ -3246,8 +3216,7 @@ PQsendFlushRequest(PGconn *conn) /* Don't try to send if we know there's no live connection. */ if (conn->status != CONNECTION_OK) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("no connection to the server\n")); + libpq_append_error(conn, "no connection to the server"); return 0; } @@ -3255,8 +3224,7 @@ PQsendFlushRequest(PGconn *conn) if (conn->asyncStatus != PGASYNC_IDLE && conn->pipelineStatus == PQ_PIPELINE_OFF) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("another command is already in progress\n")); + libpq_append_error(conn, "another command is already in progress"); return 0; } @@ -3992,8 +3960,7 @@ PQescapeStringInternal(PGconn *conn, if (error) *error = 1; if (conn) - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("incomplete multibyte character\n")); + libpq_append_error(conn, "incomplete multibyte character"); for (; i < len; i++) { if (((size_t) (target - to)) / 2 >= length) @@ -4083,8 +4050,7 @@ 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) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("incomplete multibyte character\n")); + libpq_append_error(conn, "incomplete multibyte character"); return NULL; } @@ -4101,8 +4067,7 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident) result = rp = (char *) malloc(result_size); if (rp == NULL) { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("out of memory\n")); + libpq_append_error(conn, "out of memory"); return NULL; } @@ -4266,8 +4231,7 @@ PQescapeByteaInternal(PGconn *conn, if (rp == NULL) { if (conn) - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("out of memory\n")); + libpq_append_error(conn, "out of memory"); return NULL; } diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index 795500c59354..d505ed67cc1d 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -1278,3 +1278,18 @@ libpq_ngettext(const char *msgid, const char *msgid_plural, unsigned long n) } #endif /* ENABLE_NLS */ + +void +libpq_append_error(PGconn *conn, const char *fmt, ...) +{ + va_list args; + + Assert(fmt[strlen(fmt) - 1] != '\n'); + + va_start(args, fmt); + + appendPQExpBufferVA(&conn->errorMessage, libpq_gettext(fmt), args); + appendPQExpBufferChar(&conn->errorMessage, '\n'); + + va_end(args); +} diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index c75ed63a2c62..eeef80ab2b71 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -887,6 +887,8 @@ extern char *libpq_ngettext(const char *msgid, const char *msgid_plural, unsigne */ #undef _ +extern void libpq_append_error(PGconn *conn, const char *fmt, ...) pg_attribute_printf(2, 3); + /* * These macros are needed to let error-handling code be portable between * Unix and Windows. (ugh) diff --git a/src/interfaces/libpq/nls.mk b/src/interfaces/libpq/nls.mk index 9256b426c1d4..9d994ac1960a 100644 --- a/src/interfaces/libpq/nls.mk +++ b/src/interfaces/libpq/nls.mk @@ -1,5 +1,5 @@ # src/interfaces/libpq/nls.mk CATALOG_NAME = libpq GETTEXT_FILES = fe-auth.c fe-auth-scram.c fe-connect.c fe-exec.c fe-gssapi-common.c fe-lobj.c fe-misc.c fe-protocol3.c fe-secure.c fe-secure-common.c fe-secure-gssapi.c fe-secure-openssl.c win32.c ../../port/thread.c -GETTEXT_TRIGGERS = libpq_gettext pqInternalNotice:2 -GETTEXT_FLAGS = libpq_gettext:1:pass-c-format pqInternalNotice:2:c-format +GETTEXT_TRIGGERS = libpq_append_error:2 libpq_gettext pqInternalNotice:2 +GETTEXT_FLAGS = libpq_append_error:2 libpq_gettext:1:pass-c-format pqInternalNotice:2:c-format diff --git a/src/interfaces/libpq/pqexpbuffer.c b/src/interfaces/libpq/pqexpbuffer.c index eb51e6d08840..65621ec3b1c8 100644 --- a/src/interfaces/libpq/pqexpbuffer.c +++ b/src/interfaces/libpq/pqexpbuffer.c @@ -40,7 +40,7 @@ static const char oom_buffer[1] = ""; /* Need a char * for unconstify() compatibility */ static const char *oom_buffer_ptr = oom_buffer; -static bool appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args) pg_attribute_printf(2, 0); +static bool appendPQExpBufferVA_internal(PQExpBuffer str, const char *fmt, va_list args) pg_attribute_printf(2, 0); /* @@ -250,7 +250,7 @@ printfPQExpBuffer(PQExpBuffer str, const char *fmt,...) { errno = save_errno; va_start(args, fmt); - done = appendPQExpBufferVA(str, fmt, args); + done = appendPQExpBufferVA_internal(str, fmt, args); va_end(args); } while (!done); } @@ -278,13 +278,30 @@ appendPQExpBuffer(PQExpBuffer str, const char *fmt,...) { errno = save_errno; va_start(args, fmt); - done = appendPQExpBufferVA(str, fmt, args); + done = appendPQExpBufferVA_internal(str, fmt, args); va_end(args); } while (!done); } +void +appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args) +{ + int save_errno = errno; + bool done; + + if (PQExpBufferBroken(str)) + return; /* already failed */ + + /* Loop in case we have to retry after enlarging the buffer. */ + do + { + errno = save_errno; + done = appendPQExpBufferVA_internal(str, fmt, args); + } while (!done); +} + /* - * appendPQExpBufferVA + * appendPQExpBufferVA_internal * Shared guts of printfPQExpBuffer/appendPQExpBuffer. * Attempt to format data and append it to str. Returns true if done * (either successful or hard failure), false if need to retry. @@ -293,7 +310,7 @@ appendPQExpBuffer(PQExpBuffer str, const char *fmt,...) * when looping, in case the fmt contains "%m". */ static bool -appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args) +appendPQExpBufferVA_internal(PQExpBuffer str, const char *fmt, va_list args) { size_t avail; size_t needed; diff --git a/src/interfaces/libpq/pqexpbuffer.h b/src/interfaces/libpq/pqexpbuffer.h index efd652c80a33..b8216b8a7bd9 100644 --- a/src/interfaces/libpq/pqexpbuffer.h +++ b/src/interfaces/libpq/pqexpbuffer.h @@ -157,6 +157,8 @@ extern void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...) pg_attribute */ extern void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...) pg_attribute_printf(2, 3); +extern void appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args) pg_attribute_printf(2, 0); + /*------------------------ * appendPQExpBufferStr * Append the given string to a PQExpBuffer, allocating more space -- 2.37.3