From 5982b0f3d704a2b9a857636b53653b6026b1e01a Mon Sep 17 00:00:00 2001
From: Dave Cramer <davecramer@gmail.com>
Date: Thu, 11 Jul 2019 08:20:14 -0400
Subject: [PATCH] add special startup parameter _pq_.guc_report to add
 GUC_REPORT dynamically per session

---
 src/backend/postmaster/postmaster.c | 21 +++++++++++++++++++++
 src/backend/utils/init/postinit.c   | 14 ++++++++++++++
 src/backend/utils/misc/guc.c        | 20 ++++++++++++++++++++
 src/include/libpq/libpq-be.h        |  1 +
 src/include/utils/guc.h             |  1 +
 5 files changed, 57 insertions(+)

diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 3339804be9..c7c41c4ca8 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -2080,6 +2080,7 @@ retry1:
 		 * zeroing extra byte above.
 		 */
 		port->guc_options = NIL;
+		port->guc_report = NIL;
 
 		while (offset < len)
 		{
@@ -2124,6 +2125,25 @@ retry1:
 			}
 			else if (strncmp(nameptr, "_pq_.", 5) == 0)
 			{
+				if (strncasecmp(nameptr+5, "guc_report", 10) == 0)
+				{
+					char sep[3] = " ,";
+
+					/* avoid scribbling on valptr */
+					char *temp_val = pstrdup(valptr);
+
+					/* strtok is going to scribble on temp_val */
+					char *freeptr = temp_val;
+					char *guc_report = strtok(temp_val,sep);
+					while(guc_report)
+					{
+						port->guc_report = lappend(port->guc_report,pstrdup(guc_report));
+						guc_report = strtok(NULL, sep);
+					}
+					pfree(freeptr);
+				}
+				else
+				{
 				/*
 				 * Any option beginning with _pq_. is reserved for use as a
 				 * protocol-level option, but at present no such options are
@@ -2131,6 +2151,7 @@ retry1:
 				 */
 				unrecognized_protocol_options =
 					lappend(unrecognized_protocol_options, pstrdup(nameptr));
+				}
 			}
 			else
 			{
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index e9f72b5069..f102e82c06 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -1092,6 +1092,9 @@ process_startup_options(Port *port, bool am_superuser)
 {
 	GucContext	gucctx;
 	ListCell   *gucopts;
+	ListCell   *gucreport;
+	List 	   *gucReports;
+
 
 	gucctx = am_superuser ? PGC_SU_BACKEND : PGC_BACKEND;
 
@@ -1126,6 +1129,17 @@ process_startup_options(Port *port, bool am_superuser)
 		(void) process_postgres_switches(ac, av, gucctx, NULL);
 	}
 
+	/*
+	 * Loop through the user requested GUC_REPORT and set them
+	 *  */
+	gucReports = port->guc_report;
+	foreach(gucreport,gucReports)
+	{
+		char *name;
+		name = lfirst(gucreport);
+		SetConfigReport(name, true);
+	}
+
 	/*
 	 * Process any additional GUC variable settings passed in startup packet.
 	 * These are handled exactly like command-line variables.
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index fc463601ff..5c1de33c34 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -7643,7 +7643,27 @@ GetConfigOptionFlags(const char *name, bool missing_ok)
 	return record->flags;
 }
 
+/*
+ * Set the option to be GUC_REPORT
+ */
+
+bool SetConfigReport(const char *name, bool missing_ok)
+{
+	struct config_generic *record;
 
+	record = find_option(name, false, WARNING);
+	if (record == NULL)
+	{
+		if (missing_ok)
+			return 0;
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_OBJECT),
+				 errmsg("unrecognized configuration parameter \"%s\"",
+						name)));
+	}
+	record->flags |= GUC_REPORT;
+	return 0;
+}
 /*
  * flatten_set_variable_args
  *		Given a parsenode List as emitted by the grammar for SET,
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 541f970f99..0350b70f02 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -141,6 +141,7 @@ typedef struct Port
 	char	   *user_name;
 	char	   *cmdline_options;
 	List	   *guc_options;
+	List	   *guc_report;
 
 	/*
 	 * The startup packet application name, only used here for the "connection
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index e709177c37..304c9fa893 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -354,6 +354,7 @@ extern const char *GetConfigOption(const char *name, bool missing_ok,
 								   bool restrict_privileged);
 extern const char *GetConfigOptionResetString(const char *name);
 extern int	GetConfigOptionFlags(const char *name, bool missing_ok);
+extern bool SetConfigReport(const char *name, bool missing_ok);
 extern void ProcessConfigFile(GucContext context);
 extern void InitializeGUCOptions(void);
 extern bool SelectConfigFiles(const char *userDoption, const char *progname);
-- 
2.20.1 (Apple Git-117)

