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, 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
*
* 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, 0);
+ GUC_ACTION_SAVE, true, 0);
/*
* 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, 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);
}
/*
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, 0);
+ GUC_ACTION_SAVE, true, 0);
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, 0);
+ 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)