From f32c4a3edbc49440305cc4edf775121147e6e259 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Mon, 8 Jan 2018 14:20:50 +1100
Subject: [PATCH 2/2] remote_server_info column addtion to pg_stat_wal_receiver

This column provides the remote server information of
the WAL receiver connection to the remote host.
---
 doc/src/sgml/monitoring.sgml                       |  9 ++++-
 src/backend/catalog/system_views.sql               |  1 +
 .../libpqwalreceiver/libpqwalreceiver.c            | 44 ++++++++++++++++++++++
 src/backend/replication/walreceiver.c              | 21 ++++++++++-
 src/include/catalog/pg_proc.h                      |  2 +-
 src/include/replication/walreceiver.h              | 10 +++++
 src/test/regress/expected/rules.out                |  3 +-
 7 files changed, 85 insertions(+), 5 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 8a9793644f..9a6aac45f5 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2022,11 +2022,18 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
      <entry><type>text</type></entry>
      <entry>Replication slot name used by this WAL receiver</entry>
     </row>
+    <row>
+     <entry><structfield>remote_server_info</structfield></entry>
+     <entry><type>text</type></entry>
+     <entry>
+      Effective remote server connection info string used by this WAL receiver.
+     </entry>
+    </row>
     <row>
      <entry><structfield>conninfo</structfield></entry>
      <entry><type>text</type></entry>
      <entry>
-      Connection string used by this WAL receiver,
+      Initial connection string used by this WAL receiver,
       with security-sensitive fields obfuscated.
      </entry>
     </row>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 5652e9ee6d..b0f74ed9bc 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -750,6 +750,7 @@ CREATE VIEW pg_stat_wal_receiver AS
             s.latest_end_lsn,
             s.latest_end_time,
             s.slot_name,
+            s.remote_server_info,
             s.conninfo
     FROM pg_stat_get_wal_receiver() s
     WHERE s.pid IS NOT NULL;
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index f9aec0531a..488c1c2dde 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -53,6 +53,7 @@ static WalReceiverConn *libpqrcv_connect(const char *conninfo,
 				 char **err);
 static void libpqrcv_check_conninfo(const char *conninfo);
 static char *libpqrcv_get_conninfo(WalReceiverConn *conn);
+static char *libpqrcv_get_remote_server_info(WalReceiverConn *conn);
 static char *libpqrcv_identify_system(WalReceiverConn *conn,
 						 TimeLineID *primary_tli,
 						 int *server_version);
@@ -82,6 +83,7 @@ static WalReceiverFunctionsType PQWalReceiverFunctions = {
 	libpqrcv_connect,
 	libpqrcv_check_conninfo,
 	libpqrcv_get_conninfo,
+	libpqrcv_get_remote_server_info,
 	libpqrcv_identify_system,
 	libpqrcv_readtimelinehistoryfile,
 	libpqrcv_startstreaming,
@@ -282,6 +284,47 @@ libpqrcv_get_conninfo(WalReceiverConn *conn)
 	return retval;
 }
 
+/*
+ * Return a user-displayable remote server information.
+ */
+static char *
+libpqrcv_get_remote_server_info(WalReceiverConn *conn)
+{
+	PQconninfoOption *conn_opts;
+	PQconninfoOption *conn_opt;
+	PQExpBufferData buf;
+	char	   *retval;
+
+	Assert(conn->streamConn != NULL);
+
+	initPQExpBuffer(&buf);
+	conn_opts = PQeffectiveConninfo(conn->streamConn);
+
+	if (conn_opts == NULL)
+		ereport(ERROR,
+				(errmsg("could not parse connection string: %s",
+						_("out of memory"))));
+
+	/* build a clean connection string from pieces */
+	for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
+	{
+		if ((strcmp(conn_opt->keyword, "host") == 0) ||
+			(strcmp(conn_opt->keyword, "hostaddr") == 0) ||
+			(strcmp(conn_opt->keyword, "port") == 0))
+		{
+			appendPQExpBuffer(&buf, "%s%s=%s",
+							  buf.len == 0 ? "" : " ",
+							  conn_opt->keyword, conn_opt->val);
+		}
+	}
+
+	PQconninfoFree(conn_opts);
+
+	retval = PQExpBufferDataBroken(buf) ? NULL : pstrdup(buf.data);
+	termPQExpBuffer(&buf);
+	return retval;
+}
+
 /*
  * Check that primary's system identifier matches ours, and fetch the current
  * timeline ID of the primary.
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index a39a98ff18..b93b843b2d 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -189,6 +190,7 @@ WalReceiverMain(void)
 {
 	char		conninfo[MAXCONNINFO];
 	char	   *tmp_conninfo;
+	char	   *tmp_remote_server_info;
 	char		slotname[NAMEDATALEN];
 	XLogRecPtr	startpoint;
 	TimeLineID	startpointTLI;
@@ -311,16 +313,25 @@ WalReceiverMain(void)
 	 * conninfo, for security.
 	 */
 	tmp_conninfo = walrcv_get_conninfo(wrconn);
+	tmp_remote_server_info = walrcv_get_remote_server_info(wrconn);
 	SpinLockAcquire(&walrcv->mutex);
 	memset(walrcv->conninfo, 0, MAXCONNINFO);
 	if (tmp_conninfo)
 		strlcpy((char *) walrcv->conninfo, tmp_conninfo, MAXCONNINFO);
