fix_alter_role_reset_v1.patch

text/plain

Filename: fix_alter_role_reset_v1.patch
Type: text/plain
Part: 0
Message: Re: BUG #18964: `ALTER DATABASE ... RESET ...` fails to reset extension parameters that no longer exist

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: unified
Series: patch v1
File+
src/backend/utils/misc/guc.c 21 8
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 667df448732..ba1bf49e83c 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -250,7 +250,7 @@ static void reapply_stacked_values(struct config_generic *variable,
 								   GucContext curscontext, GucSource cursource,
 								   Oid cursrole);
 static bool validate_option_array_item(const char *name, const char *value,
-									   bool skipIfNoPermissions);
+									   bool skipIfNoPermissions, bool isReset);
 static void write_auto_conf_file(int fd, const char *filename, ConfigVariable *head);
 static void replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p,
 									  const char *name, const char *value);
@@ -6497,7 +6497,7 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value)
 	Assert(value);
 
 	/* test if the option is valid and we're allowed to set it */
-	(void) validate_option_array_item(name, value, false);
+	(void) validate_option_array_item(name, value, false, false);
 
 	/* normalize name (converts obsolete GUC names to modern spellings) */
 	record = find_option(name, false, true, WARNING);
@@ -6574,7 +6574,7 @@ GUCArrayDelete(ArrayType *array, const char *name)
 	Assert(name);
 
 	/* test if the option is valid and we're allowed to set it */
-	(void) validate_option_array_item(name, NULL, false);
+	(void) validate_option_array_item(name, NULL, false, true);
 
 	/* normalize name (converts obsolete GUC names to modern spellings) */
 	record = find_option(name, false, true, WARNING);
@@ -6672,7 +6672,7 @@ GUCArrayReset(ArrayType *array)
 		*eqsgn = '\0';
 
 		/* skip if we have permission to delete it */
-		if (validate_option_array_item(val, NULL, true))
+		if (validate_option_array_item(val, NULL, true, true))
 			continue;
 
 		/* else add it to the output array */
@@ -6707,10 +6707,18 @@ GUCArrayReset(ArrayType *array)
  */
 static bool
 validate_option_array_item(const char *name, const char *value,
-						   bool skipIfNoPermissions)
+						   bool skipIfNoPermissions, bool isReset)
 
 {
 	struct config_generic *gconf;
+	bool		skip_errors;
+
+	/*
+	 * For RESET and RESET ALL, we treat unknown custom GUCs with reserved
+	 * prefixes the same as if a placeholder is created.  That requires we
+	 * skip errors in find_option().
+	 */
+	skip_errors = (isReset && valid_custom_variable_name(name));
 
 	/*
 	 * There are three cases to consider:
@@ -6731,14 +6739,19 @@ validate_option_array_item(const char *name, const char *value,
 	 * name is not known and can't be created as a placeholder.  Throw error,
 	 * unless skipIfNoPermissions is true, in which case return false.
 	 */
-	gconf = find_option(name, true, skipIfNoPermissions, ERROR);
-	if (!gconf)
+	gconf = find_option(name, true, skipIfNoPermissions || skip_errors, ERROR);
+	if (!gconf && !skip_errors)
 	{
 		/* not known, failed to make a placeholder */
 		return false;
 	}
 
-	if (gconf->flags & GUC_CUSTOM_PLACEHOLDER)
+	/*
+	 * If we reach this point and gconf is NULL, we know we're dealing with a
+	 * RESET or RESET ALL command for an unknown custom GUC with a reserved
+	 * prefix.  We treat that the same as if a placeholder was created.
+	 */
+	if (!gconf || gconf->flags & GUC_CUSTOM_PLACEHOLDER)
 	{
 		/*
 		 * We cannot do any meaningful check on the value, so only permissions