From a0ae54df9b153256a9d0afe45732853cb5ccae09 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Mon, 5 Dec 2016 14:09:54 -0500 Subject: [PATCH] libpq: Fix another bug in 721f7bd3cbccaf8c07cad2707826b83f84694832. If we failed to connect to one or more hosts, and then afterwards we find one that fails to be read-write, the latter error message was clobbering any earlier ones. Repair. Mithun Cy, slightly revised by me. --- src/interfaces/libpq/fe-connect.c | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 3b9b263a39..101cce8673 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -1762,6 +1762,39 @@ connectDBComplete(PGconn *conn) } } +/* + * This subroutine saves conn->errorMessage, which will be restored back by + * restoreErrorMessage subroutine. + */ +static bool +saveErrorMessage(PGconn *conn, PQExpBuffer savedMessage) +{ + initPQExpBuffer(savedMessage); + if (PQExpBufferBroken(savedMessage)) + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("out of memory\n")); + return false; + } + + appendPQExpBufferStr(savedMessage, + conn->errorMessage.data); + resetPQExpBuffer(&conn->errorMessage); + return true; +} + +/* + * Restores saved error messages back to conn->errorMessage. + */ +static void +restoreErrorMessage(PGconn *conn, PQExpBuffer savedMessage) +{ + appendPQExpBufferStr(savedMessage, conn->errorMessage.data); + resetPQExpBuffer(&conn->errorMessage); + appendPQExpBufferStr(&conn->errorMessage, savedMessage->data); + termPQExpBuffer(savedMessage); +} + /* ---------------- * PQconnectPoll * @@ -1795,6 +1828,7 @@ PQconnectPoll(PGconn *conn) PGresult *res; char sebuf[256]; int optval; + PQExpBufferData savedMessage; if (conn == NULL) return PGRES_POLLING_FAILED; @@ -2792,11 +2826,26 @@ keep_going: /* We will come back to here until there is if (conn->target_session_attrs != NULL && strcmp(conn->target_session_attrs, "read-write") == 0) { + /* + * We are yet to make a connection. Save all existing error + * messages until we make a successful connection state. + * This is important because PQsendQuery is going to reset + * conn->errorMessage and we will loose error messages + * related to previous hosts we have tried to connect and + * failed. + */ + if (!saveErrorMessage(conn, &savedMessage)) + goto error_return; + conn->status = CONNECTION_OK; if (!PQsendQuery(conn, "show transaction_read_only")) + { + restoreErrorMessage(conn, &savedMessage); goto error_return; + } conn->status = CONNECTION_CHECK_WRITABLE; + restoreErrorMessage(conn, &savedMessage); return PGRES_POLLING_READING; } @@ -2841,11 +2890,18 @@ keep_going: /* We will come back to here until there is if (conn->target_session_attrs != NULL && strcmp(conn->target_session_attrs, "read-write") == 0) { + if (!saveErrorMessage(conn, &savedMessage)) + goto error_return; + conn->status = CONNECTION_OK; if (!PQsendQuery(conn, "show transaction_read_only")) + { + restoreErrorMessage(conn, &savedMessage); goto error_return; + } conn->status = CONNECTION_CHECK_WRITABLE; + restoreErrorMessage(conn, &savedMessage); return PGRES_POLLING_READING; } @@ -2858,13 +2914,20 @@ keep_going: /* We will come back to here until there is case CONNECTION_CHECK_WRITABLE: { + 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; } @@ -2878,6 +2941,7 @@ keep_going: /* We will come back to here until there is if (strncmp(val, "on", 2) == 0) { PQclear(res); + restoreErrorMessage(conn, &savedMessage); /* Not writable; close connection. */ appendPQExpBuffer(&conn->errorMessage, @@ -2902,6 +2966,7 @@ keep_going: /* We will come back to here until there is goto error_return; } PQclear(res); + termPQExpBuffer(&savedMessage); /* We can release the address lists now. */ release_all_addrinfo(conn); @@ -2917,6 +2982,7 @@ keep_going: /* We will come back to here until there is */ if (res) PQclear(res); + restoreErrorMessage(conn, &savedMessage); appendPQExpBuffer(&conn->errorMessage, libpq_gettext("test \"show transaction_read_only\" failed " " on \"%s:%s\" \n"), -- 2.40.0