po 4. 9. 2023 v 14:24 odesílatel Jelte Fennema <postg...@jeltef.nl> napsal:

> On Sun, 3 Sept 2023 at 20:58, Pavel Stehule <pavel.steh...@gmail.com>
> wrote:
> > here is an try
>
> Overall it does what I had in mind. Below a few suggestions:
>
> +int
> +PQprotocolSubversion(const PGconn *conn)
>
> Ugh, it's quite annoying that the original PQprotocolVersion only
> returns the major version and thus we need this new function. It
> seems like it would be much nicer if it returned a number similar to
> PQserverVersion. I think it might be nicer to change PQprotocolVersion
> to do that than to add another function. We could do:
>
> return PG_PROTOCOL_MAJOR(conn->pversion) * 100 +
> PG_PROTOCOL_MINOR(conn->pversion);
>
> or even:
>
> if (PG_PROTOCOL_MAJOR(conn->pversion) == 3 &&
> PG_PROTOCOL_MINOR(conn->pversion))
>     return 3;
> else
>     return PG_PROTOCOL_MAJOR(conn->pversion) * 100 +
> PG_PROTOCOL_MINOR(conn->pversion);
>
> The second option would be safest backwards compatibility wise, but in
> practice you would only get another value than 3 (or 0) when
> connecting to pre 7.4 servers. That seems old enough that I don't
> think anyone is actually calling this function. **I'd like some
> feedback from others on this though.**
>

This point is open. I'll wait for a reply from others.


>
> +       /* The protocol 3.0 is required */
> +       if (PG_PROTOCOL_MAJOR(their_version) == 3)
> +           conn->pversion = their_version;
>
> Let's compare against the actual PG_PROTOCOL_EARLIEST and
> PG_PROTOCOL_LATEST to determine if the version is supported or not.
>

changed
From f1975b784627fda06b23303c4f1fb6972d80a0a0 Mon Sep 17 00:00:00 2001
From: "ok...@github.com" <pavel.steh...@gmail.com>
Date: Mon, 24 Jul 2023 20:18:16 +0200
Subject: [PATCH 4/4] Implementation of %N prompt placeholder

It is based on forcing reporting feature"role" GUC to client.
---
 doc/src/sgml/ref/psql-ref.sgml | 19 ++++++++++++++++++-
 src/bin/psql/command.c         | 13 +++++++++++++
 src/bin/psql/prompt.c          | 28 ++++++++++++++++++++++++++++
 src/bin/psql/settings.h        |  1 +
 src/bin/psql/startup.c         | 32 ++++++++++++++++++++++++++++++++
 5 files changed, 92 insertions(+), 1 deletion(-)

diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index d94e3cacfc..8b267a6da6 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -4568,7 +4568,24 @@ testdb=&gt; <userinput>INSERT INTO my_table VALUES (:'content');</userinput>
         <listitem><para>The port number at which the database server is listening.</para></listitem>
       </varlistentry>
 
