|
|
|
@ -3260,6 +3260,11 @@ static void InitializeGUCOptionsFromEnvironment(void);
|
|
|
|
|
static void InitializeOneGUCOption(struct config_generic * gconf);
|
|
|
|
|
static void push_old_value(struct config_generic * gconf, GucAction action);
|
|
|
|
|
static void ReportGUCOption(struct config_generic * record);
|
|
|
|
|
static void reapply_stacked_values(struct config_generic * variable,
|
|
|
|
|
struct config_string *pHolder,
|
|
|
|
|
GucStack *stack,
|
|
|
|
|
const char *curvalue,
|
|
|
|
|
GucContext curscontext, GucSource cursource);
|
|
|
|
|
static void ShowGUCConfigOption(const char *name, DestReceiver *dest);
|
|
|
|
|
static void ShowAllGUCConfig(DestReceiver *dest);
|
|
|
|
|
static char *_ShowOption(struct config_generic * record, bool use_units);
|
|
|
|
@ -5020,6 +5025,10 @@ config_enum_get_options(struct config_enum * record, const char *prefix,
|
|
|
|
|
* If changeVal is false then don't really set the option but do all
|
|
|
|
|
* the checks to see if it would work.
|
|
|
|
|
*
|
|
|
|
|
* elevel should normally be passed as zero, allowing this function to make
|
|
|
|
|
* its standard choice of ereport level. However some callers need to be
|
|
|
|
|
* able to override that choice; they should pass the ereport level to use.
|
|
|
|
|
*
|
|
|
|
|
* Return value:
|
|
|
|
|
* +1: the value is valid and was successfully applied.
|
|
|
|
|
* 0: the name or value is invalid (but see below).
|
|
|
|
@ -5028,34 +5037,37 @@ config_enum_get_options(struct config_enum * record, const char *prefix,
|
|
|
|
|
* If there is an error (non-existing option, invalid value) then an
|
|
|
|
|
* ereport(ERROR) is thrown *unless* this is called for a source for which
|
|
|
|
|
* we don't want an ERROR (currently, those are defaults, the config file,
|
|
|
|
|
* and per-database or per-user settings). In those cases we write a
|
|
|
|
|
* suitable error message via ereport() and return 0.
|
|
|
|
|
* and per-database or per-user settings, as well as callers who specify
|
|
|
|
|
* a less-than-ERROR elevel). In those cases we write a suitable error
|
|
|
|
|
* message via ereport() and return 0.
|
|
|
|
|
*
|
|
|
|
|
* See also SetConfigOption for an external interface.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
set_config_option(const char *name, const char *value,
|
|
|
|
|
GucContext context, GucSource source,
|
|
|
|
|
GucAction action, bool changeVal)
|
|
|
|
|
GucAction action, bool changeVal, int elevel)
|
|
|
|
|
{
|
|
|
|
|
struct config_generic *record;
|
|
|
|
|
int elevel;
|
|
|
|
|
bool prohibitValueChange = false;
|
|
|
|
|
bool makeDefault;
|
|
|
|
|
|
|
|
|
|
if (source == PGC_S_DEFAULT || source == PGC_S_FILE)
|
|
|
|
|
if (elevel == 0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* To avoid cluttering the log, only the postmaster bleats loudly
|
|
|
|
|
* about problems with the config file.
|
|
|
|
|
*/
|
|
|
|
|
elevel = IsUnderPostmaster ? DEBUG3 : LOG;
|
|
|
|
|
if (source == PGC_S_DEFAULT || source == PGC_S_FILE)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* To avoid cluttering the log, only the postmaster bleats loudly
|
|
|
|
|
* about problems with the config file.
|
|
|
|
|
*/
|
|
|
|
|
elevel = IsUnderPostmaster ? DEBUG3 : LOG;
|
|
|
|
|
}
|
|
|
|
|
else if (source == PGC_S_DATABASE || source == PGC_S_USER ||
|
|
|
|
|
source == PGC_S_DATABASE_USER)
|
|
|
|
|
elevel = WARNING;
|
|
|
|
|
else
|
|
|
|
|
elevel = ERROR;
|
|
|
|
|
}
|
|
|
|
|
else if (source == PGC_S_DATABASE || source == PGC_S_USER ||
|
|
|
|
|
source == PGC_S_DATABASE_USER)
|
|
|
|
|
elevel = WARNING;
|
|
|
|
|
else
|
|
|
|
|
elevel = ERROR;
|
|
|
|
|
|
|
|
|
|
record = find_option(name, true, elevel);
|
|
|
|
|
if (record == NULL)
|
|
|
|
@ -5798,9 +5810,11 @@ set_config_sourcefile(const char *name, char *sourcefile, int sourceline)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set a config option to the given value. See also set_config_option,
|
|
|
|
|
* this is just the wrapper to be called from outside GUC. NB: this
|
|
|
|
|
* is used only for non-transactional operations.
|
|
|
|
|
* Set a config option to the given value.
|
|
|
|
|
*
|
|
|
|
|
* See also set_config_option; this is just the wrapper to be called from
|
|
|
|
|
* outside GUC. (This function should be used when possible, because its API
|
|
|
|
|
* is more stable than set_config_option's.)
|
|
|
|
|
*
|
|
|
|
|
* Note: there is no support here for setting source file/line, as it
|
|
|
|
|
* is currently not needed.
|
|
|
|
@ -5810,7 +5824,7 @@ SetConfigOption(const char *name, const char *value,
|
|
|
|
|
GucContext context, GucSource source)
|
|
|
|
|
{
|
|
|
|
|
(void) set_config_option(name, value, context, source,
|
|
|
|
|
GUC_ACTION_SET, true);
|
|
|
|
|
GUC_ACTION_SET, true, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -6072,7 +6086,8 @@ ExecSetVariableStmt(VariableSetStmt *stmt)
|
|
|
|
|
(superuser() ? PGC_SUSET : PGC_USERSET),
|
|
|
|
|
PGC_S_SESSION,
|
|
|
|
|
action,
|
|
|
|
|
true);
|
|
|
|
|
true,
|
|
|
|
|
0);
|
|
|
|
|
break;
|
|
|
|
|
case VAR_SET_MULTI:
|
|
|
|
|
|
|
|
|
@ -6135,7 +6150,8 @@ ExecSetVariableStmt(VariableSetStmt *stmt)
|
|
|
|
|
(superuser() ? PGC_SUSET : PGC_USERSET),
|
|
|
|
|
PGC_S_SESSION,
|
|
|
|
|
action,
|
|
|
|
|
true);
|
|
|
|
|
true,
|
|
|
|
|
0);
|
|
|
|
|
break;
|
|
|
|
|
case VAR_RESET_ALL:
|
|
|
|
|
ResetAllOptions();
|
|
|
|
@ -6180,7 +6196,8 @@ SetPGVariable(const char *name, List *args, bool is_local)
|
|
|
|
|
(superuser() ? PGC_SUSET : PGC_USERSET),
|
|
|
|
|
PGC_S_SESSION,
|
|
|
|
|
is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
|
|
|
|
|
true);
|
|
|
|
|
true,
|
|
|
|
|
0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -6223,7 +6240,8 @@ set_config_by_name(PG_FUNCTION_ARGS)
|
|
|
|
|
(superuser() ? PGC_SUSET : PGC_USERSET),
|
|
|
|
|
PGC_S_SESSION,
|
|
|
|
|
is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
|
|
|
|
|
true);
|
|
|
|
|
true,
|
|
|
|
|
0);
|
|
|
|
|
|
|
|
|
|
/* get the new current value */
|
|
|
|
|
new_value = GetConfigOptionByName(name, NULL);
|
|
|
|
@ -6282,7 +6300,6 @@ define_custom_variable(struct config_generic * variable)
|
|
|
|
|
{
|
|
|
|
|
const char *name = variable->name;
|
|
|
|
|
const char **nameAddr = &name;
|
|
|
|
|
const char *value;
|
|
|
|
|
struct config_string *pHolder;
|
|
|
|
|
struct config_generic **res;
|
|
|
|
|
|
|
|
|
@ -6330,30 +6347,40 @@ define_custom_variable(struct config_generic * variable)
|
|
|
|
|
*res = variable;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Assign the string value stored in the placeholder to the real variable.
|
|
|
|
|
* Assign the string value(s) stored in the placeholder to the real
|
|
|
|
|
* variable. Essentially, we need to duplicate all the active and stacked
|
|
|
|
|
* values, but with appropriate validation and datatype adjustment.
|
|
|
|
|
*
|
|
|
|
|
* XXX this is not really good enough --- it should be a nontransactional
|
|
|
|
|
* assignment, since we don't want it to roll back if the current xact
|
|
|
|
|
* fails later. (Or do we?)
|
|
|
|
|
* If an assignment fails, we report a WARNING and keep going. We don't
|
|
|
|
|
* want to throw ERROR for bad values, because it'd bollix the add-on
|
|
|
|
|
* module that's presumably halfway through getting loaded. In such cases
|
|
|
|
|
* the default or previous state will become active instead.
|
|
|
|
|
*/
|
|
|
|
|
value = *pHolder->variable;
|
|
|
|
|
|
|
|
|
|
if (value)
|
|
|
|
|
{
|
|
|
|
|
if (set_config_option(name, value,
|
|
|
|
|
pHolder->gen.scontext, pHolder->gen.source,
|
|
|
|
|
GUC_ACTION_SET, true) != 0)
|
|
|
|
|
{
|
|
|
|
|
/* Also copy over any saved source-location information */
|
|
|
|
|
if (pHolder->gen.sourcefile)
|
|
|
|
|
set_config_sourcefile(name, pHolder->gen.sourcefile,
|
|
|
|
|
pHolder->gen.sourceline);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* First, apply the reset value if any */
|
|
|
|
|
if (pHolder->reset_val)
|
|
|
|
|
(void) set_config_option(name, pHolder->reset_val,
|
|
|
|
|
pHolder->gen.reset_scontext,
|
|
|
|
|
pHolder->gen.reset_source,
|
|
|
|
|
GUC_ACTION_SET, true, WARNING);
|
|
|
|
|
/* That should not have resulted in stacking anything */
|
|
|
|
|
Assert(variable->stack == NULL);
|
|
|
|
|
|
|
|
|
|
/* Now, apply current and stacked values, in the order they were stacked */
|
|
|
|
|
reapply_stacked_values(variable, pHolder, pHolder->gen.stack,
|
|
|
|
|
*(pHolder->variable),
|
|
|
|
|
pHolder->gen.scontext, pHolder->gen.source);
|
|
|
|
|
|
|
|
|
|
/* Also copy over any saved source-location information */
|
|
|
|
|
if (pHolder->gen.sourcefile)
|
|
|
|
|
set_config_sourcefile(name, pHolder->gen.sourcefile,
|
|
|
|
|
pHolder->gen.sourceline);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Free up as much as we conveniently can of the placeholder structure
|
|
|
|
|
* (this neglects any stack items...)
|
|
|
|
|
* Free up as much as we conveniently can of the placeholder structure.
|
|
|
|
|
* (This neglects any stack items, so it's possible for some memory to be
|
|
|
|
|
* leaked. Since this can only happen once per session per variable, it
|
|
|
|
|
* doesn't seem worth spending much code on.)
|
|
|
|
|
*/
|
|
|
|
|
set_string_field(pHolder, pHolder->variable, NULL);
|
|
|
|
|
set_string_field(pHolder, &pHolder->reset_val, NULL);
|
|
|
|
@ -6361,6 +6388,89 @@ define_custom_variable(struct config_generic * variable)
|
|
|
|
|
free(pHolder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Recursive subroutine for define_custom_variable: reapply non-reset values
|
|
|
|
|
*
|
|
|
|
|
* We recurse so that the values are applied in the same order as originally.
|
|
|
|
|
* At each recursion level, apply the upper-level value (passed in) in the
|
|
|
|
|
* fashion implied by the stack entry.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
reapply_stacked_values(struct config_generic * variable,
|
|
|
|
|
struct config_string *pHolder,
|
|
|
|
|
GucStack *stack,
|
|
|
|
|
const char *curvalue,
|
|
|
|
|
GucContext curscontext, GucSource cursource)
|
|
|
|
|
{
|
|
|
|
|
const char *name = variable->name;
|
|
|
|
|
GucStack *oldvarstack = variable->stack;
|
|
|
|
|
|
|
|
|
|
if (stack != NULL)
|
|
|
|
|
{
|
|
|
|
|
/* First, recurse, so that stack items are processed bottom to top */
|
|
|
|
|
reapply_stacked_values(variable, pHolder, stack->prev,
|
|
|
|
|
stack->prior.val.stringval,
|
|
|
|
|
stack->scontext, stack->source);
|
|
|
|
|
|
|
|
|
|
/* See how to apply the passed-in value */
|
|
|
|
|
switch (stack->state)
|
|
|
|
|
{
|
|
|
|
|
case GUC_SAVE:
|
|
|
|
|
(void) set_config_option(name, curvalue,
|
|
|
|
|
curscontext, cursource,
|
|
|
|
|
GUC_ACTION_SAVE, true, WARNING);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GUC_SET:
|
|
|
|
|
(void) set_config_option(name, curvalue,
|
|
|
|
|
curscontext, cursource,
|
|
|
|
|
GUC_ACTION_SET, true, WARNING);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GUC_LOCAL:
|
|
|
|
|
(void) set_config_option(name, curvalue,
|
|
|
|
|
curscontext, cursource,
|
|
|
|
|
GUC_ACTION_LOCAL, true, WARNING);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GUC_SET_LOCAL:
|
|
|
|
|
/* first, apply the masked value as SET */
|
|
|
|
|
(void) set_config_option(name, stack->masked.val.stringval,
|
|
|
|
|
stack->masked_scontext, PGC_S_SESSION,
|
|
|
|
|
GUC_ACTION_SET, true, WARNING);
|
|
|
|
|
/* then apply the current value as LOCAL */
|
|
|
|
|
(void) set_config_option(name, curvalue,
|
|
|
|
|
curscontext, cursource,
|
|
|
|
|
GUC_ACTION_LOCAL, true, WARNING);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we successfully made a stack entry, adjust its nest level */
|
|
|
|
|
if (variable->stack != oldvarstack)
|
|
|
|
|
variable->stack->nest_level = stack->nest_level;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* We are at the end of the stack. If the active/previous value is
|
|
|
|
|
* different from the reset value, it must represent a previously
|
|
|
|
|
* committed session value. Apply it, and then drop the stack entry
|
|
|
|
|
* that set_config_option will have created under the impression that
|
|
|
|
|
* this is to be just a transactional assignment. (We leak the stack
|
|
|
|
|
* entry.)
|
|
|
|
|
*/
|
|
|
|
|
if (curvalue != pHolder->reset_val ||
|
|
|
|
|
curscontext != pHolder->gen.reset_scontext ||
|
|
|
|
|
cursource != pHolder->gen.reset_source)
|
|
|
|
|
{
|
|
|
|
|
(void) set_config_option(name, curvalue,
|
|
|
|
|
curscontext, cursource,
|
|
|
|
|
GUC_ACTION_SET, true, WARNING);
|
|
|
|
|
variable->stack = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
DefineCustomBoolVariable(const char *name,
|
|
|
|
|
const char *short_desc,
|
|
|
|
@ -7468,7 +7578,7 @@ read_nondefault_variables(void)
|
|
|
|
|
|
|
|
|
|
(void) set_config_option(varname, varvalue,
|
|
|
|
|
varscontext, varsource,
|
|
|
|
|
GUC_ACTION_SET, true);
|
|
|
|
|
GUC_ACTION_SET, true, 0);
|
|
|
|
|
if (varsourcefile[0])
|
|
|
|
|
set_config_sourcefile(varname, varsourcefile, varsourceline);
|
|
|
|
|
|
|
|
|
@ -7569,7 +7679,9 @@ ProcessGUCArray(ArrayType *array,
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(void) set_config_option(name, value, context, source, action, true);
|
|
|
|
|
(void) set_config_option(name, value,
|
|
|
|
|
context, source,
|
|
|
|
|
action, true, 0);
|
|
|
|
|
|
|
|
|
|
free(name);
|
|
|
|
|
if (value)
|
|
|
|
@ -7873,7 +7985,7 @@ validate_option_array_item(const char *name, const char *value,
|
|
|
|
|
/* test for permissions and valid option value */
|
|
|
|
|
(void) set_config_option(name, value,
|
|
|
|
|
superuser() ? PGC_SUSET : PGC_USERSET,
|
|
|
|
|
PGC_S_TEST, GUC_ACTION_SET, false);
|
|
|
|
|
PGC_S_TEST, GUC_ACTION_SET, false, 0);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|