]> granicus.if.org Git - postgresql/commitdiff
Handle corner cases correctly in psql's reconnection logic.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 2 Sep 2019 18:02:45 +0000 (14:02 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 2 Sep 2019 18:03:05 +0000 (14:03 -0400)
After an unexpected connection loss and successful reconnection,
psql neglected to resynchronize its internal state about the server,
such as server version.  Ordinarily we'd be reconnecting to the same
server and so this isn't really necessary, but there are scenarios
where we do need to update --- one example is where we have a list
of possible connection targets and they're not all alike.

Define "resynchronize" as including connection_warnings(), so that
this case acts the same as \connect.  This seems useful; for example,
if the server version did change, the user might wish to know that.
An attuned user might also notice that the new connection isn't
SSL-encrypted, for example, though this approach isn't especially
in-your-face about such changes.  Although this part is a behavioral
change, it only affects interactive sessions, so it should not break
any applications.

Also, in do_connect, make sure that we desynchronize correctly when
abandoning an old connection in non-interactive mode.

These problems evidently are the result of people patching only one
of the two places where psql deals with connection changes, so insert
some cross-referencing comments in hopes of forestalling future bugs
of the same ilk.

Lastly, in Windows builds, issue codepage mismatch warnings only at
startup, not during reconnections.  psql's codepage can't change
during a reconnect, so complaining about it again seems like useless
noise.

Peter Billen and Tom Lane.  Back-patch to all supported branches.

Discussion: https://postgr.es/m/CAMTXbE8e6U=EBQfNSe01Ej17CBStGiudMAGSOPaw-ALxM-5jXg@mail.gmail.com

src/bin/psql/command.c
src/bin/psql/common.c

index c0a7a5566eb2a3c81a543c727591c2822f871fb5..93953fc8e7d961715d366e7db31364de53697a55 100644 (file)
@@ -3120,8 +3120,14 @@ do_connect(enum trivalue reuse_previous_specification,
                        pg_log_error("\\connect: %s", PQerrorMessage(n_conn));
                        if (o_conn)
                        {
+                               /*
+                                * Transition to having no connection.  Keep this bit in sync
+                                * with CheckConnection().
+                                */
                                PQfinish(o_conn);
                                pset.db = NULL;
+                               ResetCancelConn();
+                               UnsyncVariables();
                        }
                }
 
@@ -3135,7 +3141,8 @@ do_connect(enum trivalue reuse_previous_specification,
 
        /*
         * Replace the old connection with the new one, and update
-        * connection-dependent variables.
+        * connection-dependent variables.  Keep the resynchronization logic in
+        * sync with CheckConnection().
         */
        PQsetNoticeProcessor(n_conn, NoticeProcessor, NULL);
        pset.db = n_conn;
@@ -3226,7 +3233,8 @@ connection_warnings(bool in_startup)
                                                                                 sverbuf, sizeof(sverbuf)));
 
 #ifdef WIN32
-               checkWin32Codepage();
+               if (in_startup)
+                       checkWin32Codepage();
 #endif
                printSSLInfo();
                printGSSInfo();
index 44a782478d1970c9a5136b06642d1a1e9e306363..4b2679360fc2ebbaae4d82efeae09c9962fd7ae7 100644 (file)
@@ -402,13 +402,27 @@ CheckConnection(void)
                if (!OK)
                {
                        fprintf(stderr, _("Failed.\n"));
+
+                       /*
+                        * Transition to having no connection.  Keep this bit in sync with
+                        * do_connect().
+                        */
                        PQfinish(pset.db);
                        pset.db = NULL;
                        ResetCancelConn();
                        UnsyncVariables();
                }
                else
+               {
                        fprintf(stderr, _("Succeeded.\n"));
+
+                       /*
+                        * Re-sync, just in case anything changed.  Keep this in sync with
+                        * do_connect().
+                        */
+                       SyncVariables();
+                       connection_warnings(false); /* Must be after SyncVariables */
+               }
        }
 
        return OK;