-      <varlistentry id="app-psql-prompting-n">
+      <varlistentry id="app-psql-prompting-n-uc">
+        <term><literal>%N</literal></term>
+        <listitem>
+         <para>
+          The database role name. This value is specified by command
+          <command>SET ROLE</command>. Until execution of this command
+          the value is set to the database session user name.
+         </para>
+
+         <para>
+          This substitution requires <productname>PostgreSQL</productname>
+          version 16 and up. When you use older version, the empty string
+          is used instead.
+         </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry id="app-psql-prompting-n-lc">
         <term><literal>%n</literal></term>
         <listitem>
          <para>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index bcd8eb3538..bad0fdf415 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -3883,6 +3883,7 @@ SyncVariables(void)
 {
 	char		vbuf[32];
 	const char *server_version;
+	PGresult   *result;
 
 	/* get stuff from connection */
 	pset.encoding = PQclientEncoding(pset.db);
@@ -3912,6 +3913,18 @@ SyncVariables(void)
 	/* send stuff to it, too */
 	PQsetErrorVerbosity(pset.db, pset.verbosity);
 	PQsetErrorContextVisibility(pset.db, pset.show_context);
+
+	/* link role GUC when it is needed for prompt */
+	if (pset.prompt_shows_role)
+		result = PQlinkParameterStatus(pset.db, "role");
+	else
+		result = PQunlinkParameterStatus(pset.db, "role");
+
+	if (PQresultStatus(result) != PGRES_COMMAND_OK)
+		pg_log_info("cannot set REPORT flag on configuration variable \"role\": %s",
+					PQerrorMessage(pset.db));
+
+	PQclear(result);
 }
 
 /*
diff --git a/src/bin/psql/prompt.c b/src/bin/psql/prompt.c
index 969cd9908e..d306c91d19 100644
--- a/src/bin/psql/prompt.c
+++ b/src/bin/psql/prompt.c
@@ -165,6 +165,34 @@ get_prompt(promptStatus_t status, ConditionalStack cstack)
 					if (pset.db)
 						strlcpy(buf, session_username(), sizeof(buf));
 					break;
+					/* DB server user role */
+				case 'N':
+					if (pset.db)
+					{
+						const char *rolename = NULL;
+
+						/*
+						 * This feature requires GUC "role" to be marked
+						 * by GUC_REPORT flag. This is done by PQlinkParameterStatus
+						 * function. This function requires protocol 3.1 (ReportGUC
+						 * message). Fallback is empty string.
+						 */
+						if (PQprotocolVersion(pset.db) == 3 &&
+							PQprotocolSubversion(pset.db) >= 1)
+						{
+							rolename  = PQparameterStatus(pset.db, "role");
+
+							/* fallback when role is not set yet */
+							if (rolename && strcmp(rolename, "none") == 0)
+								rolename = session_username();
+						}
+
+						if (rolename)
+							strlcpy(buf, rolename, sizeof(buf));
+						else
+							buf[0] = '\0';
+					}
+					break;
 					/* backend pid */
 				case 'p':
 					if (pset.db)
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index 1106954236..cb7c12bd1d 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -154,6 +154,7 @@ typedef struct _psqlSettings
 	PGVerbosity verbosity;		/* current error verbosity level */
 	bool		show_all_results;
 	PGContextVisibility show_context;	/* current context display level */
+	bool		prompt_shows_role;
 } PsqlSettings;
 
 extern PsqlSettings pset;
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 5a28b6f713..0dac396525 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -1094,10 +1094,40 @@ histcontrol_hook(const char *newval)
 	return true;
 }
 
+static void
+prompt_needs_role_parameter_status(void)
+{
+	PGresult   *result;
+
+	if (!pset.db)
+		return;
+
+	pset.prompt_shows_role = false;
+
+	if (pset.prompt1 && strstr(pset.prompt1, "%N"))
+		pset.prompt_shows_role = true;
+	else if (pset.prompt2 && strstr(pset.prompt2, "%N"))
+		pset.prompt_shows_role = true;
+	else if (pset.prompt3 && strstr(pset.prompt3, "%N"))
+		pset.prompt_shows_role = true;
+
+	if (pset.prompt_shows_role)
+		result = PQlinkParameterStatus(pset.db, "role");
+	else
+		result = PQunlinkParameterStatus(pset.db, "role");
+
+	if (PQresultStatus(result) != PGRES_COMMAND_OK)
+		pg_log_info("cannot set REPORT flag on configuration variable \"role\": %s",
+					PQerrorMessage(pset.db));
+
+	PQclear(result);
+}
+
 static bool
 prompt1_hook(const char *newval)
 {
 	pset.prompt1 = newval ? newval : "";
+	prompt_needs_role_parameter_status();
 	return true;
 }
 
@@ -1105,6 +1135,7 @@ static bool
 prompt2_hook(const char *newval)
 {
 	pset.prompt2 = newval ? newval : "";
+	prompt_needs_role_parameter_status();
 	return true;
 }
 
@@ -1112,6 +1143,7 @@ static bool
 prompt3_hook(const char *newval)
 {
 	pset.prompt3 = newval ? newval : "";
+	prompt_needs_role_parameter_status();
 	return true;
 }
 
