v12-0011-Add-GUC-contexts-for-protocol-extensions.patch

application/octet-stream

Filename: v12-0011-Add-GUC-contexts-for-protocol-extensions.patch
Type: application/octet-stream
Part: 12
Message: Re: Add new protocol message to change GUCs for usage with future protocol-only GUCs

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: format-patch
Series: patch v12-0011
Subject: Add GUC contexts for protocol extensions
File+
src/backend/tcop/postgres.c 17 2
src/backend/utils/misc/guc.c 47 1
src/backend/utils/misc/guc_tables.c 2 0
src/include/utils/guc.h 2 0
From 21750fa9239e20dd2498ab6938143376bdfac94e Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Mon, 8 Jan 2024 16:25:16 +0100
Subject: [PATCH v12 11/14] Add GUC contexts for protocol extensions

This patch adds two new GUC contexts: PGC_PROTOCOL and PGC_SU_PROTOCOL.

These new GUC contexts are intended to be used by protocol extension
parameters. Any intermediary component that works at the protocol level,
such as clients libraries or connection poolsers, should be notified
when changes to such parameters are made because these parameters
control the behaviour and interpretation of the protocol. If changes are
made without these intermediary components realizing they might
interpret protocol messages incorrectly. It's also possible that such
intermediary components themselves have certain requirements on the
value of such parameters to be able to function correctly. So they might
want to block certain changes, or modify the requested value before
sending it to the PostgreSQL server.

Having these protocol extension parameters use PGC_BACKEND is also not
an option, because then these parameters would be unchangable once the
connection is set up. Which would limit the ways in which they could be
used, especially when considering connection poolers that might want to
change the protocol parameters based on the client that the server
connection is assigned to.
---
 src/backend/tcop/postgres.c         | 19 ++++++++++--
 src/backend/utils/misc/guc.c        | 48 ++++++++++++++++++++++++++++-
 src/backend/utils/misc/guc_tables.c |  2 ++
 src/include/utils/guc.h             |  2 ++
 4 files changed, 68 insertions(+), 3 deletions(-)

diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 6f1167885c0..b2748dd9e4a 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -4884,18 +4884,33 @@ PostgresMain(const char *dbname, const char *username)
 				{
 					const char *parameter_name;
 					const char *parameter_value;
+					struct config_generic *config;
 
 					forbidden_in_wal_sender(firstchar);
 
 					parameter_name = pq_getmsgstring(&input_message);
 					parameter_value = pq_getmsgstring(&input_message);
+					pq_getmsgend(&input_message);
 
-					start_xact_command();
+					config = find_option(parameter_name, false, false, ERROR);
+					if (config->context == PGC_PROTOCOL || config->context == PGC_SU_PROTOCOL)
+					{
+						if (IsTransactionOrTransactionBlock())
+						{
+							ereport(ERROR,
+									(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
+									 errmsg("parameter \"%s\" cannot be changed within a transaction", parameter_name)));
+						}
+					}
+					else
+					{
+						start_xact_command();
+					}
 
 					SetConfigOption(
 									parameter_name,
 									parameter_value,
-									(superuser() ? PGC_SUSET : PGC_USERSET),
+									(superuser() ? PGC_SU_PROTOCOL : PGC_PROTOCOL),
 									PGC_S_SESSION);
 					if (whereToSendOutput == DestRemote)
 						pq_putemptymessage(PqMsg_ParameterSetComplete);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index f51b3e0b507..29a03c6c288 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -3566,8 +3566,53 @@ set_config_with_handle(const char *name, config_handle *handle,
 				return 0;
 			}
 			break;
+		case PGC_SU_PROTOCOL:
+			if (context == PGC_BACKEND || context == PGC_PROTOCOL)
+			{
+				/*
+				 * Check whether the requesting user has been granted
+				 * privilege to set this GUC.
+				 */
+				AclResult	aclresult;
+
+				aclresult = pg_parameter_aclcheck(name, srole, ACL_SET);
+				if (aclresult != ACLCHECK_OK)
+				{
+					/* No granted privilege */
+					ereport(elevel,
+							(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+							 errmsg("permission denied to set parameter \"%s\"",
+									name)));
+					return 0;
+				}
+			}
+			/* fall through to process the same as PGC_PROTOCOL */
+			/* FALLTHROUGH */
+		case PGC_PROTOCOL:
+			if (context == PGC_SIGHUP)
+			{
+				/*
+				 * Same SIGHUP treatment as for PGC_BACKEND vars. See comment
+				 * above for details.
+				 */
+				if (IsUnderPostmaster && changeVal && !is_reload)
+					return -1;
+			}
+			else if (context != PGC_POSTMASTER &&
+					 context != PGC_BACKEND &&
+					 context != PGC_SU_BACKEND &&
+					 context != PGC_PROTOCOL &&
+					 context != PGC_SU_PROTOCOL)
+			{
+				ereport(elevel,
+						(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
+						 errmsg("parameter \"%s\" cannot be set using SQL",
+								name)));
+				return 0;
+			}
+			break;
 		case PGC_SUSET:
-			if (context == PGC_USERSET || context == PGC_BACKEND)
+			if (context == PGC_USERSET || context == PGC_PROTOCOL || context == PGC_BACKEND)
 			{
 				/*
 				 * Check whether the requesting user has been granted
@@ -4629,6 +4674,7 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
 			 * to be set in PG_AUTOCONF_FILENAME file.
 			 */
 			if ((record->context == PGC_INTERNAL) ||
+				(record->context == PGC_PROTOCOL) ||
 				(record->flags & GUC_DISALLOW_IN_FILE) ||
 				(record->flags & GUC_DISALLOW_IN_AUTO_FILE))
 				ereport(ERROR,
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index c12784cbec8..9cf005607d6 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -634,6 +634,8 @@ const char *const GucContext_Names[] =
 	[PGC_SIGHUP] = "sighup",
 	[PGC_SU_BACKEND] = "superuser-backend",
 	[PGC_BACKEND] = "backend",
+	[PGC_SU_PROTOCOL] = "superuser-protocol",
+	[PGC_PROTOCOL] = "protocol",
 	[PGC_SUSET] = "superuser",
 	[PGC_USERSET] = "user",
 };
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 8d1fe04078a..61f6b1cf752 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -71,6 +71,8 @@ typedef enum
 	PGC_SIGHUP,
 	PGC_SU_BACKEND,
 	PGC_BACKEND,
+	PGC_SU_PROTOCOL,
+	PGC_PROTOCOL,
 	PGC_SUSET,
 	PGC_USERSET,
 } GucContext;
-- 
2.34.1