From 71cff5bd404c0f9fcc017b5d3ca2cc247412d904 Mon Sep 17 00:00:00 2001
From: Hunaid Sohail <hunaid2000@gmail.com>
Date: Mon, 16 Sep 2024 11:46:46 +0500
Subject: [PATCH v34] Add psql meta command conninfo+

---
 doc/src/sgml/ref/psql-ref.sgml |  34 +++++++-
 src/bin/psql/command.c         | 155 +++++++++++++++++++++++++++++----
 src/bin/psql/help.c            |   2 +-
 3 files changed, 167 insertions(+), 24 deletions(-)

diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 3fd9959ed1..6b2d8ca788 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1060,11 +1060,37 @@ INSERT INTO tbls1 VALUES ($1, $2) \parse stmt1
       </varlistentry>
 
       <varlistentry id="app-psql-meta-command-conninfo">
-        <term><literal>\conninfo</literal></term>
+        <term><literal>\conninfo[+]</literal></term>
         <listitem>
-        <para>
-        Outputs information about the current database connection.
-        </para>
+          <para>
+            Outputs information about the current database connection.
+            When <literal>+</literal> is appended, all details
+            about the connection are displayed in table format.
+            The table output is dynamic and changes based on the
+            connection state. If the connection is not using SSL,
+            SSL-related information (SSL Protocol, Cipher, Compression,
+            and ALPN) will not be displayed.
+            <simplelist>
+              <member><literal>Session User:</literal> The session user's name;
+                see the <function>session_user()</function> function in
+                <xref linkend="functions-info-session-table"/> for more details.</member>
+              <member><literal>Protocol Version:</literal> The version of the PostgreSQL protocol used for
+                this connection.</member>
+              <member><literal>SSL Connection:</literal> True if the current connection to the server
+                uses SSL, and false otherwise.</member>
+              <member><literal>SSL Protocol:</literal> The SSL/TLS protocol version used for this connection.</member>
+              <member><literal>Cipher:</literal> The SSL/TLS cipher suite used for this connection.</member>
+              <member><literal>Compression:</literal> True if compression is in use on this connection, or false if
+                compression is not in use on this connection.</member>
+              <member><literal>ALPN:</literal> The Application-Layer Protocol Negotiation (ALPN) protocol
+                used for this connection.</member>
+              <member><literal>GSSAPI Authenticated:</literal> True if GSSAPI is in use, or false if
+                GSSAPI is not in use on this connection.</member>
+              <member><literal>Client Encoding:</literal> The encoding used by the client for this connection.</member>
+              <member><literal>Server Encoding:</literal> The encoding used by the server for this connection.</member>
+              <member><literal>Backend PID:</literal> The process ID of the backend for the connection.</member>
+            </simplelist>
+          </para>
         </listitem>
       </varlistentry>
 
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 4dfc7b2d85..3c17a240b0 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -72,7 +72,8 @@ static backslashResult exec_command_cd(PsqlScanState scan_state, bool active_bra
 									   const char *cmd);
 static backslashResult exec_command_close(PsqlScanState scan_state, bool active_branch,
 										  const char *cmd);
-static backslashResult exec_command_conninfo(PsqlScanState scan_state, bool active_branch);
+static backslashResult exec_command_conninfo(PsqlScanState scan_state, bool active_branch,
+											 const char *cmd);
 static backslashResult exec_command_copy(PsqlScanState scan_state, bool active_branch);
 static backslashResult exec_command_copyright(PsqlScanState scan_state, bool active_branch);
 static backslashResult exec_command_crosstabview(PsqlScanState scan_state, bool active_branch);
