diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 5da5981726c5cf53624ebde4aebbdd14965b7a6f..3af15dd38bb7044ec6f733787cad6897b204ccd3 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -774,9 +774,7 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 						 const char *schemaName, Oid schemaOid)
 {
 	char	   *filename;
-	char	   *save_client_min_messages,
-			   *save_log_min_messages,
-			   *save_search_path;
+	int			save_nestlevel;
 	StringInfoData pathbuf;
 	ListCell   *lc;
 
@@ -808,22 +806,20 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 	 * so that we won't spam the user with useless NOTICE messages from common
 	 * script actions like creating shell types.
 	 *
-	 * We use the equivalent of SET LOCAL to ensure the setting is undone upon
-	 * error.
+	 * We use the equivalent of a function SET option to allow the setting to
+	 * persist for exactly the duration of the script execution.  guc.c also
+	 * takes care of undoing the setting on error.
 	 */
-	save_client_min_messages =
-		pstrdup(GetConfigOption("client_min_messages", false, false));
+	save_nestlevel = NewGUCNestLevel();
+
 	if (client_min_messages < WARNING)
 		(void) set_config_option("client_min_messages", "warning",
 								 PGC_USERSET, PGC_S_SESSION,
-								 GUC_ACTION_LOCAL, true, 0);
-
-	save_log_min_messages =
-		pstrdup(GetConfigOption("log_min_messages", false, false));
+								 GUC_ACTION_SAVE, true, 0);
 	if (log_min_messages < WARNING)
 		(void) set_config_option("log_min_messages", "warning",
 								 PGC_SUSET, PGC_S_SESSION,
-								 GUC_ACTION_LOCAL, true, 0);
+								 GUC_ACTION_SAVE, true, 0);
 
 	/*
 	 * Set up the search path to contain the target schema, then the schemas
@@ -832,10 +828,9 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 	 *
 	 * Note: it might look tempting to use PushOverrideSearchPath for this,
 	 * but we cannot do that.  We have to actually set the search_path GUC in
-	 * case the extension script examines or changes it.
+	 * case the extension script examines or changes it.  In any case, the
+	 * GUC_ACTION_SAVE method is just as convenient.
 	 */
-	save_search_path = pstrdup(GetConfigOption("search_path", false, false));
-
 	initStringInfo(&pathbuf);
 	appendStringInfoString(&pathbuf, quote_identifier(schemaName));
 	foreach(lc, requiredSchemas)
@@ -849,7 +844,7 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 
 	(void) set_config_option("search_path", pathbuf.data,
 							 PGC_USERSET, PGC_S_SESSION,
-							 GUC_ACTION_LOCAL, true, 0);
+							 GUC_ACTION_SAVE, true, 0);
 
 	/*
 	 * Set creating_extension and related variables so that
@@ -910,18 +905,9 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 	CurrentExtensionObject = InvalidOid;
 
 	/*
-	 * Restore GUC variables for the remainder of the current transaction.
-	 * Again use SET LOCAL, so we won't affect the session value.
+	 * Restore the GUC variables we set above.
 	 */
-	(void) set_config_option("search_path", save_search_path,
-							 PGC_USERSET, PGC_S_SESSION,
-							 GUC_ACTION_LOCAL, true, 0);
-	(void) set_config_option("client_min_messages", save_client_min_messages,
-							 PGC_USERSET, PGC_S_SESSION,
-							 GUC_ACTION_LOCAL, true, 0);
-	(void) set_config_option("log_min_messages", save_log_min_messages,
-							 PGC_SUSET, PGC_S_SESSION,
-							 GUC_ACTION_LOCAL, true, 0);
+	AtEOXact_GUC(true, save_nestlevel);
 }
 
 /*
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index b913e85b31df91d5f720e4848f70f0d94cbc3dca..522a540c0c3bdacbee4d51b6bfeaf7b306af9055 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -2633,7 +2633,7 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
 	RangeTblEntry *fkrte;
 	const char *sep;
 	int			i;
-	int			old_work_mem;
+	int			save_nestlevel;
 	char		workmembuf[32];
 	int			spi_result;
 	SPIPlanPtr	qplan;
@@ -2772,14 +2772,16 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
 	 * this seems to meet the criteria for being considered a "maintenance"
 	 * operation, and accordingly we use maintenance_work_mem.
 	 *
-	 * We do the equivalent of "SET LOCAL work_mem" so that transaction abort
-	 * will restore the old value if we lose control due to an error.
+	 * We use the equivalent of a function SET option to allow the setting to
+	 * persist for exactly the duration of the check query.  guc.c also takes
+	 * care of undoing the setting on error.
 	 */
