aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/misc/guc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/misc/guc.c')
-rw-r--r--src/backend/utils/misc/guc.c716
1 files changed, 349 insertions, 367 deletions
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 678dd203315..371bc0b000f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.419 2007/09/10 02:01:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.420 2007/09/11 00:06:42 tgl Exp $
*
*--------------------------------------------------------------------
*/
@@ -422,9 +422,9 @@ const char *const config_type_names[] =
* 4. Add a record below.
*
* 5. Add it to src/backend/utils/misc/postgresql.conf.sample, if
- * appropriate
+ * appropriate.
*
- * 6. Don't forget to document the option.
+ * 6. Don't forget to document the option (at least in config.sgml).
*
* 7. If it's a new GUC_LIST option you must edit pg_dumpall.c to ensure
* it is not single quoted at dump time.
@@ -2499,7 +2499,7 @@ static int GUCNestLevel = 0; /* 1 when in main transaction */
static int guc_var_compare(const void *a, const void *b);
static int guc_name_compare(const char *namea, const char *nameb);
-static void push_old_value(struct config_generic * gconf);
+static void push_old_value(struct config_generic * gconf, GucAction action);
static void ReportGUCOption(struct config_generic * record);
static void ShowGUCConfigOption(const char *name, DestReceiver *dest);
static void ShowAllGUCConfig(DestReceiver *dest);
@@ -2568,13 +2568,12 @@ set_string_field(struct config_string * conf, char **field, char *newval)
if (oldval == NULL ||
oldval == *(conf->variable) ||
oldval == conf->reset_val ||
- oldval == conf->tentative_val ||
oldval == conf->boot_val)
return;
for (stack = conf->gen.stack; stack; stack = stack->prev)
{
- if (oldval == stack->tentative_val.stringval ||
- oldval == stack->value.stringval)
+ if (oldval == stack->prior.stringval ||
+ oldval == stack->masked.stringval)
return;
}
@@ -2592,19 +2591,71 @@ string_field_used(struct config_string * conf, char *strval)
if (strval == *(conf->variable) ||
strval == conf->reset_val ||
- strval == conf->tentative_val ||
strval == conf->boot_val)
return true;
for (stack = conf->gen.stack; stack; stack = stack->prev)
{
- if (strval == stack->tentative_val.stringval ||
- strval == stack->value.stringval)
+ if (strval == stack->prior.stringval ||
+ strval == stack->masked.stringval)
return true;
}
return false;
}
+/*
+ * Support for copying a variable's active value into a stack entry
+ */
+static void
+set_stack_value(struct config_generic * gconf, union config_var_value * val)
+{
+ switch (gconf->vartype)
+ {
+ case PGC_BOOL:
+ val->boolval =
+ *((struct config_bool *) gconf)->variable;
+ break;
+ case PGC_INT:
+ val->intval =
+ *((struct config_int *) gconf)->variable;
+ break;
+ case PGC_REAL:
+ val->realval =
+ *((struct config_real *) gconf)->variable;
+ break;
+ case PGC_STRING:
+ /* we assume stringval is NULL if not valid */
+ set_string_field((struct config_string *) gconf,
+ &(val->stringval),
+ *((struct config_string *) gconf)->variable);
+ break;
+ }
+}
+
+/*
+ * Support for discarding a no-longer-needed value in a stack entry
+ */
+static void
+discard_stack_value(struct config_generic *gconf, union config_var_value *val)
+{
+ switch (gconf->vartype)
+ {
+ case PGC_BOOL:
+ case PGC_INT:
+ case PGC_REAL:
+ /* no need to do anything */
+ break;
+ case PGC_STRING:
+ set_string_field((struct config_string *) gconf,
+ &(val->stringval),
+ NULL);
+ break;
+ }
+}
+
+/*
+ * Fetch the sorted array pointer (exported for help_config.c's use ONLY)
+ */
struct config_generic **
get_guc_variables(void)
{
@@ -2878,7 +2929,9 @@ guc_var_compare(const void *a, const void *b)
return guc_name_compare(confa->name, confb->name);
}
-
+/*
+ * the bare comparison function for GUC names
+ */
static int
guc_name_compare(const char *namea, const char *nameb)
{
@@ -2941,7 +2994,6 @@ InitializeGUCOptions(void)
gconf->status = 0;
gconf->reset_source = PGC_S_DEFAULT;
- gconf->tentative_source = PGC_S_DEFAULT;
gconf->source = PGC_S_DEFAULT;
gconf->stack = NULL;
@@ -2994,7 +3046,6 @@ InitializeGUCOptions(void)
*conf->variable = NULL;
conf->reset_val = NULL;
- conf->tentative_val = NULL;
if (conf->boot_val == NULL)
{
@@ -3260,7 +3311,7 @@ ResetAllOptions(void)
continue;
/* Save old value to support transaction abort */
- push_old_value(gconf);
+ push_old_value(gconf, GUC_ACTION_SET);
switch (gconf->vartype)
{
@@ -3273,11 +3324,7 @@ ResetAllOptions(void)
PGC_S_SESSION))
elog(ERROR, "failed to reset %s", conf->gen.name);
*conf->variable = conf->reset_val;
- conf->tentative_val = conf->reset_val;
conf->gen.source = conf->gen.reset_source;
- conf->gen.tentative_source = conf->gen.reset_source;
- conf->gen.status |= GUC_HAVE_TENTATIVE;
- guc_dirty = true;
break;
}
case PGC_INT:
@@ -3289,11 +3336,7 @@ ResetAllOptions(void)
PGC_S_SESSION))
elog(ERROR, "failed to reset %s", conf->gen.name);
*conf->variable = conf->reset_val;
- conf->tentative_val = conf->reset_val;
conf->gen.source = conf->gen.reset_source;
- conf->gen.tentative_source = conf->gen.reset_source;
- conf->gen.status |= GUC_HAVE_TENTATIVE;
- guc_dirty = true;
break;
}
case PGC_REAL:
@@ -3305,11 +3348,7 @@ ResetAllOptions(void)
PGC_S_SESSION))
elog(ERROR, "failed to reset %s", conf->gen.name);
*conf->variable = conf->reset_val;
- conf->tentative_val = conf->reset_val;
conf->gen.source = conf->gen.reset_source;
- conf->gen.tentative_source = conf->gen.reset_source;
- conf->gen.status |= GUC_HAVE_TENTATIVE;
- guc_dirty = true;
break;
}
case PGC_STRING:
@@ -3338,11 +3377,7 @@ ResetAllOptions(void)
}
set_string_field(conf, conf->variable, str);
- set_string_field(conf, &conf->tentative_val, str);
conf->gen.source = conf->gen.reset_source;
- conf->gen.tentative_source = conf->gen.reset_source;
- conf->gen.status |= GUC_HAVE_TENTATIVE;
- guc_dirty = true;
break;
}
}
@@ -3355,84 +3390,84 @@ ResetAllOptions(void)
/*
* push_old_value
- * Push previous state during first assignment to a GUC variable
- * within a particular transaction.
- *
- * We have to be willing to "back-fill" the state stack if the first
- * assignment occurs within a subtransaction nested several levels deep.
- * This ensures that if an intermediate transaction aborts, it will have
- * the proper value available to restore the setting to.
+ * Push previous state during transactional assignment to a GUC variable.
*/
static void
-push_old_value(struct config_generic * gconf)
+push_old_value(struct config_generic * gconf, GucAction action)
{
GucStack *stack;
- /* If we're not inside a transaction, do nothing */
+ /* If we're not inside a nest level, do nothing */
if (GUCNestLevel == 0)
return;
- for (;;)
+ /* Do we already have a stack entry of the current nest level? */
+ stack = gconf->stack;
+ if (stack && stack->nest_level >= GUCNestLevel)
{
- /* Done if we already pushed it at this nesting depth */
- if (gconf->stack && gconf->stack->nest_level >= GUCNestLevel)
- return;
-
- /*
- * We keep all the stack entries in TopTransactionContext so as to
- * avoid allocation problems when a subtransaction back-fills stack
- * entries for upper transaction levels.
- */
- stack = (GucStack *) MemoryContextAlloc(TopTransactionContext,
- sizeof(GucStack));
-
- stack->prev = gconf->stack;
- stack->nest_level = stack->prev ? stack->prev->nest_level + 1 : 1;
- stack->status = gconf->status;
- stack->tentative_source = gconf->tentative_source;
- stack->source = gconf->source;
-
- switch (gconf->vartype)
+ /* Yes, so adjust its state if necessary */
+ Assert(stack->nest_level == GUCNestLevel);
+ switch (action)
{
- case PGC_BOOL:
- stack->tentative_val.boolval =
- ((struct config_bool *) gconf)->tentative_val;
- stack->value.boolval =
- *((struct config_bool *) gconf)->variable;
- break;
-
- case PGC_INT:
- stack->tentative_val.intval =
- ((struct config_int *) gconf)->tentative_val;
- stack->value.intval =
- *((struct config_int *) gconf)->variable;
+ case GUC_ACTION_SET:
+ /* SET overrides any prior action at same nest level */
+ if (stack->state == GUC_SET_LOCAL)
+ {
+ /* must discard old masked value */
+ discard_stack_value(gconf, &stack->masked);
+ }
+ stack->state = GUC_SET;
break;
-
- case PGC_REAL:
- stack->tentative_val.realval =
- ((struct config_real *) gconf)->tentative_val;
- stack->value.realval =
- *((struct config_real *) gconf)->variable;
+ case GUC_ACTION_LOCAL:
+ if (stack->state == GUC_SET)
+ {
+ /* SET followed by SET LOCAL, remember SET's value */
+ set_stack_value(gconf, &stack->masked);
+ stack->state = GUC_SET_LOCAL;
+ }
+ /* in all other cases, no change to stack entry */
break;
-
- case PGC_STRING:
- stack->tentative_val.stringval =
- ((struct config_string *) gconf)->tentative_val;
- stack->value.stringval =
- *((struct config_string *) gconf)->variable;
+ case GUC_ACTION_SAVE:
+ /* Could only have a prior SAVE of same variable */
+ Assert(stack->state == GUC_SAVE);
break;
}
+ Assert(guc_dirty); /* must be set already */
+ return;
+ }
- gconf->stack = stack;
-
- /* Set state to indicate nothing happened yet within this level */
- gconf->status = GUC_HAVE_STACK;
+ /*
+ * Push a new stack entry
+ *
+ * We keep all the stack entries in TopTransactionContext for simplicity.
+ */
+ stack = (GucStack *) MemoryContextAllocZero(TopTransactionContext,
+ sizeof(GucStack));
- /* Ensure we remember to pop at end of xact */
- guc_dirty = true;
+ stack->prev = gconf->stack;
+ stack->nest_level = GUCNestLevel;
+ switch (action)
+ {
+ case GUC_ACTION_SET:
+ stack->state = GUC_SET;
+ break;
+ case GUC_ACTION_LOCAL:
+ stack->state = GUC_LOCAL;
+ break;
+ case GUC_ACTION_SAVE:
+ stack->state = GUC_SAVE;
+ break;
}
+ stack->source = gconf->source;
+ set_stack_value(gconf, &stack->prior);
+
+ gconf->stack = stack;
+
+ /* Ensure we remember to pop at end of xact */
+ guc_dirty = true;
}
+
/*
* Do GUC processing at main transaction start.
*/
@@ -3471,6 +3506,7 @@ NewGUCNestLevel(void)
void
AtEOXact_GUC(bool isCommit, int nestLevel)
{
+ bool still_dirty;
int i;
Assert(nestLevel > 0 && nestLevel <= GUCNestLevel);
@@ -3482,246 +3518,236 @@ AtEOXact_GUC(bool isCommit, int nestLevel)
return;
}
+ still_dirty = false;
for (i = 0; i < num_guc_variables; i++)
{
struct config_generic *gconf = guc_variables[i];
- int my_status = gconf->status;
- GucStack *stack = gconf->stack;
- bool useTentative;
- bool changed;
+ GucStack *stack;
/*
- * Skip if nothing's happened to this var in this transaction
+ * 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.
*/
- if ((my_status & (GUC_HAVE_TENTATIVE |
- GUC_HAVE_LOCAL |
- GUC_HAVE_STACK)) == 0)
+ while ((stack = gconf->stack) != NULL &&
+ stack->nest_level >= nestLevel)
{
- Assert(stack == NULL);
- continue;
- }
- /* Assert that we stacked old value before changing it */
- Assert(stack != NULL && (my_status & GUC_HAVE_STACK));
- /* However, the last change may have been at an outer xact level */
- if (stack->nest_level < nestLevel)
- continue;
- Assert(stack->nest_level == nestLevel);
-
- /*
- * We will pop the stack entry. Start by restoring outer xact status
- * (since we may want to modify it below). Be careful to use
- * my_status to reference the inner xact status below this point...
- */
- gconf->status = stack->status;
-
- /*
- * We have two cases:
- *
- * If commit and HAVE_TENTATIVE, set actual value to tentative (this
- * is to override a SET LOCAL if one occurred later than SET). We keep
- * the tentative value and propagate HAVE_TENTATIVE to the parent
- * status, allowing the SET's effect to percolate up. (But if we're
- * exiting the outermost transaction, we'll drop the HAVE_TENTATIVE
- * bit below.)
- *
- * Otherwise, we have a transaction that aborted or executed only SET
- * LOCAL (or no SET at all). In either case it should have no further
- * effect, so restore both tentative and actual values from the stack
- * entry.
- */
+ GucStack *prev = stack->prev;
+ bool restorePrior = false;
+ bool restoreMasked = false;
+ bool changed;
- useTentative = isCommit && (my_status & GUC_HAVE_TENTATIVE) != 0;
- changed = false;
-
- switch (gconf->vartype)
- {
- case PGC_BOOL:
+ /*
+ * In this next bit, if we don't set either restorePrior or
+ * restoreMasked, we must "discard" any unwanted fields of the
+ * stack entries to avoid leaking memory. If we do set one of
+ * those flags, unused fields will be cleaned up after restoring.
+ */
+ if (!isCommit) /* if abort, always restore prior value */
+ restorePrior = true;
+ else if (stack->state == GUC_SAVE)
+ restorePrior = true;
+ else if (stack->nest_level == 1)
+ {
+ /* transaction commit */
+ if (stack->state == GUC_SET_LOCAL)
+ restoreMasked = true;
+ else if (stack->state == GUC_SET)
{
- struct config_bool *conf = (struct config_bool *) gconf;
- bool newval;
- GucSource newsource;
+ /* we keep the current active value */
+ discard_stack_value(gconf, &stack->prior);
+ }
+ else /* must be GUC_LOCAL */
+ restorePrior = true;
+ }
+ else if (prev == NULL ||
+ prev->nest_level < stack->nest_level - 1)
+ {
+ /* decrement entry's level and do not pop it */
+ stack->nest_level--;
+ continue;
+ }
+ else
+ {
+ /*
+ * We have to merge this stack entry into prev.
+ * See README for discussion of this bit.
+ */
+ switch (stack->state)
+ {
+ case GUC_SAVE:
+ Assert(false); /* can't get here */
+
+ case GUC_SET:
+ /* next level always becomes SET */
+ discard_stack_value(gconf, &stack->prior);
+ if (prev->state == GUC_SET_LOCAL)
+ discard_stack_value(gconf, &prev->masked);
+ prev->state = GUC_SET;
+ break;
- if (useTentative)
- {
- newval = conf->tentative_val;
- newsource = conf->gen.tentative_source;
- conf->gen.status |= GUC_HAVE_TENTATIVE;
- }
- else
- {
- newval = stack->value.boolval;
- newsource = stack->source;
- conf->tentative_val = stack->tentative_val.boolval;
- conf->gen.tentative_source = stack->tentative_source;
- }
+ case GUC_LOCAL:
+ if (prev->state == GUC_SET)
+ {
+ /* LOCAL migrates down */
+ prev->masked = stack->prior;
+ prev->state = GUC_SET_LOCAL;
+ }
+ else
+ {
+ /* else just forget this stack level */
+ discard_stack_value(gconf, &stack->prior);
+ }
+ break;
- if (*conf->variable != newval)
- {
- if (conf->assign_hook)
- if (!(*conf->assign_hook) (newval,
- true, PGC_S_OVERRIDE))
- elog(LOG, "failed to commit %s",
- conf->gen.name);
- *conf->variable = newval;
- changed = true;
- }
- conf->gen.source = newsource;
- break;
+ case GUC_SET_LOCAL:
+ /* prior state at this level no longer wanted */
+ discard_stack_value(gconf, &stack->prior);
+ /* copy down the masked state */
+ if (prev->state == GUC_SET_LOCAL)
+ discard_stack_value(gconf, &prev->masked);
+ prev->masked = stack->masked;
+ prev->state = GUC_SET_LOCAL;
+ break;
}
- case PGC_INT:
- {
- struct config_int *conf = (struct config_int *) gconf;
- int newval;
- GucSource newsource;
+ }
- if (useTentative)
- {
- newval = conf->tentative_val;
- newsource = conf->gen.tentative_source;
- conf->gen.status |= GUC_HAVE_TENTATIVE;
- }
- else
- {
- newval = stack->value.intval;
- newsource = stack->source;
- conf->tentative_val = stack->tentative_val.intval;
- conf->gen.tentative_source = stack->tentative_source;
- }
+ changed = false;
- if (*conf->variable != newval)
- {
- if (conf->assign_hook)
- if (!(*conf->assign_hook) (newval,
- true, PGC_S_OVERRIDE))
- elog(LOG, "failed to commit %s",
- conf->gen.name);
- *conf->variable = newval;
- changed = true;
- }
- conf->gen.source = newsource;
- break;
+ if (restorePrior || restoreMasked)
+ {
+ /* Perform appropriate restoration of the stacked value */
+ union config_var_value newvalue;
+ GucSource newsource;
+
+ if (restoreMasked)
+ {
+ newvalue = stack->masked;
+ newsource = PGC_S_SESSION;
}
- case PGC_REAL:
+ else
{
- struct config_real *conf = (struct config_real *) gconf;
- double newval;
- GucSource newsource;
+ newvalue = stack->prior;
+ newsource = stack->source;
+ }
- if (useTentative)
+ switch (gconf->vartype)
+ {
+ case PGC_BOOL:
{
- newval = conf->tentative_val;
- newsource = conf->gen.tentative_source;
- conf->gen.status |= GUC_HAVE_TENTATIVE;
+ struct config_bool *conf = (struct config_bool *) gconf;
+ bool newval = newvalue.boolval;
+
+ if (*conf->variable != newval)
+ {
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (newval,
+ true, PGC_S_OVERRIDE))
+ elog(LOG, "failed to commit %s",
+ conf->gen.name);
+ *conf->variable = newval;
+ changed = true;
+ }
+ break;
}
- else
+ case PGC_INT:
{
- newval = stack->value.realval;
- newsource = stack->source;
- conf->tentative_val = stack->tentative_val.realval;
- conf->gen.tentative_source = stack->tentative_source;
- }
+ struct config_int *conf = (struct config_int *) gconf;
+ int newval = newvalue.intval;
- if (*conf->variable != newval)
- {
- if (conf->assign_hook)
- if (!(*conf->assign_hook) (newval,
- true, PGC_S_OVERRIDE))
- elog(LOG, "failed to commit %s",
- conf->gen.name);
- *conf->variable = newval;
- changed = true;
+ if (*conf->variable != newval)
+ {
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (newval,
+ true, PGC_S_OVERRIDE))
+ elog(LOG, "failed to commit %s",
+ conf->gen.name);
+ *conf->variable = newval;
+ changed = true;
+ }
+ break;
}
- conf->gen.source = newsource;
- break;
- }
- case PGC_STRING:
- {
- struct config_string *conf = (struct config_string *) gconf;
- char *newval;
- GucSource newsource;
-
- if (useTentative)
+ case PGC_REAL:
{
- newval = conf->tentative_val;
- newsource = conf->gen.tentative_source;
- conf->gen.status |= GUC_HAVE_TENTATIVE;
+ struct config_real *conf = (struct config_real *) gconf;
+ double newval = newvalue.realval;
+
+ if (*conf->variable != newval)
+ {
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (newval,
+ true, PGC_S_OVERRIDE))
+ elog(LOG, "failed to commit %s",
+ conf->gen.name);
+ *conf->variable = newval;
+ changed = true;
+ }
+ break;
}
- else
+ case PGC_STRING:
{
- newval = stack->value.stringval;
- newsource = stack->source;
- set_string_field(conf, &conf->tentative_val,
- stack->tentative_val.stringval);
- conf->gen.tentative_source = stack->tentative_source;
- }
+ struct config_string *conf = (struct config_string *) gconf;
+ char *newval = newvalue.stringval;
- if (*conf->variable != newval)
- {
- if (conf->assign_hook && newval)
+ if (*conf->variable != newval)
{
- const char *newstr;
-
- newstr = (*conf->assign_hook) (newval, true,
- PGC_S_OVERRIDE);
- if (newstr == NULL)
- elog(LOG, "failed to commit %s",
- conf->gen.name);
- else if (newstr != newval)
+ if (conf->assign_hook && newval)
{
- /*
- * If newval should now be freed, it'll be
- * taken care of below.
- *
- * See notes in set_config_option about
- * casting
- */
- newval = (char *) newstr;
+ const char *newstr;
+
+ newstr = (*conf->assign_hook) (newval, true,
+ PGC_S_OVERRIDE);
+ if (newstr == NULL)
+ elog(LOG, "failed to commit %s",
+ conf->gen.name);
+ else if (newstr != newval)
+ {
+ /*
+ * If newval should now be freed, it'll be
+ * taken care of below.
+ *
+ * See notes in set_config_option about
+ * casting
+ */
+ newval = (char *) newstr;
+ }
}
- }
- set_string_field(conf, conf->variable, newval);
- changed = true;
+ set_string_field(conf, conf->variable, newval);
+ changed = true;
+ }
+ /*
+ * Release stacked values if not used anymore.
+ * We could use discard_stack_value() here, but since
+ * we have type-specific code anyway, might as well
+ * inline it.
+ */
+ set_string_field(conf, &stack->prior.stringval, NULL);
+ set_string_field(conf, &stack->masked.stringval, NULL);
+ break;
}
- conf->gen.source = newsource;
- /* Release stacked values if not used anymore */
- set_string_field(conf, &stack->value.stringval,
- NULL);
- set_string_field(conf, &stack->tentative_val.stringval,
- NULL);
- /* Don't store tentative value separately after commit */
- if (nestLevel == 1)
- set_string_field(conf, &conf->tentative_val, NULL);
- break;
}
- }
- /* Finish popping the state stack */
- gconf->stack = stack->prev;
- pfree(stack);
+ gconf->source = newsource;
+ }
- /*
- * If we're now out of all xact levels, forget TENTATIVE status bit;
- * there's nothing tentative about the value anymore.
- */
- if (nestLevel == 1)
- {
- Assert(gconf->stack == NULL);
- gconf->status = 0;
- }
+ /* Finish popping the state stack */
+ gconf->stack = prev;
+ pfree(stack);
- /* Report new value if we changed it */
- if (changed && (gconf->flags & GUC_REPORT))
- ReportGUCOption(gconf);
+ /* Report new value if we changed it */
+ if (changed && (gconf->flags & GUC_REPORT))
+ ReportGUCOption(gconf);
+ } /* end of stack-popping loop */
+
+ if (stack != NULL)
+ still_dirty = true;
}
- /*
- * If we're now out of all xact levels, we can clear guc_dirty. (Note: we
- * cannot reset guc_dirty when exiting a subtransaction, because we know
- * that all outer transaction levels will have stacked values to deal
- * with.)
- */
- if (nestLevel == 1)
- guc_dirty = false;
+ /* If there are no remaining stack entries, we can reset guc_dirty */
+ guc_dirty = still_dirty;
/* Update nesting level */
GUCNestLevel = nestLevel - 1;
@@ -4123,8 +4149,13 @@ call_string_assign_hook(GucStringAssignHook assign_hook,
* function is being called so it can apply the access restrictions
* properly.
*
- * If value is NULL, set the option to its default value. If the
- * parameter changeVal is false then don't really set the option but do all
+ * If value is NULL, set the option to its default value (normally the
+ * reset_val, but if source == PGC_S_DEFAULT we instead use the boot_val).
+ *
+ * action indicates whether to set the value globally in the session, locally
+ * to the current top transaction, or just for the duration of a function call.
+ *
+ * If changeVal is false then don't really set the option but do all
* the checks to see if it would work.
*
* If there is an error (non-existing option, invalid value) then an
@@ -4141,7 +4172,7 @@ call_string_assign_hook(GucStringAssignHook assign_hook,
bool
set_config_option(const char *name, const char *value,
GucContext context, GucSource source,
- bool isLocal, bool changeVal)
+ GucAction action, bool changeVal)
{
struct config_generic *record;
int elevel;
@@ -4306,9 +4337,6 @@ set_config_option(const char *name, const char *value,
/*
* Evaluate value and set variable.
- *
- * Note: if value == NULL then we are supposed to set to the reset_val,
- * except when source == PGC_S_DEFAULT; then we set to the boot_val.
*/
switch (record->vartype)
{
@@ -4350,7 +4378,7 @@ set_config_option(const char *name, const char *value,
{
/* Save old value to support transaction abort */
if (!makeDefault)
- push_old_value(&conf->gen);
+ push_old_value(&conf->gen, action);
if (changeVal)
{
*conf->variable = newval;
@@ -4369,23 +4397,11 @@ set_config_option(const char *name, const char *value,
{
if (stack->source <= source)
{
- stack->value.boolval = newval;
+ stack->prior.boolval = newval;
stack->source = source;
}
}
}
- else if (isLocal)
- {
- conf->gen.status |= GUC_HAVE_LOCAL;
- guc_dirty = true;
- }
- else
- {
- conf->tentative_val = newval;
- conf->gen.tentative_source = source;
- conf->gen.status |= GUC_HAVE_TENTATIVE;
- guc_dirty = true;
- }
}
break;
}
@@ -4439,7 +4455,7 @@ set_config_option(const char *name, const char *value,
{
/* Save old value to support transaction abort */
if (!makeDefault)
- push_old_value(&conf->gen);
+ push_old_value(&conf->gen, action);
if (changeVal)
{
*conf->variable = newval;
@@ -4458,23 +4474,11 @@ set_config_option(const char *name, const char *value,
{
if (stack->source <= source)
{
- stack->value.intval = newval;
+ stack->prior.intval = newval;
stack->source = source;
}
}
}
- else if (isLocal)
- {
- conf->gen.status |= GUC_HAVE_LOCAL;
- guc_dirty = true;
- }
- else
- {
- conf->tentative_val = newval;
- conf->gen.tentative_source = source;
- conf->gen.status |= GUC_HAVE_TENTATIVE;
- guc_dirty = true;
- }
}
break;
}
@@ -4525,7 +4529,7 @@ set_config_option(const char *name, const char *value,
{
/* Save old value to support transaction abort */
if (!makeDefault)
- push_old_value(&conf->gen);
+ push_old_value(&conf->gen, action);
if (changeVal)
{
*conf->variable = newval;
@@ -4544,23 +4548,11 @@ set_config_option(const char *name, const char *value,
{
if (stack->source <= source)
{
- stack->value.realval = newval;
+ stack->prior.realval = newval;
stack->source = source;
}
}
}
- else if (isLocal)
- {
- conf->gen.status |= GUC_HAVE_LOCAL;
- guc_dirty = true;
- }
- else
- {
- conf->tentative_val = newval;
- conf->gen.tentative_source = source;
- conf->gen.status |= GUC_HAVE_TENTATIVE;
- guc_dirty = true;
- }
}
break;
}
@@ -4653,7 +4645,7 @@ set_config_option(const char *name, const char *value,
{
/* Save old value to support transaction abort */
if (!makeDefault)
- push_old_value(&conf->gen);
+ push_old_value(&conf->gen, action);
if (changeVal)
{
set_string_field(conf, conf->variable, newval);
@@ -4672,7 +4664,7 @@ set_config_option(const char *name, const char *value,
{
if (stack->source <= source)
{
- set_string_field(conf, &stack->value.stringval,
+ set_string_field(conf, &stack->prior.stringval,
newval);
stack->source = source;
}
@@ -4681,18 +4673,6 @@ set_config_option(const char *name, const char *value,
if (newval && !string_field_used(conf, newval))
free(newval);
}
- else if (isLocal)
- {
- conf->gen.status |= GUC_HAVE_LOCAL;
- guc_dirty = true;
- }
- else
- {
- set_string_field(conf, &conf->tentative_val, newval);
- conf->gen.tentative_source = source;
- conf->gen.status |= GUC_HAVE_TENTATIVE;
- guc_dirty = true;
- }
}
else if (newval)
free(newval);
@@ -4716,7 +4696,8 @@ void
SetConfigOption(const char *name, const char *value,
GucContext context, GucSource source)
{
- (void) set_config_option(name, value, context, source, false, true);
+ (void) set_config_option(name, value, context, source,
+ GUC_ACTION_SET, true);
}
@@ -4942,6 +4923,8 @@ flatten_set_variable_args(const char *name, List *args)
void
ExecSetVariableStmt(VariableSetStmt *stmt)
{
+ GucAction action = stmt->is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET;
+
switch (stmt->kind)
{
case VAR_SET_VALUE:
@@ -4950,7 +4933,7 @@ ExecSetVariableStmt(VariableSetStmt *stmt)
ExtractSetVariableArgs(stmt),
(superuser() ? PGC_SUSET : PGC_USERSET),
PGC_S_SESSION,
- stmt->is_local,
+ action,
true);
break;
case VAR_SET_MULTI:
@@ -5006,7 +4989,7 @@ ExecSetVariableStmt(VariableSetStmt *stmt)
NULL,
(superuser() ? PGC_SUSET : PGC_USERSET),
PGC_S_SESSION,
- stmt->is_local,
+ action,
true);
break;
case VAR_RESET_ALL:
@@ -5051,7 +5034,7 @@ SetPGVariable(const char *name, List *args, bool is_local)
argstring,
(superuser() ? PGC_SUSET : PGC_USERSET),
PGC_S_SESSION,
- is_local,
+ is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
true);
}
@@ -5095,7 +5078,7 @@ set_config_by_name(PG_FUNCTION_ARGS)
value,
(superuser() ? PGC_SUSET : PGC_USERSET),
PGC_S_SESSION,
- is_local,
+ is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
true);
/* get the new current value */
@@ -5190,7 +5173,7 @@ define_custom_variable(struct config_generic *variable)
if (value)
set_config_option(name, value,
pHolder->gen.context, pHolder->gen.source,
- false, true);
+ GUC_ACTION_SET, true);
/*
* Free up as much as we conveniently can of the placeholder structure
@@ -5198,7 +5181,6 @@ define_custom_variable(struct config_generic *variable)
*/
set_string_field(pHolder, pHolder->variable, NULL);
set_string_field(pHolder, &pHolder->reset_val, NULL);
- set_string_field(pHolder, &pHolder->tentative_val, NULL);
free(pHolder);
}
@@ -6145,7 +6127,7 @@ read_nondefault_variables(void)
elog(FATAL, "invalid format of exec config params file");
(void) set_config_option(varname, varvalue, record->context,
- varsource, false, true);
+ varsource, GUC_ACTION_SET, true);
free(varname);
free(varvalue);
}
@@ -6196,13 +6178,13 @@ ParseLongOption(const char *string, char **name, char **value)
/*
* Handle options fetched from pg_database.datconfig, pg_authid.rolconfig,
- * pg_proc.proconfig, etc. Caller must specify proper context/source/local.
+ * pg_proc.proconfig, etc. Caller must specify proper context/source/action.
*
* The array parameter must be an array of TEXT (it must not be NULL).
*/
void
ProcessGUCArray(ArrayType *array,
- GucContext context, GucSource source, bool isLocal)
+ GucContext context, GucSource source, GucAction action)
{
int i;
@@ -6242,7 +6224,7 @@ ProcessGUCArray(ArrayType *array,
continue;
}
- (void) set_config_option(name, value, context, source, isLocal, true);
+ (void) set_config_option(name, value, context, source, action, true);
free(name);
if (value)
@@ -6269,7 +6251,7 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value)
/* test if the option is valid */
set_config_option(name, value,
superuser() ? PGC_SUSET : PGC_USERSET,
- PGC_S_TEST, false, false);
+ PGC_S_TEST, GUC_ACTION_SET, false);
/* convert name to canonical spelling, so we can use plain strcmp */
(void) GetConfigOptionByName(name, &varname);
@@ -6347,7 +6329,7 @@ GUCArrayDelete(ArrayType *array, const char *name)
/* test if the option is valid */
set_config_option(name, NULL,
superuser() ? PGC_SUSET : PGC_USERSET,
- PGC_S_TEST, false, false);
+ PGC_S_TEST, GUC_ACTION_SET, false);
/* convert name to canonical spelling, so we can use plain strcmp */
(void) GetConfigOptionByName(name, &varname);