-- 
2.41.0

From ca53fa4fa27f8e43c690c50bbf78ae89aa8e7c27 Mon Sep 17 00:00:00 2001
From: "ok...@github.com" <pavel.steh...@gmail.com>
Date: Sun, 3 Sep 2023 19:14:24 +0200
Subject: [PATCH 3/4] - allow to connect to server with major protocol version
 3, minor version is ignored

- allow to read minor protocol version
---
 src/include/libpq/pqcomm.h          |  2 +-
 src/interfaces/libpq/exports.txt    |  1 +
 src/interfaces/libpq/fe-connect.c   | 12 +++++++++++-
 src/interfaces/libpq/fe-protocol3.c | 15 ++++++++++++---
 src/interfaces/libpq/libpq-fe.h     |  1 +
 5 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h
index 46a0946b8b..4ea4538157 100644
--- a/src/include/libpq/pqcomm.h
+++ b/src/include/libpq/pqcomm.h
@@ -94,7 +94,7 @@ is_unixsock_path(const char *path)
  */
 
 #define PG_PROTOCOL_EARLIEST	PG_PROTOCOL(3,0)
-#define PG_PROTOCOL_LATEST		PG_PROTOCOL(3,0)
+#define PG_PROTOCOL_LATEST		PG_PROTOCOL(3,1)
 
 typedef uint32 ProtocolVersion; /* FE/BE protocol version number */
 
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index 7e101368d5..71e180cd57 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -193,3 +193,4 @@ PQsendClosePrepared       190
 PQsendClosePortal         191
 PQlinkParameterStatus     192
 PQunlinkParameterStatus   193
+PQprotocolSubversion      194
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index bf83a9b569..5e628578b4 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -2777,7 +2777,7 @@ keep_going:						/* We will come back to here until there is
 		 * must persist across individual connection attempts, but we must
 		 * reset them when we start to consider a new server.
 		 */
-		conn->pversion = PG_PROTOCOL(3, 0);
+		conn->pversion = PG_PROTOCOL(3, 1);
 		conn->send_appname = true;
 #ifdef USE_SSL
 		/* initialize these values based on SSL mode */
@@ -7234,6 +7234,16 @@ PQprotocolVersion(const PGconn *conn)
 	return PG_PROTOCOL_MAJOR(conn->pversion);
 }
 
+int
+PQprotocolSubversion(const PGconn *conn)
+{
+	if (!conn)
+		return 0;
+	if (conn->status == CONNECTION_BAD)
+		return 0;
+	return PG_PROTOCOL_MINOR(conn->pversion);
+}
+
 int
 PQserverVersion(const PGconn *conn)
 {
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index 90d4e17e6f..c828124db5 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -1441,9 +1441,18 @@ pqGetNegotiateProtocolVersion3(PGconn *conn)
 	}
 
 	if (their_version < conn->pversion)
