]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
libpq: Fix another bug in 721f7bd3cbccaf8c07cad2707826b83f84694832.
authorRobert Haas <rhaas@postgresql.org>
Mon, 5 Dec 2016 19:09:54 +0000 (14:09 -0500)
committerRobert Haas <rhaas@postgresql.org>
Mon, 5 Dec 2016 19:11:52 +0000 (14:11 -0500)
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

index 3b9b263a394f8d29f6b09aadd5c930847c6bf6a4..101cce8673fc46efbba2c5817f0324cc26d56b54 100644 (file)
@@ -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"),