+
+	memset(walrcv->remote_server_info, 0, MAXCONNINFO);
+	if (tmp_remote_server_info)
+		strlcpy((char *) walrcv->remote_server_info, tmp_remote_server_info, MAXCONNINFO);
+
 	walrcv->ready_to_display = true;
 	SpinLockRelease(&walrcv->mutex);
 
 	if (tmp_conninfo)
 		pfree(tmp_conninfo);
 
+	if (tmp_remote_server_info)
+		pfree(tmp_remote_server_info);
+
 	first_stream = true;
 	for (;;)
 	{
@@ -1404,6 +1415,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	TimestampTz latest_end_time;
 	char		slotname[NAMEDATALEN];
 	char		conninfo[MAXCONNINFO];
+	char		remote_server_info[MAXCONNINFO];
 
 	/* Take a lock to ensure value consistency */
 	SpinLockAcquire(&WalRcv->mutex);
@@ -1419,6 +1431,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	latest_end_lsn = WalRcv->latestWalEnd;
 	latest_end_time = WalRcv->latestWalEndTime;
 	strlcpy(slotname, (char *) WalRcv->slotname, sizeof(slotname));
+	strlcpy(remote_server_info, (char *) WalRcv->remote_server_info, sizeof(remote_server_info));
 	strlcpy(conninfo, (char *) WalRcv->conninfo, sizeof(conninfo));
 	SpinLockRelease(&WalRcv->mutex);
 
@@ -1482,10 +1495,14 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 			nulls[10] = true;
 		else
 			values[10] = CStringGetTextDatum(slotname);
-		if (*conninfo == '\0')
+		if (*remote_server_info == '\0')
 			nulls[11] = true;
 		else
-			values[11] = CStringGetTextDatum(conninfo);
+			values[11] = CStringGetTextDatum(remote_server_info);
+		if (*conninfo == '\0')
+			nulls[12] = true;
+		else
+			values[12] = CStringGetTextDatum(conninfo);
 	}
 
 	/* Returns the record as Datum */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 298e0ae2f0..f043d88797 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2883,7 +2883,7 @@ DATA(insert OID = 3318 (  pg_stat_get_progress_info			  PGNSP PGUID 12 1 100 0 0
 DESCR("statistics: information about progress of backends running maintenance command");
 DATA(insert OID = 3099 (  pg_stat_get_wal_senders	PGNSP PGUID 12 1 10 0 0 f f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,1186,1186,1186,23,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{pid,state,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active replication");
-DATA(insert OID = 3317 (  pg_stat_get_wal_receiver	PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
+DATA(insert OID = 3317 (  pg_stat_get_wal_receiver	PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,remote_server_info,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
 DESCR("statistics: information about WAL receiver");
 DATA(insert OID = 6118 (  pg_stat_get_subscription	PGNSP PGUID 12 1 0 0 0 f f f f f f s r 1 0 2249 "26" "{26,26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o,o}" "{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}" _null_ _null_ pg_stat_get_subscription _null_ _null_ _null_ ));
 DESCR("statistics: information about subscription");
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index ea7967f6fc..2f0f33ad03 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -108,6 +108,12 @@ typedef struct
 	 */
 	char		conninfo[MAXCONNINFO];
 
+	/*
+	 * connection string; effectively used to connect to the primary, and later
+	 * clobbered to hide security-sensitive fields.
+	 */
+	char		remote_server_info[MAXCONNINFO];
+
 	/*
 	 * replication slot name; is also used for walreceiver to connect with the
 	 * primary
@@ -197,6 +203,7 @@ typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, bool logica
 											   char **err);
 typedef void (*walrcv_check_conninfo_fn) (const char *conninfo);
 typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn);
+typedef char *(*walrcv_get_remote_server_info_fn) (WalReceiverConn *conn);
 typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn,
 											TimeLineID *primary_tli,
 											int *server_version);
@@ -227,6 +234,7 @@ typedef struct WalReceiverFunctionsType
 	walrcv_connect_fn walrcv_connect;
 	walrcv_check_conninfo_fn walrcv_check_conninfo;
 	walrcv_get_conninfo_fn walrcv_get_conninfo;
+	walrcv_get_remote_server_info_fn walrcv_get_remote_server_info;
 	walrcv_identify_system_fn walrcv_identify_system;
 	walrcv_readtimelinehistoryfile_fn walrcv_readtimelinehistoryfile;
 	walrcv_startstreaming_fn walrcv_startstreaming;
@@ -246,6 +254,8 @@ extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions;
 	WalReceiverFunctions->walrcv_check_conninfo(conninfo)
 #define walrcv_get_conninfo(conn) \
 	WalReceiverFunctions->walrcv_get_conninfo(conn)
+#define walrcv_get_remote_server_info(conn) \
+	WalReceiverFunctions->walrcv_get_remote_server_info(conn)
 #define walrcv_identify_system(conn, primary_tli, server_version) \
 	WalReceiverFunctions->walrcv_identify_system(conn, primary_tli, server_version)
 #define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index f1c1b44d6f..5d757c141e 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1970,8 +1970,9 @@ pg_stat_wal_receiver| SELECT s.pid,
     s.latest_end_lsn,
     s.latest_end_time,
     s.slot_name,
+    s.remote_server_info,
     s.conninfo
-   FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, conninfo)
+   FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, remote_server_info, conninfo)
   WHERE (s.pid IS NOT NULL);
 pg_stat_xact_all_tables| SELECT c.oid AS relid,
     n.nspname AS schemaname,
-- 
2.15.0.windows.1