@@ -328,8 +329,8 @@ exec_command(const char *cmd,
 		status = exec_command_cd(scan_state, active_branch, cmd);
 	else if (strcmp(cmd, "close") == 0)
 		status = exec_command_close(scan_state, active_branch, cmd);
-	else if (strcmp(cmd, "conninfo") == 0)
-		status = exec_command_conninfo(scan_state, active_branch);
+	else if (strcmp(cmd, "conninfo") == 0 || strcmp(cmd, "conninfo+") == 0)
+		status = exec_command_conninfo(scan_state, active_branch, cmd);
 	else if (pg_strcasecmp(cmd, "copy") == 0)
 		status = exec_command_copy(scan_state, active_branch);
 	else if (strcmp(cmd, "copyright") == 0)
@@ -739,11 +740,14 @@ exec_command_close(PsqlScanState scan_state, bool active_branch, const char *cmd
 }
 
 /*
- * \conninfo -- display information about the current connection
+ * \conninfo, \conninfo+ -- display information about the current connection
  */
 static backslashResult
-exec_command_conninfo(PsqlScanState scan_state, bool active_branch)
+exec_command_conninfo(PsqlScanState scan_state, bool active_branch, const char *cmd)
 {
+	bool show_verbose;
+	show_verbose = strchr(cmd, '+') ? true : false;
+
 	if (active_branch)
 	{
 		char	   *db = PQdb(pset.db);
@@ -755,27 +759,140 @@ exec_command_conninfo(PsqlScanState scan_state, bool active_branch)
 			char	   *host = PQhost(pset.db);
 			char	   *hostaddr = PQhostaddr(pset.db);
 
-			if (is_unixsock_path(host))
+			if (!show_verbose)
 			{
-				/* hostaddr overrides host */
-				if (hostaddr && *hostaddr)
-					printf(_("You are connected to database \"%s\" as user \"%s\" on address \"%s\" at port \"%s\".\n"),
-						   db, PQuser(pset.db), hostaddr, PQport(pset.db));
+				if (is_unixsock_path(host))
+				{
+					/* hostaddr overrides host */
+					if (hostaddr && *hostaddr)
+						printf(_("You are connected to database \"%s\" as user \"%s\" on address \"%s\" at port \"%s\".\n"),
+							db, PQuser(pset.db), hostaddr, PQport(pset.db));
+					else
+						printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
+							db, PQuser(pset.db), host, PQport(pset.db));
+				}
 				else
-					printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
-						   db, PQuser(pset.db), host, PQport(pset.db));
+				{
+					if (hostaddr && *hostaddr && strcmp(host, hostaddr) != 0)
+						printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" (address \"%s\") at port \"%s\".\n"),
+							db, PQuser(pset.db), host, hostaddr, PQport(pset.db));
+					else
+						printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
+							db, PQuser(pset.db), host, PQport(pset.db));
+				}
+				printSSLInfo();
+				printGSSInfo();
 			}
+			/* Print some additional information about the connection */
 			else
 			{
-				if (hostaddr && *hostaddr && strcmp(host, hostaddr) != 0)
-					printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" (address \"%s\") at port \"%s\".\n"),
-						   db, PQuser(pset.db), host, hostaddr, PQport(pset.db));
+				printQueryOpt popt = pset.popt;
+				printTableContent cont;
+				char	protocol_version[10];
+				char	backend_pid[10];
+				int		cols,
+						rows;
+				int		ssl_in_use,
+						gssapi_used;
+				char	*session_user,
+						*client_encoding,
+						*server_encoding;
+				char	*protocol,
+						*cipher,
+						*compression,
+						*alpn;
+				char	*headers[18];
+
+				/* Get values for the parameters */
+				sprintf(protocol_version, "%d", PQprotocolVersion(pset.db));
+				ssl_in_use = PQsslInUse(pset.db);
+				if (ssl_in_use)
+				{
+					protocol = (char *) PQsslAttribute(pset.db, "protocol");
+					cipher = (char *) PQsslAttribute(pset.db, "cipher");
+					compression = (char *) PQsslAttribute(pset.db, "compression");
+					alpn = (char *) PQsslAttribute(pset.db, "alpn");
+				}
+				gssapi_used = PQconnectionUsedGSSAPI(pset.db);
+				session_user = (char *) PQparameterStatus(pset.db, "session_authorization");
+				client_encoding = (char *) PQparameterStatus(pset.db, "client_encoding");
+				server_encoding = (char *) PQparameterStatus(pset.db, "server_encoding");
+				sprintf(backend_pid, "%d", PQbackendPID(pset.db));
+
+				/* Fill headers[] with the names of the columns we will output */
+				cols = 0;
+				headers[cols++] = gettext_noop("Database");
+				headers[cols++] = gettext_noop("Current User");
+				headers[cols++] = gettext_noop("Session User");
+				if (is_unixsock_path(host))
+				{
+					if (hostaddr && *hostaddr)
+						headers[cols++] = gettext_noop("Host Address");
+					else
+						headers[cols++] = gettext_noop("Socket Directory");
+				}
 				else
