From b0b2ef25e3ff240dc1887742bfed1d044c0938a0 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 2 Sep 2019 14:02:46 -0400 Subject: [PATCH] Handle corner cases correctly in psql's reconnection logic. 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 | 12 ++++++++++-- src/bin/psql/common.c | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 4aaf657cce8..40eba61b37c 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -1970,8 +1970,14 @@ do_connect(enum trivalue reuse_previous_specification, psql_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(); } } @@ -1985,7 +1991,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; @@ -2060,7 +2067,8 @@ connection_warnings(bool in_startup) sverbuf, sizeof(sverbuf))); #ifdef WIN32 - checkWin32Codepage(); + if (in_startup) + checkWin32Codepage(); #endif printSSLInfo(); } diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index a5e42973de8..5eea2272922 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -378,13 +378,27 @@ CheckConnection(void) if (!OK) { psql_error("Failed.\n"); + + /* + * Transition to having no connection. Keep this bit in sync with + * do_connect(). + */ PQfinish(pset.db); pset.db = NULL; ResetCancelConn(); UnsyncVariables(); } else + { psql_error("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;