-		libpq_append_conn_error(conn, "protocol version not supported by server: client uses %u.%u, server supports up to %u.%u",
-								PG_PROTOCOL_MAJOR(conn->pversion), PG_PROTOCOL_MINOR(conn->pversion),
-								PG_PROTOCOL_MAJOR(their_version), PG_PROTOCOL_MINOR(their_version));
+	{
+		if (PG_PROTOCOL_MAJOR(their_version) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
+			PG_PROTOCOL_MAJOR(their_version) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST))
+		{
+			libpq_append_conn_error(conn, "protocol version not supported by server: client uses %u.%u, server supports up to %u.%u",
+									PG_PROTOCOL_MAJOR(conn->pversion), PG_PROTOCOL_MINOR(conn->pversion),
+									PG_PROTOCOL_MAJOR(their_version), PG_PROTOCOL_MINOR(their_version));
+		}
+		else
+			conn->pversion = their_version;
+	}
+
 	if (num > 0)
 	{
 		appendPQExpBuffer(&conn->errorMessage,
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index ba3ad7e0aa..904e611670 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -347,6 +347,7 @@ extern PGTransactionStatusType PQtransactionStatus(const PGconn *conn);
 extern const char *PQparameterStatus(const PGconn *conn,
 									 const char *paramName);
 extern int	PQprotocolVersion(const PGconn *conn);
+extern int	PQprotocolSubversion(const PGconn *conn);
 extern int	PQserverVersion(const PGconn *conn);
 extern char *PQerrorMessage(const PGconn *conn);
 extern int	PQsocket(const PGconn *conn);
-- 
2.41.0

From 020618033a11c7e6c92dc4bd00d6a78a216874f1 Mon Sep 17 00:00:00 2001
From: "ok...@github.com" <pavel.steh...@gmail.com>
Date: Mon, 28 Aug 2023 14:57:07 +0200
Subject: [PATCH 2/4] PQlinkParameterStatus, PQunlinkParameterStatus test based
 on libpq_pipeline test

---
 .../modules/libpq_pipeline/libpq_pipeline.c   | 31 +++++++++++++++++++
 .../libpq_pipeline/traces/reportguc.trace     | 15 +++++++++
 2 files changed, 46 insertions(+)
 create mode 100644 src/test/modules/libpq_pipeline/traces/reportguc.trace

diff --git a/src/test/modules/libpq_pipeline/libpq_pipeline.c b/src/test/modules/libpq_pipeline/libpq_pipeline.c
index 9907bc8600..ea5ef97b2d 100644
--- a/src/test/modules/libpq_pipeline/libpq_pipeline.c
+++ b/src/test/modules/libpq_pipeline/libpq_pipeline.c
@@ -1677,6 +1677,34 @@ test_uniqviol(PGconn *conn)
 	fprintf(stderr, "ok\n");
 }
 
+/*
+ * Test of ReportGUC message
+ */
+static void
+test_reportguc(PGconn *conn)
+{
+	PGresult   *res;
+
+	fprintf(stderr, "reportguc ...");
+
+	res = PQexec(conn, "SELECT pg_catalog.set_config('test.test', 'Hello', false)");
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		pg_fatal("failed to create custom config variable: %s", PQerrorMessage(conn));
+	PQclear(res);
+
+	res = PQlinkParameterStatus(conn, "test.test");
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		pg_fatal("failed to link custom variable: %s", PQerrorMessage(conn));
+	PQclear(res);
+
+	res = PQunlinkParameterStatus(conn, "test.test");
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		pg_fatal("failed to unlink custom variable: %s", PQerrorMessage(conn));
+	PQclear(res);
+
+	fprintf(stderr, "ok\n");
+}
+
 /*
  * Subroutine for test_uniqviol; given a PGresult, print it out and consume
  * the expected NULL that should follow it.
@@ -1757,6 +1785,7 @@ print_test_list(void)
 	printf("singlerow\n");
 	printf("transaction\n");
 	printf("uniqviol\n");
+	printf("reportguc\n");
 }
 
 int
@@ -1869,6 +1898,8 @@ main(int argc, char **argv)
 		test_transaction(conn);
 	else if (strcmp(testname, "uniqviol") == 0)
 		test_uniqviol(conn);
+	else if (strcmp(testname, "reportguc") == 0)
+		test_reportguc(conn);
 	else
 	{
 		fprintf(stderr, "\"%s\" is not a recognized test name\n", testname);
diff --git a/src/test/modules/libpq_pipeline/traces/reportguc.trace b/src/test/modules/libpq_pipeline/traces/reportguc.trace
new file mode 100644
index 0000000000..b000dfe0be
--- /dev/null
+++ b/src/test/modules/libpq_pipeline/traces/reportguc.trace
@@ -0,0 +1,15 @@
+F	62	Query	 "SELECT pg_catalog.set_config('test.test', 'Hello', false)"
+B	35	RowDescription	 1 "set_config" NNNN 0 NNNN 65535 -1 0
+B	15	DataRow	 1 5 'Hello'
+B	13	CommandComplete	 "SELECT 1"
+B	5	ReadyForQuery	 I
+F	15	ReportGUC	 t "test.test"
+F	4	Sync
+B	20	ParameterStatus	 "test.test" "Hello"
+B	19	CommandComplete	 "SET REPORT_GUC"
+B	5	ReadyForQuery	 I
+F	15	ReportGUC	 f "test.test"
+F	4	Sync
+B	21	CommandComplete	 "UNSET REPORT_GUC"
+B	5	ReadyForQuery	 I
+F	4	Terminate
-- 
2.41.0

From 56726d38f03879fb9623a79f369910bb2d7eb355 Mon Sep 17 00:00:00 2001
From: "ok...@github.com" <pavel.steh...@gmail.com>
Date: Mon, 24 Jul 2023 20:13:17 +0200
Subject: [PATCH 1/4] Protocol ReportGUC message

This patch implements dynamic reporting changes of GUC to client side.

The flags per GUC can be changed by functions SetGUCOptionFlag and UsetGUCOptionFlag.
---
 doc/src/sgml/protocol.sgml          | 37 +++++++++++++++++++++++++++++
 src/backend/tcop/postgres.c         | 32 +++++++++++++++++++++++++
 src/backend/utils/misc/guc.c        | 31 ++++++++++++++++++++++++
 src/include/libpq/protocol.h        |  1 +
 src/include/utils/guc.h             |  2 ++
 src/interfaces/libpq/exports.txt    |  2 ++
 src/interfaces/libpq/fe-exec.c      | 36 +++++++++++++++++++++++++++-
 src/interfaces/libpq/fe-protocol3.c |  1 -
 src/interfaces/libpq/fe-trace.c     | 12 ++++++++++
 src/interfaces/libpq/libpq-fe.h     |  3 +++
 src/interfaces/libpq/libpq-int.h    |  4 +++-
 11 files changed, 158 insertions(+), 3 deletions(-)

diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index b11d9a6ba3..fe6c4042fd 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -5401,6 +5401,43 @@ psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;"
     </listitem>
    </varlistentry>
 
+   <varlistentry id="protocol-message-formats-ReportGUC">
+    <term>ReportGUC (F)</term>
+    <listitem>
+     <variablelist>
+      <varlistentry>
+       <term>Byte1('r')</term>
+       <listitem>
+        <para>
+         Identifies the message type.  ReportGUC is sent by
+         frontend when the changes of specified GUC option
+         should be (or should not be) reported to state parameter.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>Byte1</term>
+       <listitem>
+        <para>
+         't' when reporting should be enables, 'f' if reporting should be
+         disabled.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>String</term>
+       <listitem>
+        <para>
+         The name of GUC option.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+    </listitem>
+   </varlistentry>
+
    <varlistentry id="protocol-message-formats-RowDescription">
     <term>RowDescription (B)</term>
     <listitem>
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index e4756f8be2..0e4ddbf8ee 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -451,6 +451,11 @@ SocketBackend(StringInfo inBuf)
 			doing_extended_query_message = false;
 			break;
 
+		case PqMsg_ReportGUC:
+			maxmsglen = PQ_SMALL_MESSAGE_LIMIT;
+			doing_extended_query_message = false;
+			break;
+
 		default:
 
 			/*
@@ -4835,6 +4840,33 @@ PostgresMain(const char *dbname, const char *username)
 				send_ready_for_query = true;
 				break;
 
+			case PqMsg_ReportGUC:
+				{
+					const char	   *name;
+					const char	   *status;
+					int				is_set;
+
+					is_set = pq_getmsgbyte(&input_message);
+					name = pq_getmsgstring(&input_message);
+					pq_getmsgend(&input_message);
+
+					if (is_set == 't')
+					{
+						SetGUCOptionFlag(name, GUC_REPORT);
+						status = "SET REPORT_GUC";
+					}
+					else
+					{
+						UnsetGUCOptionFlag(name, GUC_REPORT);
+						status = "UNSET REPORT_GUC";
+					}
+
+					pq_puttextmessage(PqMsg_CommandComplete, status);
+
+					valgrind_report_error_query("ReportGUC message");
+				}
+				break;
+
 				/*
 				 * 'X' means that the frontend is closing down the socket. EOF
 				 * means unexpected loss of frontend connection. Either way,
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 84e7ad4d90..4a1e968255 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2532,6 +2532,37 @@ BeginReportingGUCOptions(void)
 	}
 }
 
+/*
+ * Allow to set / unset dynamicaly flags to GUC variables
+ */
+void
+SetGUCOptionFlag(const char *name, int flag)
+{
+	struct config_generic *conf;
+
+	/* only GUC_REPORT flag is supported now */
+	Assert(flag == GUC_REPORT);
+
+	conf = find_option(name, false, true, ERROR);
+	conf->flags |= flag;
+
+	if (flag == GUC_REPORT)
+		/* force transmit value of related option to client Parameter Status */
+		ReportGUCOption(conf);
+}
+
+void
+UnsetGUCOptionFlag(const char *name, int flag)
+{
+	struct config_generic *conf;
+
+	/* only GUC_REPORT flag is supported now */
+	Assert(flag == GUC_REPORT);
+
+	conf = find_option(name, false, true, ERROR);
+	conf->flags &= ~flag;
+}
+
 /*
  * ReportChangedGUCOptions: report recently-changed GUC_REPORT variables
  *
diff --git a/src/include/libpq/protocol.h b/src/include/libpq/protocol.h
index cc46f4b586..bd2c368b54 100644
--- a/src/include/libpq/protocol.h
+++ b/src/include/libpq/protocol.h
@@ -27,6 +27,7 @@
 #define PqMsg_Sync					'S'
 #define PqMsg_Terminate				'X'
 #define PqMsg_CopyFail				'f'
+#define PqMsg_ReportGUC				'r'
 #define PqMsg_GSSResponse			'p'
 #define PqMsg_PasswordMessage		'p'
 #define PqMsg_SASLInitialResponse	'p'
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index e89083ee0e..c200ca9b34 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -370,6 +370,8 @@ extern void ResetAllOptions(void);
 extern void AtStart_GUC(void);
 extern int	NewGUCNestLevel(void);
 extern void AtEOXact_GUC(bool isCommit, int nestLevel);
+extern void SetGUCOptionFlag(const char *name, int flag);
+extern void UnsetGUCOptionFlag(const char *name, int flag);
 extern void BeginReportingGUCOptions(void);
 extern void ReportChangedGUCOptions(void);
 extern void ParseLongOption(const char *string, char **name, char **value);
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index 850734ac96..7e101368d5 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -191,3 +191,5 @@ PQclosePrepared           188
 PQclosePortal             189
 PQsendClosePrepared       190
 PQsendClosePortal         191
+PQlinkParameterStatus     192
+PQunlinkParameterStatus   193
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index c6d80ec396..1971b63102 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -1069,6 +1069,33 @@ pqSaveMessageField(PGresult *res, char code, const char *value)
 	res->errFields = pfield;
 }
 
+/*
+ * Add GUC_REPORT flag to specified setting and wait for synchronization
+ * with state parameters.
+ */
+PGresult *
+PQlinkParameterStatus(PGconn *conn, const char *paramName)
+{
+	if (!PQexecStart(conn))
+		return NULL;
+	if (!PQsendTypedCommand(conn, PqMsg_ReportGUC, 't', paramName))
+		return NULL;
+	return PQexecFinish(conn);
+}
+
+/*
+ * Remove GUC_REPORT flag from specified setting.
+ */
+PGresult *
+PQunlinkParameterStatus(PGconn *conn, const char *paramName)
+{
+	if (!PQexecStart(conn))
+		return NULL;
+	if (!PQsendTypedCommand(conn, PqMsg_ReportGUC, 'f', paramName))
+		return NULL;
+	return PQexecFinish(conn);
+}
+
 /*
  * pqSaveParameterStatus - remember parameter status sent by backend
  */
@@ -2543,11 +2570,14 @@ PQsendClosePortal(PGconn *conn, const char *portal)
  *
  * Available options for "command" are
  *	 PqMsg_Close for Close; or
- *	 PqMsg_Describe for Describe.
+ *	 PqMsg_Describe for Describe; or
+ *	 PqMsg_ReportGUC for (un)set GUC_REPORT flag.
  *
  * Available options for "type" are
  *	 'S' to run a command on a prepared statement; or
  *	 'P' to run a command on a portal.
+ *	 't' to set GUC_REPORT flag
+ *	 'f' to unset GUC_REPORT flag
  *
  * Returns 1 on success and 0 on failure.
  */
@@ -2591,6 +2621,10 @@ PQsendTypedCommand(PGconn *conn, char command, char type, const char *target)
 	{
 		entry->queryclass = PGQUERY_DESCRIBE;
 	}
+	else if (command == PqMsg_ReportGUC)
+	{
+		entry->queryclass = PGQUERY_SETTING;
+	}
 	else
 	{
 		libpq_append_conn_error(conn, "unknown command type provided");
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index 5613c56b14..90d4e17e6f 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -2003,7 +2003,6 @@ pqEndcopy3(PGconn *conn)
 	return 1;
 }
 
-
 /*
  * PQfn - Send a function call to the POSTGRES backend.
  *
diff --git a/src/interfaces/libpq/fe-trace.c b/src/interfaces/libpq/fe-trace.c
index b18e3deab6..2a439080e1 100644
--- a/src/interfaces/libpq/fe-trace.c
+++ b/src/interfaces/libpq/fe-trace.c
@@ -522,6 +522,15 @@ pqTraceOutputZ(FILE *f, const char *message, int *cursor)
 	pqTraceOutputByte1(f, message, cursor);
 }
 
+/* ReportGUC */
+static void
+pqTraceOutputr(FILE *f, const char *message, int *cursor)
+{
+	fprintf(f, "ReportGUC\t");
+	pqTraceOutputByte1(f, message, cursor);
+	pqTraceOutputString(f, message, cursor, false);
+}
+
 /*
  * Print the given message to the trace output stream.
  */
@@ -644,6 +653,9 @@ pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer)
 		case PqMsg_AuthenticationRequest:
 			pqTraceOutputR(conn->Pfdebug, message, &logCursor);
 			break;