-					printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
-						   db, PQuser(pset.db), host, PQport(pset.db));
+				{
+					headers[cols++] = gettext_noop("Host");
+					if (hostaddr && *hostaddr && strcmp(host, hostaddr) != 0)
+						headers[cols++] = gettext_noop("Host Address");
+				}
+				headers[cols++] = gettext_noop("Port");
+				headers[cols++] = gettext_noop("Protocol Version");
+				headers[cols++] = gettext_noop("SSL Connection");
+				if (ssl_in_use)
+				{
+					headers[cols++] = gettext_noop("SSL Protocol");
+					headers[cols++] = gettext_noop("Cipher");
+					headers[cols++] = gettext_noop("Compression");
+					headers[cols++] = gettext_noop("ALPN");
+				}
+				headers[cols++] = gettext_noop("GSSAPI Authenticated");
+				headers[cols++] = gettext_noop("Client Encoding");
+				headers[cols++] = gettext_noop("Server Encoding");
+				headers[cols++] = gettext_noop("Backend PID");
+				rows = 1;
+
+				/* Print the information in a table */
+				printTableInit(&cont, &popt.topt, _("Connection Information"), cols, rows);
+
+				for (int i = 0; i < cols; i++)
+					printTableAddHeader(&cont, headers[i], true, 'l');
+
+				printTableAddCell(&cont, db, false, false);
+				printTableAddCell(&cont, PQuser(pset.db), false, false);
+				printTableAddCell(&cont, session_user ? session_user : _("(none)"), false, false);
+				if (is_unixsock_path(host))
+				{
+					if (hostaddr && *hostaddr)
+						printTableAddCell(&cont, hostaddr, false, false);
+					else
+						printTableAddCell(&cont, host, false, false);
+				}
+				else
+				{
+					printTableAddCell(&cont, host, false, false);
+					if (hostaddr && *hostaddr && strcmp(host, hostaddr) != 0)
+						printTableAddCell(&cont, hostaddr, false, false);
+				}
+				printTableAddCell(&cont, PQport(pset.db), false, false);
+				printTableAddCell(&cont, protocol_version, false, false);
+				printTableAddCell(&cont, ssl_in_use ? _("yes") : _("no"), false, false);
+				if (ssl_in_use)
+				{
+					printTableAddCell(&cont, protocol ? protocol : _("unknown"), false, false);
+					printTableAddCell(&cont, cipher ? cipher : _("unknown"), false, false);
+					printTableAddCell(&cont, (compression && strcmp(compression, "off") != 0) ? _("on") : _("off"), false, false);
+					printTableAddCell(&cont, (alpn && alpn[0] != '\0') ? alpn : _("none"), false, false);
+				}
+				printTableAddCell(&cont, gssapi_used ? _("yes") : _("no"), false, false);
+				printTableAddCell(&cont, client_encoding ? client_encoding : _("(none)"), false, false);
+				printTableAddCell(&cont, server_encoding ? server_encoding : _("(none)"), false, false);
+				printTableAddCell(&cont, backend_pid, false, false);
+
+				printTable(&cont, pset.queryFout, false, pset.logfile);
+				printTableCleanup(&cont);
 			}
-			printSSLInfo();
-			printGSSInfo();
 		}
 	}
 
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 19d20c5878..ce6d6ae184 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -313,7 +313,7 @@ slashUsage(unsigned short int pager)
 	else
 		HELP0("  \\c[onnect] {[DBNAME|- USER|- HOST|- PORT|-] | conninfo}\n"
 			  "                         connect to new database (currently no connection)\n");
-	HELP0("  \\conninfo              display information about current connection\n");
+	HELP0("  \\conninfo[+]           display information about current connection\n");
 	HELP0("  \\encoding [ENCODING]   show or set client encoding\n");
 	HELP0("  \\parse STMT_NAME       create a prepared statement\n");
 	HELP0("  \\password [USERNAME]   securely change the password for a user\n");
-- 
2.34.1

