typedefstruct
{ char unit[MAX_UNIT_LEN + 1]; /* unit, as a string, like "kB" or
* "min" */ int base_unit; /* GUC_UNIT_XXX */ double multiplier; /* Factor for converting unit -> base_unit */
} unit_conversion;
/* Ensure that the constants in the tables don't overflow or underflow */ #if BLCKSZ < 1024 || BLCKSZ > (1024*1024) #error BLCKSZ must be between 1KB and1MB #endif #if XLOG_BLCKSZ < 1024 || XLOG_BLCKSZ > (1024*1024) #error XLOG_BLCKSZ must be between 1KB and1MB #endif
staticconstchar *const memory_units_hint = gettext_noop("Valid units for this parameter are \"B\", \"kB\", \"MB\", \"GB\", and \"TB\".");
static HTAB *guc_hashtab; /* entries are GUCHashEntrys */
/* *Inadditiontothehashtable,variableshavingcertainpropertiesare *linkedintotheselists,sothatwecanfindthemwithoutscanningthe *wholehashtable.Inmostapplications,onlyasmallfractionofthe *GUCsappearintheselistsatanygiventime.Theusageofthestack *andreportlistsisstylizedenoughthattheycanbeslists,butthe *nondeflisthastobeadlisttoavoidO(N)deletesincommoncases.
*/ static dlist_head guc_nondef_list; /* list of variables that have source
* different from PGC_S_DEFAULT */ static slist_head guc_stack_list; /* list of variables that have non-NULL
* stack */ static slist_head guc_report_list; /* list of variables that have the
* GUC_NEEDS_REPORT bit set in status */
staticbool reporting_enabled; /* true to enable GUC_REPORT */
staticint GUCNestLevel = 0; /* 1 when in main transaction */
/* Ignore anything already marked as ignorable */ if (item->ignore) continue;
/* *Trytofindthevariable;butdonotcreateacustomplaceholderif *it'snottherealready.
*/
record = find_option(item->name, false, true, elevel);
if (record)
{ /* If it's already marked, then this is a duplicate entry */ if (record->status & GUC_IS_IN_FILE)
{ /* *Marktheearlieroccurrence(s)asdead/ignorable.Wecould *avoidtheO(N^2)behaviorherewithsomeadditionalstate, *butitseemsunlikelytobeworththetrouble.
*/
ConfigVariable *pitem;
for (pitem = head; pitem != item; pitem = pitem->next)
{ if (!pitem->ignore &&
strcmp(pitem->name, item->name) == 0)
pitem->ignore = true;
}
} /* Now mark it as present in file */
record->status |= GUC_IS_IN_FILE;
} elseif (!valid_custom_variable_name(item->name))
{ /* Invalid non-custom variable, so complain */
ereport(elevel,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("unrecognized configuration parameter \"%s\" in file \"%s\" line %d",
item->name,
item->filename, item->sourceline)));
item->errmsg = pstrdup("unrecognized configuration parameter");
error = true;
ConfFileWithError = item->filename;
}
}
/* *Ifwe'vedetectedanyerrorssofar,wedon'twanttoriskapplyingany *changes.
*/ if (error) goto bail_out;
/* Otherwise, set flag that we're beginning to apply changes */
applying = true;
if (gconf->reset_source != PGC_S_FILE ||
(gconf->status & GUC_IS_IN_FILE)) continue; if (gconf->context < PGC_SIGHUP)
{ /* The removal can't be effective without a restart */
gconf->status |= GUC_PENDING_RESTART;
ereport(elevel,
(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
errmsg("parameter \"%s\" cannot be changed without restarting the server",
gconf->name)));
record_config_file_error(psprintf("parameter \"%s\" cannot be changed without restarting the server",
gconf->name),
NULL, 0,
&head, &tail);
error = true; continue;
}
/* No more to do if we're just doing show_all_file_settings() */ if (!applySettings) continue;
/* *Resetany"file"sourcesto"default",elseset_config_optionwill *notoverridethosesettings.
*/ if (gconf->reset_source == PGC_S_FILE)
gconf->reset_source = PGC_S_DEFAULT; if (gconf->source == PGC_S_FILE)
set_guc_source(gconf, PGC_S_DEFAULT); for (stack = gconf->stack; stack; stack = stack->prev)
{ if (stack->source == PGC_S_FILE)
stack->source = PGC_S_DEFAULT;
}
/* Now we can re-apply the wired-in default (i.e., the boot_val) */ if (set_config_option(gconf->name, NULL,
context, PGC_S_DEFAULT,
GUC_ACTION_SET, true, 0, false) > 0)
{ /* Log the change if appropriate */ if (context == PGC_SIGHUP)
ereport(elevel,
(errmsg("parameter \"%s\" removed from configuration file, reset to default",
gconf->name)));
}
}
/* *Restoreanyvariablesdeterminedbyenvironmentvariablesor *dynamically-computeddefaults.Thisisano-opexceptinthecase *whereoneofthesehadbeenintheconfigfileandisnowremoved. * *Inparticular,we*mustnot*dothisduringthepostmaster'sinitial *loadingofthefile,sincethetimezonefunctionsinparticularshould *berunonlyafterinitializationiscomplete. * *XXXthisisanunmaintainablecrock,becausewehavetoknowhowtoset *(oratleastwhattocalltoset)everynon-PGC_INTERNALvariablethat *couldpotentiallyhavePGC_S_DYNAMIC_DEFAULTorPGC_S_ENV_VARsource.
*/ if (context == PGC_SIGHUP && applySettings)
{
InitializeGUCOptionsFromEnvironment();
pg_timezone_abbrev_initialize(); /* this selects SQL_ASCII in processes not connected to a database */
SetConfigOption("client_encoding", GetDatabaseEncodingName(),
PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT);
}
/* *Nowapplythevaluesfromtheconfigfile.
*/ for (item = head; item; item = item->next)
{ char *pre_value = NULL; int scres;
/* Ignore anything marked as ignorable */ if (item->ignore) continue;
/* In SIGHUP cases in the postmaster, we want to report changes */ if (context == PGC_SIGHUP && applySettings && !IsUnderPostmaster)
{ constchar *preval = GetConfigOption(item->name, true, false);
/* If option doesn't exist yet or is NULL, treat as empty string */ if (!preval)
preval = ""; /* must dup, else might have dangling pointer below */
pre_value = pstrdup(preval);
}
scres = set_config_option(item->name, item->value,
context, PGC_S_FILE,
GUC_ACTION_SET, applySettings, 0, false); if (scres > 0)
{ /* variable was updated, so log the change if appropriate */ if (pre_value)
{ constchar *post_value = GetConfigOption(item->name, true, false);
if (!post_value)
post_value = ""; if (strcmp(pre_value, post_value) != 0)
ereport(elevel,
(errmsg("parameter \"%s\" changed to \"%s\"",
item->name, item->value)));
}
item->applied = true;
} elseif (scres == 0)
{
error = true;
item->errmsg = pstrdup("setting could not be applied");
ConfFileWithError = item->filename;
} else
{ /* no error, but variable's active value was not changed */
item->applied = true;
}
if (old != NULL)
{ /* This is to help catch old code that malloc's GUC data. */
Assert(GetMemoryChunkContext(old) == GUCMemoryContext);
data = repalloc_extended(old, size,
MCXT_ALLOC_NO_OOM);
} else
{ /* Like realloc(3), but not like repalloc(), we allow old == NULL. */
data = MemoryContextAllocExtended(GUCMemoryContext, size,
MCXT_ALLOC_NO_OOM);
} if (unlikely(data == NULL))
ereport(elevel,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"))); return data;
}
data = guc_malloc(elevel, len); if (likely(data != NULL))
memcpy(data, src, len); return data;
}
void
guc_free(void *ptr)
{ /* *Historically,GUC-relatedcodehasreliedheavilyontheabilitytodo *free(NULL),soweallowthathereeventhoughpfree()doesn't.
*/ if (ptr != NULL)
{ /* This is to help catch old code that malloc's GUC data. */
Assert(GetMemoryChunkContext(ptr) == GUCMemoryContext);
pfree(ptr);
}
}
/* *Supportfordiscardingano-longer-neededvalueinastackentry. *The"extra"fieldassociatedwiththestackentryiscleared,too.
*/ staticvoid
discard_stack_value(struct config_generic *gconf, config_var_value *val)
{ switch (gconf->vartype)
{ case PGC_BOOL: case PGC_INT: case PGC_REAL: case PGC_ENUM: /* no need to do anything */ break; case PGC_STRING:
set_string_field((struct config_string *) gconf,
&(val->val.stringval),
NULL); break;
}
set_extra_field(gconf, &(val->extra), NULL);
}
for (constchar *p = name; *p; p++)
{ if (*p == GUC_QUALIFIER_SEPARATOR)
{ if (name_start) returnfalse; /* empty name component */
saw_sep = true;
name_start = true;
} elseif (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz_", *p) != NULL ||
IS_HIGHBIT_SET(*p))
{ /* okay as first or non-first character */
name_start = false;
} elseif (!name_start && strchr("0123456789$", *p) != NULL) /* okay as non-first character */ ; else returnfalse;
} if (name_start) returnfalse; /* empty name component */ /* OK if we found at least one separator */ return saw_sep;
}
/* *DecidewhetheranunrecognizedvariablenameisallowedtobeSET. * *Itmustpassthesyntacticrulesofvalid_custom_variable_name(), *anditmustnotbeinanynamespacealreadyreservedbyanextension. *(Wemakethisseparatefromvalid_custom_variable_name()becausewedon't *applythereserved-namespacetestwhenreadingconfigurationfiles.) * *Ifvalid,returntrue.Otherwise,returnfalseifskip_errorsistrue, *elsethrowasuitableerroratthespecifiedelevel(andreturnfalse *ifthat'slessthanERROR).
*/ staticbool
assignable_custom_variable_name(constchar *name, bool skip_errors, int elevel)
{ /* If there's no separator, it can't be a custom variable */ constchar *sep = strchr(name, GUC_QUALIFIER_SEPARATOR);
/* The name must be syntactically acceptable ... */ if (!valid_custom_variable_name(name))
{ if (!skip_errors)
ereport(elevel,
(errcode(ERRCODE_INVALID_NAME),
errmsg("invalid configuration parameter name \"%s\"",
name),
errdetail("Custom parameter names must be two or more simple identifiers separated by dots."))); returnfalse;
} /* ... and it must not match any previously-reserved prefix */
foreach(lc, reserved_class_prefix)
{ constchar *rcprefix = lfirst(lc);
if (strlen(rcprefix) == classLen &&
strncmp(name, rcprefix, classLen) == 0)
{ if (!skip_errors)
ereport(elevel,
(errcode(ERRCODE_INVALID_NAME),
errmsg("invalid configuration parameter name \"%s\"",
name),
errdetail("\"%s\" is a reserved prefix.",
rcprefix))); returnfalse;
}
} /* OK to create it */ returntrue;
}
/* Unrecognized single-part name */ if (!skip_errors)
ereport(elevel,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("unrecognized configuration parameter \"%s\"",
name))); returnfalse;
}
/* Look it up using the hash table. */
hentry = (GUCHashEntry *) hash_search(guc_hashtab,
&name,
HASH_FIND,
NULL); if (hentry) return hentry->gucvar;
/* *Seeifthenameisanobsoletenameforavariable.Weassumethatthe *setofsupportedoldnamesisshortenoughthatabrute-forcesearchis *thebestway.
*/ for (i = 0; map_old_guc_names[i] != NULL; i += 2)
{ if (guc_name_compare(name, map_old_guc_names[i]) == 0) return find_option(map_old_guc_names[i + 1], false,
skip_errors, elevel);
}
if (create_placeholders)
{ /* *Checkifthenameisvalid,andifso,addaplaceholder.
*/ if (assignable_custom_variable_name(name, skip_errors, elevel)) return add_placeholder_variable(name, elevel); else return NULL; /* error message, if any, already emitted */
}
/* Unknown name and we're not supposed to make a placeholder */ if (!skip_errors)
ereport(elevel,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("unrecognized configuration parameter \"%s\"",
name))); return NULL;
}
/* *thebarecomparisonfunctionforGUCnames
*/ int
guc_name_compare(constchar *namea, constchar *nameb)
{ /* *Thetemptationtousestrcasecmp()heremustberesisted,becausethe *hashmappinghastoremainstableacrosssetlocale()calls.So,build *ourownwithasimpleASCII-onlydowncasing.
*/ while (*namea && *nameb)
{ char cha = *namea++; char chb = *nameb++;
if (cha >= 'A' && cha <= 'Z')
cha += 'a' - 'A'; if (chb >= 'A' && chb <= 'Z')
chb += 'a' - 'A'; if (cha != chb) return cha - chb;
} if (*namea) return1; /* a is longer */ if (*nameb) return -1; /* b is longer */ return0;
}
/* configdir is -D option, or $PGDATA if no -D */ if (userDoption)
configdir = make_absolute_path(userDoption); else
configdir = make_absolute_path(getenv("PGDATA"));
if (configdir && stat(configdir, &stat_buf) != 0)
{
write_stderr("%s: could not access directory \"%s\": %m\n",
progname,
configdir); if (errno == ENOENT)
write_stderr("Run initdb or pg_basebackup to initialize a PostgreSQL data directory.\n"); returnfalse;
}
/* *Findtheconfigurationfile:ifconfig_filewasspecifiedonthe *commandline,useit,elseuseconfigdir/postgresql.conf.Inanycase *ensuretheresultisanabsolutepath,sothatitwillbeinterpreted *thesamewaybyfuturebackends.
*/ if (ConfigFileName)
{
fname = make_absolute_path(ConfigFileName);
fname_is_malloced = true;
} elseif (configdir)
{
fname = guc_malloc(FATAL,
strlen(configdir) + strlen(CONFIG_FILENAME) + 2);
sprintf(fname, "%s/%s", configdir, CONFIG_FILENAME);
fname_is_malloced = false;
} else
{
write_stderr("%s does not know where to find the server configuration file.\n" "You must specify the --config-file or -D invocation " "option or set the PGDATA environment variable.\n",
progname); returnfalse;
}
if (fname_is_malloced)
free(fname); else
guc_free(fname);
/* *Nowreadtheconfigfileforthefirsttime.
*/ if (stat(ConfigFileName, &stat_buf) != 0)
{
write_stderr("%s: could not access the server configuration file \"%s\": %m\n",
progname, ConfigFileName);
free(configdir); returnfalse;
}
/* *Ifthedata_directoryGUCvariablehasbeenset,usethatasDataDir; *otherwiseuseconfigdirifset;elsepunt. * *Note:SetDataDirwillcopyandabsolute-izeitsargument,sowedon't *haveto.
*/
data_directory_rec = (struct config_string *)
find_option("data_directory", false, false, PANIC); if (*data_directory_rec->variable)
SetDataDir(*data_directory_rec->variable); elseif (configdir)
SetDataDir(configdir); else
{
write_stderr("%s does not know where to find the database system data.\n" "This can be specified as \"data_directory\" in \"%s\", " "or by the -D invocation option, or by the " "PGDATA environment variable.\n",
progname, ConfigFileName); returnfalse;
}
/* *Figureoutwherepg_hba.confis,andmakesurethepathisabsolute.
*/ if (HbaFileName)
{
fname = make_absolute_path(HbaFileName);
fname_is_malloced = true;
} elseif (configdir)
{
fname = guc_malloc(FATAL,
strlen(configdir) + strlen(HBA_FILENAME) + 2);
sprintf(fname, "%s/%s", configdir, HBA_FILENAME);
fname_is_malloced = false;
} else
{
write_stderr("%s does not know where to find the \"hba\" configuration file.\n" "This can be specified as \"hba_file\" in \"%s\", " "or by the -D invocation option, or by the " "PGDATA environment variable.\n",
progname, ConfigFileName); returnfalse;
}
SetConfigOption("hba_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
if (fname_is_malloced)
free(fname); else
guc_free(fname);
/* *Likewiseforpg_ident.conf.
*/ if (IdentFileName)
{
fname = make_absolute_path(IdentFileName);
fname_is_malloced = true;
} elseif (configdir)
{
fname = guc_malloc(FATAL,
strlen(configdir) + strlen(IDENT_FILENAME) + 2);
sprintf(fname, "%s/%s", configdir, IDENT_FILENAME);
fname_is_malloced = false;
} else
{
write_stderr("%s does not know where to find the \"ident\" configuration file.\n" "This can be specified as \"ident_file\" in \"%s\", " "or by the -D invocation option, or by the " "PGDATA environment variable.\n",
progname, ConfigFileName); returnfalse;
}
SetConfigOption("ident_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
if (fname_is_malloced)
free(fname); else
guc_free(fname);
/* We need only consider GUCs not already at PGC_S_DEFAULT */
dlist_foreach_modify(iter, &guc_nondef_list)
{ struct config_generic *gconf = dlist_container(struct config_generic,
nondef_link, iter.cur);
/* Don't reset non-SET-able values */ if (gconf->context != PGC_SUSET &&
gconf->context != PGC_USERSET) continue; /* Don't reset if special exclusion from RESET ALL */ if (gconf->flags & GUC_NO_RESET_ALL) continue; /* No need to reset if wasn't SET */ if (gconf->source <= PGC_S_OVERRIDE) continue;
/* Save old value to support transaction abort */
push_old_value(gconf, GUC_ACTION_SET);
/* If we're not inside a nest level, do nothing */ if (GUCNestLevel == 0) return;
/* Do we already have a stack entry of the current nest level? */
stack = gconf->stack; if (stack && stack->nest_level >= GUCNestLevel)
{ /* Yes, so adjust its state if necessary */
Assert(stack->nest_level == GUCNestLevel); switch (action)
{ 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 GUC_ACTION_LOCAL: if (stack->state == GUC_SET)
{ /* SET followed by SET LOCAL, remember SET's value */
stack->masked_scontext = gconf->scontext;
stack->masked_srole = gconf->srole;
set_stack_value(gconf, &stack->masked);
stack->state = GUC_SET_LOCAL;
} /* in all other cases, no change to stack entry */ break; case GUC_ACTION_SAVE: /* Could only have a prior SAVE of same variable */
Assert(stack->state == GUC_SAVE); break;
} return;
}
/* We need only process GUCs having nonempty stacks */
slist_foreach_modify(iter, &guc_stack_list)
{ struct config_generic *gconf = slist_container(struct config_generic,
stack_link, iter.cur);
GucStack *stack;
/* *Inthisnextbit,ifwedon'tseteitherrestorePrioror *restoreMasked,wemust"discard"anyunwantedfieldsofthe *stackentriestoavoidleakingmemory.Ifwedosetoneof *thoseflags,unusedfieldswillbecleanedupafterrestoring.
*/ if (!isCommit) /* if abort, always restore prior value */
restorePrior = true; elseif (stack->state == GUC_SAVE)
restorePrior = true; elseif (stack->nest_level == 1)
{ /* transaction commit */ if (stack->state == GUC_SET_LOCAL)
restoreMasked = true; elseif (stack->state == GUC_SET)
{ /* we keep the current active value */
discard_stack_value(gconf, &stack->prior);
} else/* must be GUC_LOCAL */
restorePrior = true;
} elseif (prev == NULL ||
prev->nest_level < stack->nest_level - 1)
{ /* decrement entry's level and do not pop it */
stack->nest_level--; continue;
} else
{ /* *Wehavetomergethisstackentryintoprev.SeeREADMEfor *discussionofthisbit.
*/ switch (stack->state)
{ case GUC_SAVE:
Assert(false); /* can't get here */ break;
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;
case GUC_LOCAL: if (prev->state == GUC_SET)
{ /* LOCAL migrates down */
prev->masked_scontext = stack->scontext;
prev->masked_srole = stack->srole;
prev->masked = stack->prior;
prev->state = GUC_SET_LOCAL;
} else
{ /* else just forget this stack level */
discard_stack_value(gconf, &stack->prior);
} break;
case GUC_SET_LOCAL: /* prior state at this level no longer wanted */
discard_stack_value(gconf, &stack->prior); /* copy down the masked state */
prev->masked_scontext = stack->masked_scontext;
prev->masked_srole = stack->masked_srole; if (prev->state == GUC_SET_LOCAL)
discard_stack_value(gconf, &prev->masked);
prev->masked = stack->masked;
prev->state = GUC_SET_LOCAL; break;
}
}
changed = false;
if (restorePrior || restoreMasked)
{ /* Perform appropriate restoration of the stacked value */
config_var_value newvalue;
GucSource newsource;
GucContext newscontext;
Oid newsrole;
/* Report new value if we changed it */ if (changed && (gconf->flags & GUC_REPORT) &&
!(gconf->status & GUC_NEEDS_REPORT))
{
gconf->status |= GUC_NEEDS_REPORT;
slist_push_head(&guc_report_list, &gconf->report_link);
}
} /* end of stack-popping loop */
}
/* extract unit string to compare to table entries */
unitlen = 0; while (*unit != '\0' && !isspace((unsignedchar) *unit) &&
unitlen < MAX_UNIT_LEN)
unitstr[unitlen++] = *(unit++);
unitstr[unitlen] = '\0'; /* allow whitespace after unit */ while (isspace((unsignedchar) *unit))
unit++; if (*unit != '\0') returnfalse; /* unit too long, or garbage after it */
/* now search the appropriate table */ if (base_unit & GUC_UNIT_MEMORY)
table = memory_unit_conversion_table; else
table = time_unit_conversion_table;
for (i = 0; *table[i].unit; i++)
{ if (base_unit == table[i].base_unit &&
strcmp(unitstr, table[i].unit) == 0)
{ double cvalue = value * table[i].multiplier;
/* *ReturnthenameofaGUC'sbaseunit(e.g."ms")givenitsflags. *ReturnNULLiftheGUCisunitless.
*/ constchar *
get_config_unit_name(int flags)
{ switch (flags & GUC_UNIT)
{ case0: return NULL; /* GUC has no units */ case GUC_UNIT_BYTE: return"B"; case GUC_UNIT_KB: return"kB"; case GUC_UNIT_MB: return"MB"; case GUC_UNIT_BLOCKS:
{ staticchar bbuf[8];
/* initialize if first time through */ if (bbuf[0] == '\0')
snprintf(bbuf, sizeof(bbuf), "%dkB", BLCKSZ / 1024); return bbuf;
} case GUC_UNIT_XBLOCKS:
{ staticchar xbuf[8];
/* initialize if first time through */ if (xbuf[0] == '\0')
snprintf(xbuf, sizeof(xbuf), "%dkB", XLOG_BLCKSZ / 1024); return xbuf;
} case GUC_UNIT_MS: return"ms"; case GUC_UNIT_S: return"s"; case GUC_UNIT_MIN: return"min"; default:
elog(ERROR, "unrecognized GUC units value: %d",
flags & GUC_UNIT); return NULL;
}
}
if (endptr == value || errno == ERANGE) returnfalse; /* no HINT for these cases */
/* reject NaN (infinities will fail range check below) */ if (isnan(val)) returnfalse; /* treat same as syntax error; no HINT */
/* allow whitespace between number and unit */ while (isspace((unsignedchar) *endptr))
endptr++;
/* Handle possible unit */ if (*endptr != '\0')
{ if ((flags & GUC_UNIT) == 0) returnfalse; /* this setting does not accept a unit */
if (!convert_to_base_unit(val,
endptr, (flags & GUC_UNIT),
&val))
{ /* invalid unit, or garbage after the unit; set hint and fail. */ if (hintmsg)
{ if (flags & GUC_UNIT_MEMORY)
*hintmsg = memory_units_hint; else
*hintmsg = time_units_hint;
} returnfalse;
}
}
/* Round to int, then check for overflow */
val = rint(val);
if (val > INT_MAX || val < INT_MIN)
{ if (hintmsg)
*hintmsg = gettext_noop("Value exceeds integer range."); returnfalse;
}
/* To suppress compiler warnings, always set output params */ if (result)
*result = 0; if (hintmsg)
*hintmsg = NULL;
errno = 0;
val = strtod(value, &endptr);
if (endptr == value || errno == ERANGE) returnfalse; /* no HINT for these cases */
/* reject NaN (infinities will fail range checks later) */ if (isnan(val)) returnfalse; /* treat same as syntax error; no HINT */
/* allow whitespace between number and unit */ while (isspace((unsignedchar) *endptr))
endptr++;
/* Handle possible unit */ if (*endptr != '\0')
{ if ((flags & GUC_UNIT) == 0) returnfalse; /* this setting does not accept a unit */
if (!convert_to_base_unit(val,
endptr, (flags & GUC_UNIT),
&val))
{ /* invalid unit, or garbage after the unit; set hint and fail. */ if (hintmsg)
{ if (flags & GUC_UNIT_MEMORY)
*hintmsg = memory_units_hint; else
*hintmsg = time_units_hint;
} returnfalse;
}
}
if (unit)
unitspace = " "; else
unit = unitspace = "";
ereport(elevel,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("%d%s%s is outside the valid range for parameter \"%s\" (%d%s%s .. %d%s%s)",
newval->intval, unitspace, unit,
conf->gen.name,
conf->min, unitspace, unit,
conf->max, unitspace, unit))); returnfalse;
}
if (unit)
unitspace = " "; else
unit = unitspace = "";
ereport(elevel,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("%g%s%s is outside the valid range for parameter \"%s\" (%g%s%s .. %g%s%s)",
newval->realval, unitspace, unit,
conf->gen.name,
conf->min, unitspace, unit,
conf->max, unitspace, unit))); returnfalse;
}
if (!call_real_check_hook(conf, &newval->realval, newextra,
source, elevel)) returnfalse;
} break; case PGC_STRING:
{ struct config_string *conf = (struct config_string *) record;
/* if handle is specified, no need to look up option */ if (!handle)
{
record = find_option(name, true, false, elevel); if (record == NULL) return0;
} else
record = handle;
/* *GUC_ACTION_SAVEchangesareacceptableduringaparalleloperation, *becausethecurrentworkerwillalsopopthechange.We'reprobably *dealingwithafunctionhavingaproconfigentry.Onlythefunction's *bodyshouldobservethechange,andpeerworkersdonotshareinthe *executionofafunctioncallstartedbythisworker. * *AlsoallownormalsettingiftheGUCismarkedGUC_ALLOW_IN_PARALLEL. * *Otherchangesmightneedtoaffectotherworkers,soforbidthem.
*/ if (IsInParallelMode() && changeVal && action != GUC_ACTION_SAVE &&
(record->flags & GUC_ALLOW_IN_PARALLEL) == 0)
{
ereport(elevel,
(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
errmsg("parameter \"%s\" cannot be set during a parallel operation",
record->name))); return0;
}
/* *Checkiftheoptioncanbesetatthistime.Seeguc.hfortheprecise *rules.
*/ switch (record->context)
{ case PGC_INTERNAL: if (context != PGC_INTERNAL)
{
ereport(elevel,
(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
errmsg("parameter \"%s\" cannot be changed",
record->name))); return0;
} break; case PGC_POSTMASTER: if (context == PGC_SIGHUP)
{ /* *Wearere-readingaPGC_POSTMASTERvariablefrom *postgresql.conf.Wecan'tchangethesetting,soweshould *giveawarningiftheDBAtriestochangeit.However, *becauseofvariantformats,canonicalizationbycheck *hooks,etc,wecan'tjustcomparethegivenstringdirectly *towhat'sstored.Setaflagtocheckbelowafterwehave *thefinalstorablevalue.
*/
prohibitValueChange = true;
} elseif (context != PGC_POSTMASTER)
{
ereport(elevel,
(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
errmsg("parameter \"%s\" cannot be changed without restarting the server",
record->name))); return0;
} break; case PGC_SIGHUP: if (context != PGC_SIGHUP && context != PGC_POSTMASTER)
{
ereport(elevel,
(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
errmsg("parameter \"%s\" cannot be changed now",
record->name))); return0;
}
/* *Hmm,theideaoftheSIGHUPcontextis"oughttobeglobal,but *canbechangedafterpostmasterstart".Butthere'snothing *thatpreventsacraftyadministratorfromsendingSIGHUP *signalstoindividualbackendsonly.
*/ break; case PGC_SU_BACKEND: if (context == PGC_BACKEND)
{ /* *Checkwhethertherequestinguserhasbeengranted *privilegetosetthisGUC.
*/
AclResult aclresult;
aclresult = pg_parameter_aclcheck(record->name, srole, ACL_SET); if (aclresult != ACLCHECK_OK)
{ /* No granted privilege */
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
record->name))); return0;
}
} /* fall through to process the same as PGC_BACKEND */ /* FALLTHROUGH */ case PGC_BACKEND: if (context == PGC_SIGHUP)
{ /* *IfaPGC_BACKENDorPGC_SU_BACKENDparameterischangedin *theconfigfile,wewanttoacceptthenewvalueinthe *postmaster(whenceitwillpropagateto *subsequently-startedbackends),butignoreitinexisting *backends.Thisisatadklugy,butnecessarybecausewe *don'tre-readtheconfigfileduringbackendstart. * *However,ifchangeValisfalsethenplowaheadanywaysince *wearetryingtofindoutifthevalueispotentiallygood, *notactuallyuseit. * *InEXEC_BACKENDbuilds,thisworksdifferently:weloadall *non-defaultsettingsfromtheCONFIG_EXEC_PARAMSfile *duringbackendstart.Inthatcasewemustaccept *PGC_SIGHUPsettings,soastohavethesamevalueasif *we'dforkedfromthepostmaster.Thiscanalsohappenwhen *usingRestoreGUCState()withinabackgroundworkerthat *needstohavethesamesettingsastheuserbackendthat *startedit.is_reloadwillbetruewheneithersituation *applies.
*/ if (IsUnderPostmaster && changeVal && !is_reload) return -1;
} elseif (context != PGC_POSTMASTER &&
context != PGC_BACKEND &&
context != PGC_SU_BACKEND &&
source != PGC_S_CLIENT)
{
ereport(elevel,
(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
errmsg("parameter \"%s\" cannot be set after connection start",
record->name))); return0;
} break; case PGC_SUSET: if (context == PGC_USERSET || context == PGC_BACKEND)
{ /* *Checkwhethertherequestinguserhasbeengranted *privilegetosetthisGUC.
*/
AclResult aclresult;
aclresult = pg_parameter_aclcheck(record->name, srole, ACL_SET); if (aclresult != ACLCHECK_OK)
{ /* No granted privilege */
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
record->name))); return0;
}
} break; case PGC_USERSET: /* always okay */ break;
}
/* *DisallowchangingGUC_NOT_WHILE_SEC_RESTvaluesifweareinsidea *securityrestrictioncontext.WecanrejectthisregardlessoftheGUC *contextorsource,mainlybecausesourcesthatitmightbereasonable *tooverrideforwon'tbeseenwhileinsideafunction. * *Note:variablesmarkedGUC_NOT_WHILE_SEC_RESTshouldusuallybemarked *GUC_NO_RESET_ALLaswell,becauseResetAllOptions()doesn'tcheckthis. *Anexceptionmightbemadeiftheresetvalueisassumedtobe"safe". * *Note:thisflagiscurrentlyusedfor"session_authorization"and *"role".Weneedtoprohibitchangingtheseinsidealocaluserid *contextbecausewhenweexitit,GUCwon'tbenotified,leavingthings *outofsync.(ThiscouldbefixedbyforcinganewGUCnestinglevel, *butthatwouldchangebehaviorinpossibly-undesirableways.)Also,we *prohibitchangingtheseinasecurity-restrictedoperationbecause *otherwiseRESETcouldbeusedtoregainthesessionuser'sprivileges.
*/ if (record->flags & GUC_NOT_WHILE_SEC_REST)
{ if (InLocalUserIdChange())
{ /* *Phrasingofthiserrormessageishistorical,butit'sthemost *commoncase.
*/
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("cannot set parameter \"%s\" within security-definer function",
record->name))); return0;
} if (InSecurityRestrictedOperation())
{
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("cannot set parameter \"%s\" within security-restricted operation",
record->name))); return0;
}
}
/* Disallow resetting and saving GUC_NO_RESET values */ if (record->flags & GUC_NO_RESET)
{ if (value == NULL)
{
ereport(elevel,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("parameter \"%s\" cannot be reset", record->name))); return0;
} if (action == GUC_ACTION_SAVE)
{
ereport(elevel,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("parameter \"%s\" cannot be set locally in functions",
record->name))); return0;
}
}
record = find_option(name, false, missing_ok, ERROR); if (record == NULL) return NULL; if (restrict_privileged &&
!ConfigOptionIsVisible(record))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to examine \"%s\"", name),
errdetail("Only roles with privileges of the \"%s\" role may examine this parameter.", "pg_read_all_settings")));
record = find_option(name, false, false, ERROR);
Assert(record != NULL); if (!ConfigOptionIsVisible(record))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to examine \"%s\"", name),
errdetail("Only roles with privileges of the \"%s\" role may examine this parameter.", "pg_read_all_settings")));
/* Emit file header containing warning comment */
appendStringInfoString(&buf, "# Do not edit this file manually!\n");
appendStringInfoString(&buf, "# It will be overwritten by the ALTER SYSTEM command.\n");
errno = 0; if (write(fd, buf.data, buf.len) != buf.len)
{ /* if write didn't set errno, assume problem is no disk space */ if (errno == 0)
errno = ENOSPC;
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not write to file \"%s\": %m", filename)));
}
/* Emit each parameter, properly quoting the value */ for (item = head; item != NULL; item = item->next)
{ char *escaped;
escaped = escape_single_quotes_ascii(item->value); if (!escaped)
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory")));
appendStringInfoString(&buf, escaped);
free(escaped);
appendStringInfoString(&buf, "'\n");
errno = 0; if (write(fd, buf.data, buf.len) != buf.len)
{ /* if write didn't set errno, assume problem is no disk space */ if (errno == 0)
errno = ENOSPC;
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not write to file \"%s\": %m", filename)));
}
}
/* fsync before considering the write to be successful */ if (pg_fsync(fd) != 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not fsync file \"%s\": %m", filename)));
/* *Extractstatementarguments
*/
name = altersysstmt->setstmt->name;
if (!AllowAlterSystem)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("ALTER SYSTEM is not allowed in this environment")));
switch (altersysstmt->setstmt->kind)
{ case VAR_SET_VALUE:
value = ExtractSetVariableArgs(altersysstmt->setstmt); break;
case VAR_SET_DEFAULT: case VAR_RESET:
value = NULL; break;
case VAR_RESET_ALL:
value = NULL;
resetall = true; break;
default:
elog(ERROR, "unrecognized alter system stmt type: %d",
altersysstmt->setstmt->kind); break;
}
/* *CheckpermissiontorunALTERSYSTEMonthetargetvariable
*/ if (!superuser())
{ if (resetall)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to perform ALTER SYSTEM RESET ALL"))); else
{
AclResult aclresult;
aclresult = pg_parameter_aclcheck(name, GetUserId(),
ACL_ALTER_SYSTEM); if (aclresult != ACLCHECK_OK)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
name)));
}
}
/* *Unlessit'sRESET_ALL,validatethetargetvariableandvalue
*/ if (!resetall)
{ struct config_generic *record;
/* We don't want to create a placeholder if there's not one already */
record = find_option(name, false, true, DEBUG5); if (record != NULL)
{ /* *Don'tallowparametersthatcan'tbesetinconfigurationfiles *tobesetinPG_AUTOCONF_FILENAMEfile.
*/ if ((record->context == PGC_INTERNAL) ||
(record->flags & GUC_DISALLOW_IN_FILE) ||
(record->flags & GUC_DISALLOW_IN_AUTO_FILE))
ereport(ERROR,
(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
errmsg("parameter \"%s\" cannot be changed",
name)));
/* *Ifavalueisspecified,verifythatit'ssane.
*/ if (value)
{ union config_var_val newval; void *newextra = NULL;
if (!parse_and_validate_value(record, value,
PGC_S_FILE, ERROR,
&newval, &newextra))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid value for parameter \"%s\": \"%s\"",
name, value)));
/* *Wemustalsorejectvaluescontainingnewlines,becausethegrammar *forconfigfilesdoesn'tsupportembeddednewlinesinstring *literals.
*/ if (value && strchr(value, '\n'))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("parameter value for ALTER SYSTEM must not contain a newline")));
}
/* *Toensurecrashsafety,firstwritethenewfiledatatoatempfile, *thenatomicallyrenameitintoplace. * *Ifthereisatempfileleftoverduetoapreviouscrash,it'sokayto *truncateandreuseit.
*/
Tmpfd = BasicOpenFile(AutoConfTmpFileName,
O_CREAT | O_RDWR | O_TRUNC); if (Tmpfd < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open file \"%s\": %m",
AutoConfTmpFileName)));
/* *UseaTRYblocktocleanupthefileifwefail.SinceweneedaTRY *blockanyway,OKtouseBasicOpenFileratherthanOpenTransientFile.
*/
PG_TRY();
{ /* Write and sync the new contents to the temporary file */
write_auto_conf_file(Tmpfd, AutoConfTmpFileName, head);
/* Close before renaming; may be required on some platforms */
close(Tmpfd);
Tmpfd = -1;
/* *Astherenameisatomicoperation,ifanyproblemoccursafterthis *atworstitcanlosetheparameterssetbylastALTERSYSTEM *command.
*/
durable_rename(AutoConfTmpFileName, AutoConfFileName, ERROR);
}
PG_CATCH();
{ /* Close file first, else unlink might fail on some platforms */ if (Tmpfd >= 0)
close(Tmpfd);
/* Unlink, but ignore any error */
(void) unlink(AutoConfTmpFileName);
/* First, apply the reset value if any */ if (pHolder->reset_val)
(void) set_config_option_ext(name, pHolder->reset_val,
pHolder->gen.reset_scontext,
pHolder->gen.reset_source,
pHolder->gen.reset_srole,
GUC_ACTION_SET, true, WARNING, false); /* 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,
pHolder->gen.srole);
/* Also copy over any saved source-location information */ if (pHolder->gen.sourcefile)
set_config_sourcefile(name, pHolder->gen.sourcefile,
pHolder->gen.sourceline);
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, stack->srole);
/* See how to apply the passed-in value */ switch (stack->state)
{ case GUC_SAVE:
(void) set_config_option_ext(name, curvalue,
curscontext, cursource, cursrole,
GUC_ACTION_SAVE, true,
WARNING, false); break;
case GUC_SET_LOCAL: /* first, apply the masked value as SET */
(void) set_config_option_ext(name, stack->masked.val.stringval,
stack->masked_scontext,
PGC_S_SESSION,
stack->masked_srole,
GUC_ACTION_SET, true,
WARNING, false); /* then apply the current value as LOCAL */
(void) set_config_option_ext(name, curvalue,
curscontext, cursource, cursrole,
GUC_ACTION_LOCAL, true,
WARNING, false); break;
}
/* If we successfully made a stack entry, adjust its nest level */ if (variable->stack != oldvarstack)
variable->stack->nest_level = stack->nest_level;
} else
{ /* *Weareattheendofthestack.Iftheactive/previousvalueis *differentfromtheresetvalue,itmustrepresentapreviously *committedsessionvalue.Applyit,andthendropthestackentry *thatset_config_optionwillhavecreatedundertheimpressionthat *thisistobejustatransactionalassignment.(Weleakthestack *entry.)
*/ if (curvalue != pHolder->reset_val ||
curscontext != pHolder->gen.reset_scontext ||
cursource != pHolder->gen.reset_source ||
cursrole != pHolder->gen.reset_srole)
{
(void) set_config_option_ext(name, curvalue,
curscontext, cursource, cursrole,
GUC_ACTION_SET, true, WARNING, false); if (variable->stack != NULL)
{
slist_delete(&guc_stack_list, &variable->stack_link);
variable->stack = NULL;
}
}
}
}
if ((var->flags & GUC_CUSTOM_PLACEHOLDER) != 0 &&
strncmp(className, var->name, classLen) == 0 &&
var->name[classLen] == GUC_QUALIFIER_SEPARATOR)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_NAME),
errmsg("invalid configuration parameter name \"%s\", removing it",
var->name),
errdetail("\"%s\" is now a reserved prefix.",
className))); /* Remove it from the hash table */
hash_search(guc_hashtab,
&var->name,
HASH_REMOVE,
NULL); /* Remove it from any lists it's in, too */
RemoveGUCFromLists(var);
}
}
/* And remember the name so we can prevent future mistakes. */
oldcontext = MemoryContextSwitchTo(GUCMemoryContext);
reserved_class_prefix = lappend(reserved_class_prefix, pstrdup(className));
MemoryContextSwitchTo(oldcontext);
}
/* We need only consider GUCs with source not PGC_S_DEFAULT */
dlist_foreach(iter, &guc_nondef_list)
{ struct config_generic *conf = dlist_container(struct config_generic,
nondef_link, iter.cur); bool modified;
/* return only parameters marked for inclusion in explain */ if (!(conf->flags & GUC_EXPLAIN)) continue;
/* return only options visible to the current user */ if (!ConfigOptionIsVisible(conf)) continue;
/* return only options that are different from their boot values */
modified = false;
record = find_option(name, false, missing_ok, ERROR); if (record == NULL)
{ if (varname)
*varname = NULL; return NULL;
}
if (!ConfigOptionIsVisible(record))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to examine \"%s\"", name),
errdetail("Only roles with privileges of the \"%s\" role may examine this parameter.", "pg_read_all_settings")));
/* *Openfile
*/
fp = AllocateFile(CONFIG_EXEC_PARAMS_NEW, "w"); if (!fp)
{
ereport(elevel,
(errcode_for_file_access(),
errmsg("could not write to file \"%s\": %m",
CONFIG_EXEC_PARAMS_NEW))); return;
}
/* We need only consider GUCs with source not PGC_S_DEFAULT */
dlist_foreach(iter, &guc_nondef_list)
{ struct config_generic *gconf = dlist_container(struct config_generic,
nondef_link, iter.cur);
write_one_nondefault_variable(fp, gconf);
}
if (FreeFile(fp))
{
ereport(elevel,
(errcode_for_file_access(),
errmsg("could not write to file \"%s\": %m",
CONFIG_EXEC_PARAMS_NEW))); return;
}
/* *Openfile
*/
fp = AllocateFile(CONFIG_EXEC_PARAMS, "r"); if (!fp)
{ /* File not found is fine */ if (errno != ENOENT)
ereport(FATAL,
(errcode_for_file_access(),
errmsg("could not read from file \"%s\": %m",
CONFIG_EXEC_PARAMS))); return;
}
for (;;)
{ if ((varname = read_string_with_null(fp)) == NULL) break;
if (find_option(varname, true, false, FATAL) == NULL)
elog(FATAL, "failed to locate variable \"%s\" in exec config params file", varname);
if ((varvalue = read_string_with_null(fp)) == NULL)
elog(FATAL, "invalid format of exec config params file"); if ((varsourcefile = read_string_with_null(fp)) == NULL)
elog(FATAL, "invalid format of exec config params file"); if (fread(&varsourceline, 1, sizeof(varsourceline), fp) != sizeof(varsourceline))
elog(FATAL, "invalid format of exec config params file"); if (fread(&varsource, 1, sizeof(varsource), fp) != sizeof(varsource))
elog(FATAL, "invalid format of exec config params file"); if (fread(&varscontext, 1, sizeof(varscontext), fp) != sizeof(varscontext))
elog(FATAL, "invalid format of exec config params file"); if (fread(&varsrole, 1, sizeof(varsrole), fp) != sizeof(varsrole))
elog(FATAL, "invalid format of exec config params file");
/* Skippable GUCs consume zero space. */ if (can_skip_gucvar(gconf)) return0;
/* Name, plus trailing zero byte. */
size = strlen(gconf->name) + 1;
/* Get the maximum display length of the GUC value. */ switch (gconf->vartype)
{ case PGC_BOOL:
{
valsize = 5; /* max(strlen('true'), strlen('false')) */
} break;
/* Reserve space for saving the actual size of the guc state */
Assert(maxsize > sizeof(actual_size));
curptr = start_address + sizeof(actual_size);
bytes_left = maxsize - sizeof(actual_size);
/* We need only consider GUCs with source not PGC_S_DEFAULT */
dlist_foreach(iter, &guc_nondef_list)
{ struct config_generic *gconf = dlist_container(struct config_generic,
nondef_link, iter.cur);
if (conf->reset_extra && conf->reset_extra != gconf->extra)
guc_free(conf->reset_extra); break;
} case PGC_INT:
{ struct config_int *conf = (struct config_int *) gconf;
if (conf->reset_extra && conf->reset_extra != gconf->extra)
guc_free(conf->reset_extra); break;
} case PGC_REAL:
{ struct config_real *conf = (struct config_real *) gconf;
if (conf->reset_extra && conf->reset_extra != gconf->extra)
guc_free(conf->reset_extra); break;
} case PGC_STRING:
{ struct config_string *conf = (struct config_string *) gconf;
guc_free(*conf->variable); if (conf->reset_val && conf->reset_val != *conf->variable)
guc_free(conf->reset_val); if (conf->reset_extra && conf->reset_extra != gconf->extra)
guc_free(conf->reset_extra); break;
} case PGC_ENUM:
{ struct config_enum *conf = (struct config_enum *) gconf;
if (conf->reset_extra && conf->reset_extra != gconf->extra)
guc_free(conf->reset_extra); break;
}
} /* Remove it from any lists it's in. */
RemoveGUCFromLists(gconf); /* Now we can reset the struct to PGS_S_DEFAULT state. */
InitializeOneGUCOption(gconf);
}
/* First item is the length of the subsequent data */
memcpy(&len, gucstate, sizeof(len));
srcptr += sizeof(len);
srcend = srcptr + len;
/* If the GUC value check fails, we want errors to show useful context. */
error_context_callback.callback = guc_restore_error_context_callback;
error_context_callback.previous = error_context_stack;
error_context_callback.arg = NULL;
error_context_stack = &error_context_callback;
/* Restore all the listed GUCs. */ while (srcptr < srcend)
{ int result; char *error_context_name_and_value[2];
for (cp = *name; *cp; cp++) if (*cp == '-')
*cp = '_';
}
/* *TransformarrayofGUCsettingsintolistsofnamesandvalues.Thelists *arefastertoprocessincaseswherethesettingsmustbeapplied *repeatedly(e.g.foreachfunctioninvocation).
*/ void
TransformGUCArray(ArrayType *array, List **names, List **values)
{ int i;
/* test if the option is valid and we're allowed to set it */
(void) validate_option_array_item(name, value, false);
/* normalize name (converts obsolete GUC names to modern spellings) */
record = find_option(name, false, true, WARNING); if (record)
name = record->name;
/* build new item for array */
newval = psprintf("%s=%s", name, value);
datum = CStringGetTextDatum(newval);
/* test if the option is valid and we're allowed to set it */
(void) validate_option_array_item(name, NULL, false);
/* normalize name (converts obsolete GUC names to modern spellings) */
record = find_option(name, false, true, WARNING); if (record)
name = record->name;
/* if array is currently null, then surely nothing to delete */ if (!array) return NULL;
newarray = NULL;
index = 1;
for (i = 1; i <= ARR_DIMS(array)[0]; i++)
{
Datum d; char *val; bool isnull;
if (!gconf || gconf->flags & GUC_CUSTOM_PLACEHOLDER)
{ /* *Wecannotdoanymeaningfulcheckonthevalue,soonlypermissions *areusefultocheck.
*/ if (superuser() ||
pg_parameter_aclcheck(name, GetUserId(), ACL_SET) == ACLCHECK_OK) returntrue; if (skipIfNoPermissions) returnfalse;
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"", name)));
}
/* manual permissions check so we can avoid an error being thrown */ if (gconf->context == PGC_USERSET) /* ok */ ; elseif (gconf->context == PGC_SUSET &&
(superuser() ||
pg_parameter_aclcheck(name, GetUserId(), ACL_SET) == ACLCHECK_OK)) /* ok */ ; elseif (skipIfNoPermissions) returnfalse; /* if a permissions error should be thrown, let set_config_option do it */
/* 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, 0, false);
staticbool
call_bool_check_hook(struct config_bool *conf, bool *newval, void **extra,
GucSource source, int elevel)
{ /* Quick success if no hook */ if (!conf->check_hook) returntrue;
/* Reset variables that might be set by hook */
GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE;
GUC_check_errmsg_string = NULL;
GUC_check_errdetail_string = NULL;
GUC_check_errhint_string = NULL;
if (!conf->check_hook(newval, extra, source))
{
ereport(elevel,
(errcode(GUC_check_errcode_value),
GUC_check_errmsg_string ?
errmsg_internal("%s", GUC_check_errmsg_string) :
errmsg("invalid value for parameter \"%s\": %d",
conf->gen.name, (int) *newval),
GUC_check_errdetail_string ?
errdetail_internal("%s", GUC_check_errdetail_string) : 0,
GUC_check_errhint_string ?
errhint("%s", GUC_check_errhint_string) : 0)); /* Flush any strings created in ErrorContext */
FlushErrorState(); returnfalse;
}
returntrue;
}
staticbool
call_int_check_hook(struct config_int *conf, int *newval, void **extra,
GucSource source, int elevel)
{ /* Quick success if no hook */ if (!conf->check_hook) returntrue;
/* Reset variables that might be set by hook */
GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE;
GUC_check_errmsg_string = NULL;
GUC_check_errdetail_string = NULL;
GUC_check_errhint_string = NULL;
if (!conf->check_hook(newval, extra, source))
{
ereport(elevel,
(errcode(GUC_check_errcode_value),
GUC_check_errmsg_string ?
errmsg_internal("%s", GUC_check_errmsg_string) :
errmsg("invalid value for parameter \"%s\": %d",
conf->gen.name, *newval),
GUC_check_errdetail_string ?
errdetail_internal("%s", GUC_check_errdetail_string) : 0,
GUC_check_errhint_string ?
errhint("%s", GUC_check_errhint_string) : 0)); /* Flush any strings created in ErrorContext */
FlushErrorState(); returnfalse;
}
returntrue;
}
staticbool
call_real_check_hook(struct config_real *conf, double *newval, void **extra,
GucSource source, int elevel)
{ /* Quick success if no hook */ if (!conf->check_hook) returntrue;
/* Reset variables that might be set by hook */
GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE;
GUC_check_errmsg_string = NULL;
GUC_check_errdetail_string = NULL;
GUC_check_errhint_string = NULL;
if (!conf->check_hook(newval, extra, source))
{
ereport(elevel,
(errcode(GUC_check_errcode_value),
GUC_check_errmsg_string ?
errmsg_internal("%s", GUC_check_errmsg_string) :
errmsg("invalid value for parameter \"%s\": %g",
conf->gen.name, *newval),
GUC_check_errdetail_string ?
errdetail_internal("%s", GUC_check_errdetail_string) : 0,
GUC_check_errhint_string ?
errhint("%s", GUC_check_errhint_string) : 0)); /* Flush any strings created in ErrorContext */
FlushErrorState(); returnfalse;
}
returntrue;
}
staticbool
call_string_check_hook(struct config_string *conf, char **newval, void **extra,
GucSource source, int elevel)
{ volatilebool result = true;
/* Quick success if no hook */ if (!conf->check_hook) returntrue;
/* *IfelevelisERROR,orifthecheck_hookitselfthrowsanelog *(undesirable,butnotalwaysavoidable),makesurewedon'tleakthe *already-malloc'dnewvalstring.
*/
PG_TRY();
{ /* Reset variables that might be set by hook */
GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE;
GUC_check_errmsg_string = NULL;
GUC_check_errdetail_string = NULL;
GUC_check_errhint_string = NULL;
if (!conf->check_hook(newval, extra, source))
{
ereport(elevel,
(errcode(GUC_check_errcode_value),
GUC_check_errmsg_string ?
errmsg_internal("%s", GUC_check_errmsg_string) :
errmsg("invalid value for parameter \"%s\": \"%s\"",
conf->gen.name, *newval ? *newval : ""),
GUC_check_errdetail_string ?
errdetail_internal("%s", GUC_check_errdetail_string) : 0,
GUC_check_errhint_string ?
errhint("%s", GUC_check_errhint_string) : 0)); /* Flush any strings created in ErrorContext */
FlushErrorState();
result = false;
}
}
PG_CATCH();
{
guc_free(*newval);
PG_RE_THROW();
}
PG_END_TRY();
return result;
}
staticbool
call_enum_check_hook(struct config_enum *conf, int *newval, void **extra,
GucSource source, int elevel)
{ /* Quick success if no hook */ if (!conf->check_hook) returntrue;
/* Reset variables that might be set by hook */
GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE;
GUC_check_errmsg_string = NULL;
GUC_check_errdetail_string = NULL;
GUC_check_errhint_string = NULL;
if (!conf->check_hook(newval, extra, source))
{
ereport(elevel,
(errcode(GUC_check_errcode_value),
GUC_check_errmsg_string ?
errmsg_internal("%s", GUC_check_errmsg_string) :
errmsg("invalid value for parameter \"%s\": \"%s\"",
conf->gen.name,
config_enum_lookup_by_value(conf, *newval)),
GUC_check_errdetail_string ?
errdetail_internal("%s", GUC_check_errdetail_string) : 0,
GUC_check_errhint_string ?
errhint("%s", GUC_check_errhint_string) : 0)); /* Flush any strings created in ErrorContext */
FlushErrorState(); returnfalse;
}
returntrue;
}
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.365Bemerkung:
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.