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;
 
     * 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);
-
-   save_log_min_messages =
-       pstrdup(GetConfigOption("log_min_messages", false, false));
+                                GUC_ACTION_SAVE, true);
    if (log_min_messages < WARNING)
        (void) set_config_option("log_min_messages", "warning",
                                 PGC_SUSET, PGC_S_SESSION,
-                                GUC_ACTION_LOCAL, true);
+                                GUC_ACTION_SAVE, true);
 
    /*
     * Set up the search path to contain the target schema, then the schemas
     *
     * 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)
 
    (void) set_config_option("search_path", pathbuf.data,
                             PGC_USERSET, PGC_S_SESSION,
-                            GUC_ACTION_LOCAL, true);
+                            GUC_ACTION_SAVE, true);
 
    /*
     * Set creating_extension and related variables so that
    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);
-   (void) set_config_option("client_min_messages", save_client_min_messages,
-                            PGC_USERSET, PGC_S_SESSION,
-                            GUC_ACTION_LOCAL, true);
-   (void) set_config_option("log_min_messages", save_log_min_messages,
-                            PGC_SUSET, PGC_S_SESSION,
-                            GUC_ACTION_LOCAL, true);
+   AtEOXact_GUC(true, save_nestlevel);
 }
 
 /*
 
    RangeTblEntry *fkrte;
    const char *sep;
    int         i;
-   int         old_work_mem;
+   int         save_nestlevel;
    char        workmembuf[32];
    int         spi_result;
    SPIPlanPtr  qplan;
     * 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);
+                            GUC_ACTION_SAVE, true);
 
    if (SPI_connect() != SPI_OK_CONNECT)
        elog(ERROR, "SPI_connect failed");
        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);
+   AtEOXact_GUC(true, save_nestlevel);
 
    return true;
 }
 
 
 /*
  * 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)
 
 /*
  * 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.
  */
        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)