From: Bruce Momjian Date: Mon, 14 Aug 2006 02:27:27 +0000 (+0000) Subject: Revert (again) GUC patch to return commented fields to their default X-Git-Tag: REL8_2_BETA1~319 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f058451871879392ed9295daed3f5310e85f3986;p=postgresql Revert (again) GUC patch to return commented fields to their default values, due to concern about the patch. --- diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l index a0044abc86..463b5541b3 100644 --- a/src/backend/utils/misc/guc-file.l +++ b/src/backend/utils/misc/guc-file.l @@ -4,7 +4,7 @@ * * Copyright (c) 2000-2006, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.44 2006/08/13 02:22:24 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.45 2006/08/14 02:27:26 momjian Exp $ */ %{ @@ -50,8 +50,7 @@ int GUC_yylex(void); static bool ParseConfigFile(const char *config_file, const char *calling_file, int depth, GucContext context, int elevel, struct name_value_pair **head_p, - struct name_value_pair **tail_p, - int *varcount); + struct name_value_pair **tail_p); static void free_name_value_list(struct name_value_pair * list); static char *GUC_scanstr(const char *s); @@ -115,11 +114,8 @@ STRING \'([^'\\\n]|\\.|\'\')*\' void ProcessConfigFile(GucContext context) { - int elevel, i; + int elevel; struct name_value_pair *item, *head, *tail; - char *env; - bool *apply_list = NULL; - int varcount = 0; Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP); @@ -138,109 +134,25 @@ ProcessConfigFile(GucContext context) if (!ParseConfigFile(ConfigFileName, NULL, 0, context, elevel, - &head, &tail, &varcount)) + &head, &tail)) goto cleanup_list; - /* Can we allocate memory here, what about leaving here prematurely? */ - apply_list = (bool *) palloc(sizeof(bool) * varcount); - /* Check if all options are valid */ - for (item = head, i = 0; item; item = item->next, i++) + for (item = head; item; item = item->next) { - bool isEqual, isContextOk; - - if (!verify_config_option(item->name, item->value, context, - PGC_S_FILE, &isEqual, &isContextOk)) - { - ereport(elevel, - (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), - errmsg("configuration file is invalid"))); + if (!set_config_option(item->name, item->value, context, + PGC_S_FILE, false, false)) goto cleanup_list; - } - - if (isContextOk == false) - { - apply_list[i] = false; - if (context == PGC_SIGHUP) - { - if (isEqual == false) - ereport(elevel, - (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), - errmsg("parameter \"%s\" cannot be changed after server start; configuration file change ignored", - item->name))); - } - else - /* if it is boot phase, context must be valid for all - * configuration item. */ - goto cleanup_list; - } - else - apply_list[i] = true; } /* If we got here all the options checked out okay, so apply them. */ - for (item = head, i = 0; item; item = item->next, i++) - if (apply_list[i]) - set_config_option(item->name, item->value, context, - PGC_S_FILE, false, true); - - if (context == PGC_SIGHUP) + for (item = head; item; item = item->next) { - /* - * Revert all "untouched" options with reset source PGC_S_FILE to - * default/boot value. - */ - for (i = 0; i < num_guc_variables; i++) - { - struct config_generic *gconf = guc_variables[i]; - - if (gconf->reset_source == PGC_S_FILE && - !(gconf->status & GUC_IN_CONFFILE)) - { - if (gconf->context == PGC_BACKEND && IsUnderPostmaster) - ; /* Be silent. Does any body want message from each session? */ - else if (gconf->context == PGC_POSTMASTER) - ereport(elevel, - (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), - errmsg("parameter \"%s\" cannot be changed (commented) after server start; configuration file change ignored", - gconf->name))); - else if (set_config_option(gconf->name, NULL, context, - PGC_S_FILE, false, true)) - { - GucStack *stack; - - gconf->reset_source = PGC_S_DEFAULT; - - for (stack = gconf->stack; stack; stack = stack->prev) - if (stack->source == PGC_S_FILE) - stack->source = PGC_S_DEFAULT; - - ereport(elevel, - (errcode(ERRCODE_SUCCESSFUL_COMPLETION), - errmsg("configuration option %s returned to default value", gconf->name))); - } - } - gconf->status &= ~GUC_IN_CONFFILE; - } - - /* - * Revert to environment variable. PGPORT is ignored, because it cannot be - * set in running state. - */ - env = getenv("PGDATESTYLE"); - if (env != NULL) - set_config_option("datestyle", env, context, - PGC_S_ENV_VAR, false, true); - - env = getenv("PGCLIENTENCODING"); - if (env != NULL) - set_config_option("client_encoding", env, context, - PGC_S_ENV_VAR, false, true); + set_config_option(item->name, item->value, context, + PGC_S_FILE, false, true); } -cleanup_list: - if (apply_list) - pfree(apply_list); + cleanup_list: free_name_value_list(head); } @@ -277,14 +189,13 @@ static bool ParseConfigFile(const char *config_file, const char *calling_file, int depth, GucContext context, int elevel, struct name_value_pair **head_p, - struct name_value_pair **tail_p, - int *varcount) + struct name_value_pair **tail_p) { - bool OK = true; - char abs_path[MAXPGPATH]; - FILE *fp; + bool OK = true; + char abs_path[MAXPGPATH]; + FILE *fp; YY_BUFFER_STATE lex_buffer; - int token; + int token; /* * Reject too-deep include nesting depth. This is just a safety check @@ -378,7 +289,7 @@ ParseConfigFile(const char *config_file, const char *calling_file, if (!ParseConfigFile(opt_value, config_file, depth + 1, context, elevel, - head_p, tail_p, varcount)) + head_p, tail_p)) { pfree(opt_name); pfree(opt_value); @@ -422,7 +333,6 @@ ParseConfigFile(const char *config_file, const char *calling_file, else (*tail_p)->next = item; *tail_p = item; - (*varcount)++; } /* break out of loop if read EOF, else loop for next line */ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index cda5a41142..0e16035ef6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut . * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.340 2006/08/13 15:37:02 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.341 2006/08/14 02:27:26 momjian Exp $ * *-------------------------------------------------------------------- */ @@ -2313,7 +2313,7 @@ guc_strdup(int elevel, const char *src) * states). */ static void -set_string_field(struct config_string *conf, char **field, char *newval) +set_string_field(struct config_string * conf, char **field, char *newval) { char *oldval = *field; GucStack *stack; @@ -2535,7 +2535,8 @@ add_placeholder_variable(const char *name, int elevel) gen = &var->gen; memset(var, 0, sz); - if ((gen->name = guc_strdup(elevel, name)) == NULL) + gen->name = guc_strdup(elevel, name); + if (gen->name == NULL) { free(var); return NULL; @@ -2692,40 +2693,40 @@ InitializeGUCOptions(void) { struct config_bool *conf = (struct config_bool *) gconf; - if (conf->assign_hook && - !(*conf->assign_hook) (conf->boot_val, true, - PGC_S_DEFAULT)) - elog(FATAL, "failed to initialize %s to %d", - conf->gen.name, (int) conf->boot_val); - *conf->variable = conf->reset_val = conf->boot_val; + if (conf->assign_hook) + if (!(*conf->assign_hook) (conf->reset_val, true, + PGC_S_DEFAULT)) + elog(FATAL, "failed to initialize %s to %d", + conf->gen.name, (int) conf->reset_val); + *conf->variable = conf->reset_val; break; } case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; - Assert(conf->boot_val >= conf->min); - Assert(conf->boot_val <= conf->max); - if (conf->assign_hook && - !(*conf->assign_hook) (conf->boot_val, true, - PGC_S_DEFAULT)) - elog(FATAL, "failed to initialize %s to %d", - conf->gen.name, conf->boot_val); - *conf->variable = conf->reset_val = conf->boot_val; + Assert(conf->reset_val >= conf->min); + Assert(conf->reset_val <= conf->max); + if (conf->assign_hook) + if (!(*conf->assign_hook) (conf->reset_val, true, + PGC_S_DEFAULT)) + elog(FATAL, "failed to initialize %s to %d", + conf->gen.name, conf->reset_val); + *conf->variable = conf->reset_val; break; } case PGC_REAL: { struct config_real *conf = (struct config_real *) gconf; - Assert(conf->boot_val >= conf->min); - Assert(conf->boot_val <= conf->max); - if (conf->assign_hook && - !(*conf->assign_hook) (conf->boot_val, true, - PGC_S_DEFAULT)) - elog(FATAL, "failed to initialize %s to %g", - conf->gen.name, conf->boot_val); - *conf->variable = conf->reset_val = conf->boot_val; + Assert(conf->reset_val >= conf->min); + Assert(conf->reset_val <= conf->max); + if (conf->assign_hook) + if (!(*conf->assign_hook) (conf->reset_val, true, + PGC_S_DEFAULT)) + elog(FATAL, "failed to initialize %s to %g", + conf->gen.name, conf->reset_val); + *conf->variable = conf->reset_val; break; } case PGC_STRING: @@ -2738,8 +2739,10 @@ InitializeGUCOptions(void) conf->tentative_val = NULL; if (conf->boot_val == NULL) + { /* Cannot set value yet */ break; + } str = guc_strdup(FATAL, conf->boot_val); conf->reset_val = str; @@ -2751,8 +2754,10 @@ InitializeGUCOptions(void) newstr = (*conf->assign_hook) (str, true, PGC_S_DEFAULT); if (newstr == NULL) + { elog(FATAL, "failed to initialize %s to \"%s\"", conf->gen.name, str); + } else if (newstr != str) { free(str); @@ -2792,10 +2797,12 @@ InitializeGUCOptions(void) if (env != NULL) SetConfigOption("port", env, PGC_POSTMASTER, PGC_S_ENV_VAR); - if ((env = getenv("PGDATESTYLE")) != NULL) + env = getenv("PGDATESTYLE"); + if (env != NULL) SetConfigOption("datestyle", env, PGC_POSTMASTER, PGC_S_ENV_VAR); - if ((env = getenv("PGCLIENTENCODING")) != NULL) + env = getenv("PGCLIENTENCODING"); + if (env != NULL) SetConfigOption("client_encoding", env, PGC_POSTMASTER, PGC_S_ENV_VAR); } @@ -3172,7 +3179,7 @@ AtEOXact_GUC(bool isCommit, bool isSubXact) for (i = 0; i < num_guc_variables; i++) { struct config_generic *gconf = guc_variables[i]; - int my_status = gconf->status & (~GUC_IN_CONFFILE); + int my_status = gconf->status; GucStack *stack = gconf->stack; bool useTentative; bool changed; @@ -3683,294 +3690,96 @@ call_string_assign_hook(GucStringAssignHook assign_hook, return result; } + /* - * Try to parse value. Determine what is type and call related - * parsing function or if newval is equal to NULL, reset value - * to default or bootval. If the value parsed okay return true, - * else false. + * Sets option `name' to given value. The value should be a string + * which is going to be parsed and converted to the appropriate data + * type. The context and source parameters indicate in which context this + * 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 + * the checks to see if it would work. + * + * If there is an error (non-existing option, invalid value) then an + * ereport(ERROR) is thrown *unless* this is called in a context where we + * don't want to ereport (currently, startup or SIGHUP config file reread). + * In that case we write a suitable error message via ereport(DEBUG) and + * return false. This is working around the deficiencies in the ereport + * mechanism, so don't blame me. In all other cases, the function + * returns true, including cases where the input is valid but we chose + * not to apply it because of context or source-priority considerations. + * + * See also SetConfigOption for an external interface. */ -static bool -parse_value(int elevel, const struct config_generic *record, - const char *value, GucSource *source, bool changeVal, - union config_var_value *retval) +bool +set_config_option(const char *name, const char *value, + GucContext context, GucSource source, + bool isLocal, bool changeVal) { - /* - * Evaluate value and set variable. - */ - switch (record->vartype) - { - case PGC_BOOL: - { - struct config_bool *conf = (struct config_bool *) record; - bool newval; - - if (value) - { - if (!parse_bool(value, &newval)) - { - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("parameter \"%s\" requires a Boolean value", - record->name))); - return false; - } - } - else - { - /* - * Revert value to default if source is configuration file. It is used when - * configuration parameter is removed/commented out in the config file. Else - * RESET or SET TO DEFAULT command is called and reset_val is used. - */ - if (*source == PGC_S_FILE) - newval = conf->boot_val; - else - { - newval = conf->reset_val; - *source = conf->gen.reset_source; - } - } - - if (conf->assign_hook && - !(*conf->assign_hook) (newval, changeVal, *source)) - { - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid value for parameter \"%s\": %d", - record->name, (int) newval))); - return false; - } - if (retval) - retval->boolval = newval; - break; - } - - case PGC_INT: - { - struct config_int *conf = (struct config_int *) record; - int newval; - - if (value) - { - if (!parse_int(value, &newval, conf->gen.flags)) - { - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("parameter \"%s\" requires an integer value", - record->name))); - return false; - } - if (newval < conf->min || newval > conf->max) - { - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("%d is outside the valid range for parameter \"%s\" (%d .. %d)", - newval, record->name, conf->min, conf->max))); - return false; - } - } - else - { - /* - * Revert value to default if source is configuration file. It is used when - * configuration parameter is removed/commented out in the config file. Else - * RESET or SET TO DEFAULT command is called and reset_val is used. - */ - if (*source == PGC_S_FILE) - newval = conf->boot_val; - else - { - newval = conf->reset_val; - *source = conf->gen.reset_source; - } - } - - if (conf->assign_hook) - if (!(*conf->assign_hook) (newval, changeVal, *source)) - { - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid value for parameter \"%s\": %d", - record->name, newval))); - return false; - } - if (retval) - retval->intval = newval; - break; - } - - case PGC_REAL: - { - struct config_real *conf = (struct config_real *) record; - double newval; - - if (value) - { - if (!parse_real(value, &newval)) - { - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("parameter \"%s\" requires a numeric value", - record->name))); - return false; - } - if (newval < conf->min || newval > conf->max) - { - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("%g is outside the valid range for parameter \"%s\" (%g .. %g)", - newval, record->name, conf->min, conf->max))); - return false; - } - } - else - { - /* - * Revert value to default if source is configuration file. It is used when - * configuration parameter is removed/commented out in the config file. Else - * RESET or SET TO DEFAULT command is called and reset_val is used. - */ - if (*source == PGC_S_FILE) - newval = conf->boot_val; - else - { - newval = conf->reset_val; - *source = conf->gen.reset_source; - } - } - - if (conf->assign_hook && - !(*conf->assign_hook) (newval, changeVal, *source)) - { - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid value for parameter \"%s\": %g", - record->name, newval))); - return false; - } - if (retval) - retval->realval = newval; - break; - } - - case PGC_STRING: - { - struct config_string *conf = (struct config_string *) record; - char *newval; - - if (value) - { - if ((newval = guc_strdup(elevel, value)) == NULL) - return false; - /* - * The only sort of "parsing" check we need to do is - * apply truncation if GUC_IS_NAME. - */ - if (conf->gen.flags & GUC_IS_NAME) - truncate_identifier(newval, strlen(newval), true); - } - else if (*source == PGC_S_FILE) - { - /* Revert value to default when item is removed from config file. */ - if (conf->boot_val != NULL) - { - newval = guc_strdup(elevel, conf->boot_val); - if (newval == NULL) - return false; - } - else - return false; - } - else if (conf->reset_val) - { - /* - * We could possibly avoid strdup here, but easier to make - * this case work the same as the normal assignment case. - */ - if ((newval = guc_strdup(elevel, conf->reset_val)) == NULL) - return false; - *source = conf->gen.reset_source; - } - else - /* Nothing to reset to, as yet; so do nothing */ - break; - - if (conf->assign_hook) - { - const char *hookresult; - - /* - * If the hook ereports, we have to make sure we free - * newval, else it will be a permanent memory leak. - */ - hookresult = call_string_assign_hook(conf->assign_hook, - newval, - changeVal, - *source); - if (hookresult == NULL) - { - free(newval); - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid value for parameter \"%s\": \"%s\"", - record->name, value ? value : ""))); - return false; - } - else if (hookresult != newval) - { - free(newval); + struct config_generic *record; + int elevel; + bool makeDefault; - /* - * Having to cast away const here is annoying, but the - * alternative is to declare assign_hooks as returning - * char*, which would mean they'd have to cast away - * const, or as both taking and returning char*, which - * doesn't seem attractive either --- we don't want - * them to scribble on the passed str. - */ - newval = (char *) hookresult; - } - } + if (context == PGC_SIGHUP || source == PGC_S_DEFAULT) + { + /* + * To avoid cluttering the log, only the postmaster bleats loudly + * about problems with the config file. + */ + elevel = IsUnderPostmaster ? DEBUG2 : LOG; + } + else if (source == PGC_S_DATABASE || source == PGC_S_USER) + elevel = INFO; + else + elevel = ERROR; - if (retval) - retval->stringval = newval; - else - free(newval); - break; - } + record = find_option(name, elevel); + if (record == NULL) + { + ereport(elevel, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("unrecognized configuration parameter \"%s\"", name))); + return false; } - return true; -} -/* - * Check if the option can be set at this time. See guc.h for the precise - * rules. - */ -static bool -checkContext(int elevel, struct config_generic *record, GucContext context) -{ + /* + * Check if the option can be set at this time. See guc.h for the precise + * rules. Note that we don't want to throw errors if we're in the SIGHUP + * context. In that case we just ignore the attempt and return true. + */ switch (record->context) { case PGC_INTERNAL: + if (context == PGC_SIGHUP) + return true; if (context != PGC_INTERNAL) { ereport(elevel, (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), errmsg("parameter \"%s\" cannot be changed", - record->name))); + name))); return false; } break; case PGC_POSTMASTER: if (context == PGC_SIGHUP) - return false; + { + if (changeVal && !is_newvalue_equal(record, value)) + ereport(elevel, + (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), + errmsg("parameter \"%s\" cannot be changed after server start; configuration file change ignored", + name))); + return true; + } if (context != PGC_POSTMASTER) { ereport(elevel, (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), errmsg("parameter \"%s\" cannot be changed after server start", - record->name))); + name))); return false; } break; @@ -3980,7 +3789,7 @@ checkContext(int elevel, struct config_generic *record, GucContext context) ereport(elevel, (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), errmsg("parameter \"%s\" cannot be changed now", - record->name))); + name))); return false; } @@ -4003,16 +3812,14 @@ checkContext(int elevel, struct config_generic *record, GucContext context) * backend start. */ if (IsUnderPostmaster) - { - return false; - } + return true; } else if (context != PGC_BACKEND && context != PGC_POSTMASTER) { ereport(elevel, (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), errmsg("parameter \"%s\" cannot be set after connection start", - record->name))); + name))); return false; } break; @@ -4022,7 +3829,7 @@ checkContext(int elevel, struct config_generic *record, GucContext context) ereport(elevel, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied to set parameter \"%s\"", - record->name))); + name))); return false; } break; @@ -4030,128 +3837,12 @@ checkContext(int elevel, struct config_generic *record, GucContext context) /* always okay */ break; } - return true; -} - -/* - * Get error level for different sources and context. - */ -static int -get_elevel(GucContext context, GucSource source) -{ - int elevel; - if (context == PGC_SIGHUP || source == PGC_S_DEFAULT) - { - /* - * To avoid cluttering the log, only the postmaster bleats loudly - * about problems with the config file. - */ - elevel = IsUnderPostmaster ? DEBUG2 : LOG; - } - else if (source == PGC_S_DATABASE || source == PGC_S_USER) - elevel = INFO; - else - elevel = ERROR; - - return elevel; -} - -/* - * Verify if option exists and value is valid. - * It is primary used for validation of items in configuration file. - */ -bool -verify_config_option(const char *name, const char *value, - GucContext context, GucSource source, - bool *isNewEqual, bool *isContextOK) -{ - int elevel; - struct config_generic *record; - - elevel = get_elevel(context, source); - - record = find_option(name, elevel); - if (record == NULL) - { - ereport(elevel, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("unrecognized configuration parameter \"%s\"", name))); - return false; - } - - if (parse_value(elevel, record, value, &source, false, NULL)) - { - /* - * Mark record as present in the config file. Be carefull if - * you use this function for another purpose than config file - * verification. It causes confusion in the config file parser. - */ - record->status |= GUC_IN_CONFFILE; - - if (isNewEqual != NULL) - *isNewEqual = is_newvalue_equal(record, value); - if (isContextOK != NULL) - *isContextOK = checkContext(elevel, record, context); - } - else - return false; - - return true; -} - - -/* - * Sets option `name' to given value. The value should be a string - * which is going to be parsed and converted to the appropriate data - * type. The context and source parameters indicate in which context this - * 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 - * the checks to see if it would work. - * - * If there is an error (non-existing option, invalid value) then an - * ereport(ERROR) is thrown *unless* this is called in a context where we - * don't want to ereport (currently, startup or SIGHUP config file reread). - * In that case we write a suitable error message via ereport(DEBUG) and - * return false. This is working around the deficiencies in the ereport - * mechanism, so don't blame me. In all other cases, the function - * returns true, including cases where the input is valid but we chose - * not to apply it because of context or source-priority considerations. - * - * See also SetConfigOption for an external interface. - */ -bool -set_config_option(const char *name, const char *value, - GucContext context, GucSource source, - bool isLocal, bool changeVal) -{ - struct config_generic *record; - int elevel; - bool makeDefault; - - elevel = get_elevel(context, source); - - record = find_option(name, elevel); - if (record == NULL) - { - ereport(elevel, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("unrecognized configuration parameter \"%s\"", name))); - return false; - } - - /* Check if change is allowed in the running context. */ - if (!checkContext(elevel, record, context)) - return false; /* * Should we set reset/stacked values? (If so, the behavior is not * transactional.) */ - makeDefault = changeVal && (source <= PGC_S_OVERRIDE) && - (value != NULL || source == PGC_S_FILE); + makeDefault = changeVal && (source <= PGC_S_OVERRIDE) && (value != NULL); /* * Ignore attempted set if overridden by previously processed setting. @@ -4180,23 +3871,44 @@ set_config_option(const char *name, const char *value, { struct config_bool *conf = (struct config_bool *) record; bool newval; - - if (!parse_value(elevel, record, value, &source, changeVal, - (union config_var_value*) &newval)) - return false; + + if (value) + { + if (!parse_bool(value, &newval)) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("parameter \"%s\" requires a Boolean value", + name))); + return false; + } + } + else + { + newval = conf->reset_val; + source = conf->gen.reset_source; + } + + if (conf->assign_hook) + if (!(*conf->assign_hook) (newval, changeVal, source)) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": %d", + name, (int) newval))); + return false; + } if (changeVal || makeDefault) { /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen); - if (changeVal) { *conf->variable = newval; conf->gen.source = source; } - if (makeDefault) { GucStack *stack; @@ -4236,22 +3948,51 @@ set_config_option(const char *name, const char *value, struct config_int *conf = (struct config_int *) record; int newval; - if (!parse_value(elevel, record, value, &source, changeVal, - (union config_var_value*) &newval)) - return false; + if (value) + { + if (!parse_int(value, &newval, conf->gen.flags)) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("parameter \"%s\" requires an integer value", + name))); + return false; + } + if (newval < conf->min || newval > conf->max) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("%d is outside the valid range for parameter \"%s\" (%d .. %d)", + newval, name, conf->min, conf->max))); + return false; + } + } + else + { + newval = conf->reset_val; + source = conf->gen.reset_source; + } + + if (conf->assign_hook) + if (!(*conf->assign_hook) (newval, changeVal, source)) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": %d", + name, newval))); + return false; + } if (changeVal || makeDefault) { /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen); - if (changeVal) { *conf->variable = newval; conf->gen.source = source; } - if (makeDefault) { GucStack *stack; @@ -4291,22 +4032,51 @@ set_config_option(const char *name, const char *value, struct config_real *conf = (struct config_real *) record; double newval; - if (!parse_value(elevel, record, value, &source, changeVal, - (union config_var_value*) &newval)) - return false; + if (value) + { + if (!parse_real(value, &newval)) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("parameter \"%s\" requires a numeric value", + name))); + return false; + } + if (newval < conf->min || newval > conf->max) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("%g is outside the valid range for parameter \"%s\" (%g .. %g)", + newval, name, conf->min, conf->max))); + return false; + } + } + else + { + newval = conf->reset_val; + source = conf->gen.reset_source; + } + + if (conf->assign_hook) + if (!(*conf->assign_hook) (newval, changeVal, source)) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": %g", + name, newval))); + return false; + } if (changeVal || makeDefault) { /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen); - if (changeVal) { *conf->variable = newval; conf->gen.source = source; } - if (makeDefault) { GucStack *stack; @@ -4346,22 +4116,82 @@ set_config_option(const char *name, const char *value, struct config_string *conf = (struct config_string *) record; char *newval; - if (!parse_value(elevel, record, value, &source, changeVal, - (union config_var_value*) &newval)) - return false; + if (value) + { + newval = guc_strdup(elevel, value); + if (newval == NULL) + return false; + /* + * The only sort of "parsing" check we need to do is + * apply truncation if GUC_IS_NAME. + */ + if (conf->gen.flags & GUC_IS_NAME) + truncate_identifier(newval, strlen(newval), true); + } + else if (conf->reset_val) + { + /* + * We could possibly avoid strdup here, but easier to make + * this case work the same as the normal assignment case. + */ + newval = guc_strdup(elevel, conf->reset_val); + if (newval == NULL) + return false; + source = conf->gen.reset_source; + } + else + { + /* Nothing to reset to, as yet; so do nothing */ + break; + } + + if (conf->assign_hook) + { + const char *hookresult; + + /* + * If the hook ereports, we have to make sure we free + * newval, else it will be a permanent memory leak. + */ + hookresult = call_string_assign_hook(conf->assign_hook, + newval, + changeVal, + source); + if (hookresult == NULL) + { + free(newval); + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%s\"", + name, value ? value : ""))); + return false; + } + else if (hookresult != newval) + { + free(newval); + + /* + * Having to cast away const here is annoying, but the + * alternative is to declare assign_hooks as returning + * char*, which would mean they'd have to cast away + * const, or as both taking and returning char*, which + * doesn't seem attractive either --- we don't want + * them to scribble on the passed str. + */ + newval = (char *) hookresult; + } + } if (changeVal || makeDefault) { /* Save old value to support transaction abort */ if (!makeDefault) push_old_value(&conf->gen); - if (changeVal) { set_string_field(conf, conf->variable, newval); conf->gen.source = source; } - if (makeDefault) { GucStack *stack; @@ -4937,7 +4767,8 @@ GetPGVariableResultDesc(const char *name) /* need a tuple descriptor representing a single TEXT column */ tupdesc = CreateTemplateTupleDesc(1, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname, TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname, + TEXTOID, -1, 0); } return tupdesc; } @@ -5029,6 +4860,7 @@ ShowAllGUCConfig(DestReceiver *dest) /* send it to dest */ do_tup_output(tstate, values); + /* clean up */ if (values[1] != NULL) pfree(values[1]); } @@ -5482,9 +5314,6 @@ _ShowOption(struct config_generic * record, bool use_units) static bool is_newvalue_equal(struct config_generic *record, const char *newvalue) { - if (!newvalue) - return false; - switch (record->vartype) { case PGC_BOOL: @@ -5512,10 +5341,7 @@ is_newvalue_equal(struct config_generic *record, const char *newvalue) { struct config_string *conf = (struct config_string *) record; - if (!*conf->variable) /* custom variable with no value yet */ - return false; - else - return strcmp(*conf->variable, newvalue) == 0; + return strcmp(*conf->variable, newvalue) == 0; } } diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index e966ac9fd8..403d022b7a 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -7,7 +7,7 @@ * Copyright (c) 2000-2006, PostgreSQL Global Development Group * Written by Peter Eisentraut . * - * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.74 2006/08/13 01:30:17 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.75 2006/08/14 02:27:27 momjian Exp $ *-------------------------------------------------------------------- */ #ifndef GUC_H @@ -193,9 +193,6 @@ extern void ParseLongOption(const char *string, char **name, char **value); extern bool set_config_option(const char *name, const char *value, GucContext context, GucSource source, bool isLocal, bool changeVal); -extern bool verify_config_option(const char *name, const char *value, - GucContext context, GucSource source, - bool *isNewEqual, bool *isContextOK); extern char *GetConfigOptionByName(const char *name, const char **varname); extern void GetConfigOptionByNum(int varnum, const char **values, bool *noshow); extern int GetNumConfigOptions(void); diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h index 6345fb1abd..a0ebf2c529 100644 --- a/src/include/utils/guc_tables.h +++ b/src/include/utils/guc_tables.h @@ -7,7 +7,7 @@ * * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.27 2006/08/13 02:22:24 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.28 2006/08/14 02:27:27 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -143,8 +143,7 @@ struct config_generic #define GUC_HAVE_TENTATIVE 0x0001 /* tentative value is defined */ #define GUC_HAVE_LOCAL 0x0002 /* a SET LOCAL has been executed */ #define GUC_HAVE_STACK 0x0004 /* we have stacked prior value(s) */ -#define GUC_IN_CONFFILE 0x0008 /* value shows up in the configuration - file (is not commented) */ + /* GUC records for specific variable types */ @@ -154,12 +153,11 @@ struct config_bool /* these fields must be set correctly in initial value: */ /* (all but reset_val are constants) */ bool *variable; - bool boot_val; + bool reset_val; GucBoolAssignHook assign_hook; GucShowHook show_hook; /* variable fields, initialized at runtime: */ bool tentative_val; - bool reset_val; }; struct config_int @@ -168,14 +166,13 @@ struct config_int /* these fields must be set correctly in initial value: */ /* (all but reset_val are constants) */ int *variable; - int boot_val; + int reset_val; int min; int max; GucIntAssignHook assign_hook; GucShowHook show_hook; /* variable fields, initialized at runtime: */ int tentative_val; - int reset_val; }; struct config_real @@ -184,14 +181,13 @@ struct config_real /* these fields must be set correctly in initial value: */ /* (all but reset_val are constants) */ double *variable; - double boot_val; + double reset_val; double min; double max; GucRealAssignHook assign_hook; GucShowHook show_hook; /* variable fields, initialized at runtime: */ double tentative_val; - double reset_val; }; struct config_string