mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 00:03:57 -04:00 
			
		
		
		
	Make configuration parameters fall back to their default values when they
are removed from the configuration file. Joachim Wieland
This commit is contained in:
		
							parent
							
								
									adf7788c5e
								
							
						
					
					
						commit
						b7edb568bd
					
				| @ -4,7 +4,7 @@ | ||||
|  * | ||||
|  * Copyright (c) 2000-2007, PostgreSQL Global Development Group | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.49 2007/03/13 14:32:25 petere Exp $ | ||||
|  * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.50 2007/04/21 20:02:40 petere Exp $ | ||||
|  */ | ||||
| 
 | ||||
| %{ | ||||
| @ -116,6 +116,9 @@ ProcessConfigFile(GucContext context) | ||||
| { | ||||
| 	int			elevel; | ||||
| 	struct name_value_pair *item, *head, *tail; | ||||
| 	int			i; | ||||
| 	bool	   *in_conffile = NULL; | ||||
| 	const char *var; | ||||
| 
 | ||||
| 	Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP); | ||||
| 
 | ||||
| @ -140,19 +143,158 @@ ProcessConfigFile(GucContext context) | ||||
| 	/* Check if all options are valid */ | ||||
| 	for (item = head; item; item = item->next) | ||||
| 	{ | ||||
| 		char *sep = strchr(item->name, GUC_QUALIFIER_SEPARATOR); | ||||
| 		if (sep && !is_custom_class(item->name, sep - item->name)) | ||||
| 		{ | ||||
| 			ereport(elevel, | ||||
| 				(errcode(ERRCODE_UNDEFINED_OBJECT), | ||||
| 				 errmsg("unrecognized configuration parameter \"%s\"", | ||||
| 						item->name))); | ||||
| 			goto cleanup_list; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!set_config_option(item->name, item->value, context, | ||||
| 							   PGC_S_FILE, false, false)) | ||||
| 			goto cleanup_list; | ||||
| 	} | ||||
| 
 | ||||
| 	/* If we got here all the options checked out okay, so apply them. */ | ||||
| 
 | ||||
| 	/* | ||||
| 	 * Mark all variables as not showing up in the config file.  The | ||||
| 	 * allocation has to take place after ParseConfigFile() since this | ||||
| 	 * function can change num_guc_variables due to custom variables. | ||||
| 	 * It would be easier to add a new field or status bit to struct | ||||
| 	 * conf_generic, but that way we would expose internal information | ||||
| 	 * that is just needed here in the following few lines.  The price | ||||
| 	 * to pay for this separation are a few more loops over the set of | ||||
| 	 * configuration options, but those are expected to be rather few | ||||
| 	 * and we only have to pay the cost at SIGHUP.  We initialize | ||||
| 	 * in_conffile only here because set_config_option() makes | ||||
| 	 * guc_variables grow with custom variables. | ||||
| 	 */ | ||||
| 	in_conffile = guc_malloc(elevel, num_guc_variables * sizeof(bool)); | ||||
| 	if (!in_conffile) | ||||
| 		goto cleanup_list; | ||||
| 	for (i = 0; i < num_guc_variables; i++) | ||||
| 		in_conffile[i] = false; | ||||
| 
 | ||||
| 	for (item = head; item; item = item->next) | ||||
| 	{ | ||||
| 		set_config_option(item->name, item->value, context, | ||||
| 						  PGC_S_FILE, false, true); | ||||
| 		/* | ||||
| 		 * After set_config_option() the variable name item->name is | ||||
| 		 * known to exist. | ||||
| 		 */ | ||||
| 		Assert(guc_get_index(item->name) >= 0); | ||||
| 		in_conffile[guc_get_index(item->name)] = true; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < num_guc_variables; i++) | ||||
| 	{ | ||||
| 		struct config_generic *gconf = guc_variables[i]; | ||||
| 		if (!in_conffile[i] && gconf->source == PGC_S_FILE) | ||||
| 		{ | ||||
| 			if (gconf->context < PGC_SIGHUP) | ||||
| 				ereport(elevel, | ||||
| 					(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), | ||||
| 							 errmsg("parameter \"%s\" cannot be changed after server start; configuration file change ignored", | ||||
| 									gconf->name))); | ||||
| 			else | ||||
| 			{ | ||||
| 					/* prepare */ | ||||
| 					GucStack   *stack; | ||||
| 					if (gconf->reset_source == PGC_S_FILE) | ||||
| 						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; | ||||
| 					/* apply the default */ | ||||
| 					set_config_option(gconf->name, NULL, context, | ||||
| 									  PGC_S_DEFAULT, false, true); | ||||
| 			} | ||||
| 		} | ||||
| 		else if (!in_conffile[i] && gconf->reset_source == PGC_S_FILE) | ||||
| 		{ | ||||
| 			/*------ | ||||
| 			 * Change the reset_val to default_val.  Here's an | ||||
| 			 * example: In the configuration file we have | ||||
| 			 * | ||||
| 			 * seq_page_cost = 3.00 | ||||
| 			 * | ||||
| 			 * Now we execute in a session | ||||
| 			 * | ||||
| 			 * SET seq_page_cost TO 4.00; | ||||
| 			 * | ||||
| 			 * Then we remove this option from the configuration file | ||||
| 			 * and send SIGHUP. Now when you execute | ||||
| 			 * | ||||
| 			 * RESET seq_page_cost; | ||||
| 			 * | ||||
| 			 * it should fall back to 1.00 (the default value for | ||||
| 			 * seq_page_cost) and not to 3.00 (which is the current | ||||
| 			 * reset_val). | ||||
| 			 */ | ||||
| 
 | ||||
| 			switch (gconf->vartype) | ||||
| 			{ | ||||
| 				case PGC_BOOL: | ||||
| 					{ | ||||
| 						struct config_bool *conf; | ||||
| 						conf = (struct config_bool *) gconf; | ||||
| 						conf->reset_val = conf->boot_val; | ||||
| 						break; | ||||
| 					} | ||||
| 				case PGC_INT: | ||||
| 					{ | ||||
| 						struct config_int *conf; | ||||
| 						conf = (struct config_int *) gconf; | ||||
| 						conf->reset_val = conf->boot_val; | ||||
| 						break; | ||||
| 					} | ||||
| 				case PGC_REAL: | ||||
| 					{ | ||||
| 						struct config_real *conf; | ||||
| 						conf = (struct config_real *) gconf; | ||||
| 						conf->reset_val = conf->boot_val; | ||||
| 						break; | ||||
| 					} | ||||
| 				case PGC_STRING: | ||||
| 					{ | ||||
| 						struct config_string   *conf; | ||||
| 						conf = (struct config_string *) gconf; | ||||
| 						/* | ||||
| 						 * We can cast away the const here because we | ||||
| 						 * won't free the address.  It is protected by | ||||
| 						 * set_string_field() and string_field_used(). | ||||
| 						 */ | ||||
| 						conf->reset_val = (char *) conf->boot_val; | ||||
| 						break; | ||||
| 					} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* If we got here all the options checked out okay, so apply them. */ | ||||
| 	for (item = head; item; item = item->next) | ||||
| 		set_config_option(item->name, item->value, context, | ||||
| 						  PGC_S_FILE, false, true); | ||||
| 
 | ||||
| 	/* | ||||
| 	 * Reset variables to the value of environment variables | ||||
| 	 * (PGC_S_ENV_VAR overrules PGC_S_FILE).  PGPORT is ignored, | ||||
| 	 * because it cannot be changed without restart. | ||||
| 	 */ | ||||
| 	var = getenv("PGDATESTYLE"); | ||||
| 	if (var != NULL) | ||||
| 		set_config_option("datestyle", var, context, | ||||
| 						  PGC_S_ENV_VAR, false, true); | ||||
| 
 | ||||
| 	var = getenv("PGCLIENTENCODING"); | ||||
| 	if (var != NULL) | ||||
| 		set_config_option("client_encoding", var, context, | ||||
| 						  PGC_S_ENV_VAR, false, true); | ||||
| 
 | ||||
|  cleanup_list: | ||||
| 	free(in_conffile); | ||||
| 	free_name_value_list(head); | ||||
| } | ||||
| 
 | ||||
| @ -312,14 +454,14 @@ ParseConfigFile(const char *config_file, const char *calling_file, | ||||
| 			{ | ||||
| 				pfree(opt_name); | ||||
| 				pfree(opt_value); | ||||
| 				/* we assume error message was logged already */ | ||||
| 
 | ||||
| 				/* We assume the error message was logged already. */ | ||||
| 				OK = false; | ||||
| 				goto cleanup_exit; | ||||
| 			} | ||||
| 			pfree(opt_name); | ||||
| 			pfree(opt_value); | ||||
| 		} | ||||
| 		else | ||||
| 
 | ||||
| 		if (pg_strcasecmp(opt_name, "include") != 0) | ||||
| 		{ | ||||
| 			/* append to list */ | ||||
| 			struct name_value_pair *item; | ||||
|  | ||||
| @ -10,7 +10,7 @@ | ||||
|  * Written by Peter Eisentraut <peter_e@gmx.net>. | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.386 2007/04/18 16:44:18 alvherre Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.387 2007/04/21 20:02:40 petere Exp $ | ||||
|  * | ||||
|  *-------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -2481,7 +2481,8 @@ set_string_field(struct config_string * conf, char **field, char *newval) | ||||
| 	if (oldval == NULL || | ||||
| 		oldval == *(conf->variable) || | ||||
| 		oldval == conf->reset_val || | ||||
| 		oldval == conf->tentative_val) | ||||
| 		oldval == conf->tentative_val || | ||||
| 		oldval == conf->boot_val) | ||||
| 		return; | ||||
| 	for (stack = conf->gen.stack; stack; stack = stack->prev) | ||||
| 	{ | ||||
| @ -2504,7 +2505,8 @@ string_field_used(struct config_string * conf, char *strval) | ||||
| 
 | ||||
| 	if (strval == *(conf->variable) || | ||||
| 		strval == conf->reset_val || | ||||
| 		strval == conf->tentative_val) | ||||
| 		strval == conf->tentative_val || | ||||
| 		strval == conf->boot_val) | ||||
| 		return true; | ||||
| 	for (stack = conf->gen.stack; stack; stack = stack->prev) | ||||
| 	{ | ||||
| @ -2673,6 +2675,18 @@ add_guc_variable(struct config_generic * var, int elevel) | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| guc_get_index(const char *name) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < num_guc_variables; i++) | ||||
| 		if (strcasecmp(name, guc_variables[i]->name) == 0) | ||||
| 			return i; | ||||
| 
 | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Create and add a placeholder variable. It's presumed to belong | ||||
|  * to a valid custom variable class at this point. | ||||
| @ -2851,39 +2865,39 @@ InitializeGUCOptions(void) | ||||
| 					struct config_bool *conf = (struct config_bool *) gconf; | ||||
| 
 | ||||
| 					if (conf->assign_hook) | ||||
| 						if (!(*conf->assign_hook) (conf->reset_val, true, | ||||
| 						if (!(*conf->assign_hook) (conf->boot_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; | ||||
| 								 conf->gen.name, (int) conf->boot_val); | ||||
| 					*conf->variable = conf->reset_val = conf->boot_val; | ||||
| 					break; | ||||
| 				} | ||||
| 			case PGC_INT: | ||||
| 				{ | ||||
| 					struct config_int *conf = (struct config_int *) gconf; | ||||
| 
 | ||||
| 					Assert(conf->reset_val >= conf->min); | ||||
| 					Assert(conf->reset_val <= conf->max); | ||||
| 					Assert(conf->boot_val >= conf->min); | ||||
| 					Assert(conf->boot_val <= conf->max); | ||||
| 					if (conf->assign_hook) | ||||
| 						if (!(*conf->assign_hook) (conf->reset_val, true, | ||||
| 						if (!(*conf->assign_hook) (conf->boot_val, true, | ||||
| 												   PGC_S_DEFAULT)) | ||||
| 							elog(FATAL, "failed to initialize %s to %d", | ||||
| 								 conf->gen.name, conf->reset_val); | ||||
| 					*conf->variable = conf->reset_val; | ||||
| 								 conf->gen.name, conf->boot_val); | ||||
| 					*conf->variable = conf->reset_val = conf->boot_val;  | ||||
| 					break; | ||||
| 				} | ||||
| 			case PGC_REAL: | ||||
| 				{ | ||||
| 					struct config_real *conf = (struct config_real *) gconf; | ||||
| 
 | ||||
| 					Assert(conf->reset_val >= conf->min); | ||||
| 					Assert(conf->reset_val <= conf->max); | ||||
| 					Assert(conf->boot_val >= conf->min); | ||||
| 					Assert(conf->boot_val <= conf->max); | ||||
| 					if (conf->assign_hook) | ||||
| 						if (!(*conf->assign_hook) (conf->reset_val, true, | ||||
| 						if (!(*conf->assign_hook) (conf->boot_val, true, | ||||
| 												   PGC_S_DEFAULT)) | ||||
| 							elog(FATAL, "failed to initialize %s to %g", | ||||
| 								 conf->gen.name, conf->reset_val); | ||||
| 					*conf->variable = conf->reset_val; | ||||
| 								 conf->gen.name, conf->boot_val); | ||||
| 					*conf->variable = conf->reset_val = conf->boot_val;  | ||||
| 					break; | ||||
| 				} | ||||
| 			case PGC_STRING: | ||||
| @ -3945,6 +3959,13 @@ set_config_option(const char *name, const char *value, | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Do not replace a value that has been set on the command line by a SIGHUP | ||||
| 	 * reload | ||||
| 	 */ | ||||
| 	if (context == PGC_SIGHUP && record->source == PGC_S_ARGV) | ||||
| 		return true; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * 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 | ||||
| @ -4040,19 +4061,26 @@ set_config_option(const char *name, const char *value, | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Should we set reset/stacked values?	(If so, the behavior is not | ||||
| 	 * transactional.) | ||||
| 	 * Should we set reset/stacked values?  (If so, the behavior is not | ||||
| 	 * transactional.)  This is done either when we get a default | ||||
| 	 * value from the database's/user's/client's default settings or | ||||
| 	 * when we reset a value to its default. | ||||
| 	 */ | ||||
| 	makeDefault = changeVal && (source <= PGC_S_OVERRIDE) && (value != NULL); | ||||
| 	makeDefault = changeVal && (source <= PGC_S_OVERRIDE) | ||||
| 					&& ((value != NULL) || source == PGC_S_DEFAULT); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Ignore attempted set if overridden by previously processed setting. | ||||
| 	 * However, if changeVal is false then plow ahead anyway since we are | ||||
| 	 * trying to find out if the value is potentially good, not actually use | ||||
| 	 * it. Also keep going if makeDefault is true, since we may want to set | ||||
| 	 * the reset/stacked values even if we can't set the variable itself. | ||||
| 	 * Ignore attempted set if overridden by previously processed | ||||
| 	 * setting.  However, if changeVal is false then plow ahead anyway | ||||
| 	 * since we are trying to find out if the value is potentially | ||||
| 	 * good, not actually use it.  Also keep going if makeDefault is | ||||
| 	 * true, since we may want to set the reset/stacked values even if | ||||
| 	 * we can't set the variable itself.  There's one exception to | ||||
| 	 * this rule: if we want to apply the default value to variables | ||||
| 	 * that were removed from the configuration file.  This is | ||||
| 	 * indicated by source == PGC_S_DEFAULT. | ||||
| 	 */ | ||||
| 	if (record->source > source) | ||||
| 	if (record->source > source && source != PGC_S_DEFAULT) | ||||
| 	{ | ||||
| 		if (changeVal && !makeDefault) | ||||
| 		{ | ||||
| @ -4084,6 +4112,14 @@ set_config_option(const char *name, const char *value, | ||||
| 						return false; | ||||
| 					} | ||||
| 				} | ||||
| 				/*
 | ||||
| 				 * If value == NULL and source == PGC_S_DEFAULT then | ||||
| 				 * we reset some value to its default (removed from | ||||
| 				 * configuration file). | ||||
| 				 */ | ||||
| 				else if (source == PGC_S_DEFAULT) | ||||
| 					newval = conf->boot_val; | ||||
| 				/* else we handle a "RESET varname" command */ | ||||
| 				else | ||||
| 				{ | ||||
| 					newval = conf->reset_val; | ||||
| @ -4168,6 +4204,14 @@ set_config_option(const char *name, const char *value, | ||||
| 						return false; | ||||
| 					} | ||||
| 				} | ||||
| 				/*
 | ||||
| 				 * If value == NULL and source == PGC_S_DEFAULT then | ||||
| 				 * we reset some value to its default (removed from | ||||
| 				 * configuration file). | ||||
| 				 */ | ||||
| 				else if (source == PGC_S_DEFAULT) | ||||
| 					newval = conf->boot_val; | ||||
| 				/* else we handle a "RESET varname" command */ | ||||
| 				else | ||||
| 				{ | ||||
| 					newval = conf->reset_val; | ||||
| @ -4252,6 +4296,14 @@ set_config_option(const char *name, const char *value, | ||||
| 						return false; | ||||
| 					} | ||||
| 				} | ||||
| 				/*
 | ||||
| 				 * If value == NULL and source == PGC_S_DEFAULT then | ||||
| 				 * we reset some value to its default (removed from | ||||
| 				 * configuration file). | ||||
| 				 */ | ||||
| 				else if (source == PGC_S_DEFAULT) | ||||
| 					newval = conf->boot_val; | ||||
| 				/* else we handle a "RESET varname" command */ | ||||
| 				else | ||||
| 				{ | ||||
| 					newval = conf->reset_val; | ||||
| @ -4330,6 +4382,23 @@ set_config_option(const char *name, const char *value, | ||||
| 					if (conf->gen.flags & GUC_IS_NAME) | ||||
| 						truncate_identifier(newval, strlen(newval), true); | ||||
| 				} | ||||
| 				/*
 | ||||
| 				 * If value == NULL and source == PGC_S_DEFAULT then | ||||
| 				 * we reset some value to its default (removed from | ||||
| 				 * configuration file). | ||||
| 				 */ | ||||
| 				else if (source == PGC_S_DEFAULT) | ||||
| 				{ | ||||
| 					if (conf->boot_val == NULL) | ||||
| 						newval = NULL; | ||||
| 					else | ||||
| 					{ | ||||
| 						newval = guc_strdup(elevel, conf->boot_val); | ||||
| 						if (newval == NULL) | ||||
| 							return false; | ||||
| 					} | ||||
| 				} | ||||
| 				/* else we handle a "RESET varname" command */ | ||||
| 				else if (conf->reset_val) | ||||
| 				{ | ||||
| 					/*
 | ||||
| @ -6404,6 +6473,13 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source) | ||||
| 	int			c; | ||||
| 	StringInfoData buf; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Resetting custom_variable_classes by removing it from the | ||||
| 	 * configuration file will lead to newval = NULL | ||||
| 	 */ | ||||
| 	if (newval == NULL) | ||||
| 		return guc_strdup(ERROR, ""); | ||||
| 
 | ||||
| 	initStringInfo(&buf); | ||||
| 	while ((c = *cp++) != 0) | ||||
| 	{ | ||||
| @ -6448,7 +6524,7 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source) | ||||
| 	if (buf.len == 0) | ||||
| 		newval = NULL; | ||||
| 	else if (doit) | ||||
| 		newval = strdup(buf.data); | ||||
| 		newval = guc_strdup(ERROR, buf.data); | ||||
| 
 | ||||
| 	pfree(buf.data); | ||||
| 	return newval; | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * | ||||
|  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group | ||||
|  * | ||||
|  *	  $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.32 2007/03/13 14:32:25 petere Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.33 2007/04/21 20:02:41 petere Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -154,10 +154,11 @@ struct config_bool | ||||
| 	/* these fields must be set correctly in initial value: */ | ||||
| 	/* (all but reset_val are constants) */ | ||||
| 	bool	   *variable; | ||||
| 	bool		reset_val; | ||||
| 	bool		boot_val; | ||||
| 	GucBoolAssignHook assign_hook; | ||||
| 	GucShowHook show_hook; | ||||
| 	/* variable fields, initialized at runtime: */ | ||||
| 	bool		reset_val; | ||||
| 	bool		tentative_val; | ||||
| }; | ||||
| 
 | ||||
| @ -167,12 +168,13 @@ struct config_int | ||||
| 	/* these fields must be set correctly in initial value: */ | ||||
| 	/* (all but reset_val are constants) */ | ||||
| 	int		   *variable; | ||||
| 	int			reset_val; | ||||
| 	int			boot_val; | ||||
| 	int			min; | ||||
| 	int			max; | ||||
| 	GucIntAssignHook assign_hook; | ||||
| 	GucShowHook show_hook; | ||||
| 	/* variable fields, initialized at runtime: */ | ||||
| 	int			reset_val; | ||||
| 	int			tentative_val; | ||||
| }; | ||||
| 
 | ||||
| @ -182,12 +184,13 @@ struct config_real | ||||
| 	/* these fields must be set correctly in initial value: */ | ||||
| 	/* (all but reset_val are constants) */ | ||||
| 	double	   *variable; | ||||
| 	double		reset_val; | ||||
| 	double		boot_val; | ||||
| 	double		min; | ||||
| 	double		max; | ||||
| 	GucRealAssignHook assign_hook; | ||||
| 	GucShowHook show_hook; | ||||
| 	/* variable fields, initialized at runtime: */ | ||||
| 	double		reset_val; | ||||
| 	double		tentative_val; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user