+		case PqMsg_ReportGUC:
+			pqTraceOutputr(conn->Pfdebug, message, &logCursor);
+			break;
 		case PqMsg_PortalSuspended:
 			fprintf(conn->Pfdebug, "PortalSuspended");
 			/* No message content */
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index 97762d56f5..ba3ad7e0aa 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -593,6 +593,9 @@ extern unsigned char *PQescapeBytea(const unsigned char *from, size_t from_lengt
 									size_t *to_length);
 
 
+/* Control of dynamic propagation settings to state parameters */
+extern PGresult *PQlinkParameterStatus(PGconn *conn, const char *paramName);
+extern PGresult *PQunlinkParameterStatus(PGconn *conn, const char *paramName);
 
 /* === in fe-print.c === */
 
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index c745facfec..081e228f2b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -322,7 +322,8 @@ typedef enum
 	PGQUERY_PREPARE,			/* Parse only (PQprepare) */
 	PGQUERY_DESCRIBE,			/* Describe Statement or Portal */
 	PGQUERY_SYNC,				/* Sync (at end of a pipeline) */
-	PGQUERY_CLOSE				/* Close Statement or Portal */
+	PGQUERY_CLOSE,				/* Close Statement or Portal */
+	PGQUERY_SETTING				/* setting GUC_REPORT flag */
 } PGQueryClass;
 
 /*
@@ -718,6 +719,7 @@ extern PGresult *pqFunctionCall3(PGconn *conn, Oid fnid,
 								 int *result_buf, int *actual_result_len,
 								 int result_is_int,
 								 const PQArgBlock *args, int nargs);
+extern int pqSendReportGUCMessage(PGconn *conn, const char *paramName, bool create_flag);
 
 /* === in fe-misc.c === */
 
-- 
2.41.0

Reply via email to