-	old_work_mem = work_mem;
+	save_nestlevel = NewGUCNestLevel();
+
 	snprintf(workmembuf, sizeof(workmembuf), "%d", maintenance_work_mem);
 	(void) set_config_option("work_mem", workmembuf,
 							 PGC_USERSET, PGC_S_SESSION,
-							 GUC_ACTION_LOCAL, true, 0);
+							 GUC_ACTION_SAVE, true, 0);
 
 	if (SPI_connect() != SPI_OK_CONNECT)
 		elog(ERROR, "SPI_connect failed");
@@ -2862,13 +2864,9 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
 		elog(ERROR, "SPI_finish failed");
 
 	/*
-	 * Restore work_mem for the remainder of the current transaction. This is
-	 * another SET LOCAL, so it won't affect the session value.
+	 * Restore work_mem.
 	 */
-	snprintf(workmembuf, sizeof(workmembuf), "%d", old_work_mem);
-	(void) set_config_option("work_mem", workmembuf,
-							 PGC_USERSET, PGC_S_SESSION,
-							 GUC_ACTION_LOCAL, true, 0);
+	AtEOXact_GUC(true, save_nestlevel);
 
 	return true;
 }
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 151cb190c35622320326053700daaff248bd06f8..85fdad8996c3d6f65d7435304424edbe3b805c4d 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -4329,8 +4329,9 @@ AtStart_GUC(void)
 
 /*
  * Enter a new nesting level for GUC values.  This is called at subtransaction
- * start and when entering a function that has proconfig settings.	NOTE that
- * we must not risk error here, else subtransaction start will be unhappy.
+ * start, and when entering a function that has proconfig settings, and in
+ * some other places where we want to set GUC variables transiently.
+ * NOTE we must not risk error here, else subtransaction start will be unhappy.
  */
 int
 NewGUCNestLevel(void)
@@ -4340,8 +4341,9 @@ NewGUCNestLevel(void)
 
 /*
  * Do GUC processing at transaction or subtransaction commit or abort, or
- * when exiting a function that has proconfig settings.  (The name is thus
- * a bit of a misnomer; perhaps it should be ExitGUCNestLevel or some such.)
+ * when exiting a function that has proconfig settings, or when undoing a
+ * transient assignment to some GUC variables.  (The name is thus a bit of
+ * a misnomer; perhaps it should be ExitGUCNestLevel or some such.)
  * During abort, we discard all GUC settings that were applied at nesting
  * levels >= nestLevel.  nestLevel == 1 corresponds to the main transaction.
  */
@@ -4374,11 +4376,11 @@ AtEOXact_GUC(bool isCommit, int nestLevel)
 		GucStack   *stack;
 
 		/*
-		 * Process and pop each stack entry within the nest level.	To
-		 * simplify fmgr_security_definer(), we allow failure exit from a
-		 * function-with-SET-options to be recovered at the surrounding
-		 * transaction or subtransaction abort; so there could be more than
-		 * one stack entry to pop.
+		 * Process and pop each stack entry within the nest level. To simplify
+		 * fmgr_security_definer() and other places that use GUC_ACTION_SAVE,
+		 * we allow failure exit from code that uses a local nest level to be
+		 * recovered at the surrounding transaction or subtransaction abort;
+		 * so there could be more than one stack entry to pop.
 		 */
 		while ((stack = gconf->stack) != NULL &&
 			   stack->nest_level >= nestLevel)
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index d88a4b6cfd4bc8821a7e6c90ec3fb94020af18c3..8e3057a0140093f37c3fc28854e14d34b6c6bfca 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -155,7 +155,7 @@ typedef enum
 	/* Types of set_config_option actions */
 	GUC_ACTION_SET,				/* regular SET command */
 	GUC_ACTION_LOCAL,			/* SET LOCAL command */
-	GUC_ACTION_SAVE				/* function SET option */
+	GUC_ACTION_SAVE				/* function SET option, or temp assignment */
 } GucAction;
 
 #define GUC_QUALIFIER_SEPARATOR '.'