Attached is the long-awaited guc patch that makes values fall back to their
default values when they got removed (or commented) from the configuration
file. This has always been a source of confusion.

There are three not-so-obvious cases that I'd like to comment:

First one:

In the configuration file you have:

seq_page_cost = 3  (the default for this option is 1)

You start the database and issue "SET seq_page_cost TO 4".

Then you remove the seq_page_cost definition from the configuration file and
send SIGHUP.

If you now do a "RESET seq_page_cost" it will fall back to 1 and not to 3.



Second one:

You have custom_variable_classes = "foo"

You start a transaction and do "SET foo.bar to 4".

Now you remove the custom_variable_classes definition and it falls back to
being empty. Hence all foo.* variables become invalid. You cannot COMMIT the
transaction and COMMIT results in a transaction abort.



Third one:

In the configuration file you have

custom_variable_classes = "foo"
foo.bar = 3

You start a transaction and do "SET foo.bar to 4". Then you remove the
definition of "foo.bar" but you keep the custom_variable_classes definition.
COMMITting the transaction succeeds but since foo.bar does not exist in the
configuration file anymore, your SET command is considered to define a new
variable and executing "RESET foo.bar" does not change the variable (without
any change to the configuration file it would remove your setting and
restore the setting from the configuration file for "foo.bar").



Everything else should be quite straightforward. It is also intended that if
you have changed (or commented) a variable in the configuration file that
cannot be applied (because a parameter can only be changed at server start)
you will get this message every time you send a SIGHUP. That way you can see
if your configuration file matches your current server configuration.



Comments welcome,

Joachim

Index: src/backend/access/transam/xact.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/access/transam/xact.c,v
retrieving revision 1.234
diff -c -r1.234 xact.c
*** src/backend/access/transam/xact.c	9 Feb 2007 03:35:33 -0000	1.234
--- src/backend/access/transam/xact.c	19 Feb 2007 12:44:31 -0000
***************
*** 1514,1519 ****
--- 1514,1537 ----
  	AtCommit_Notify();
  
  	/*
+ 	 * GUC can abort the transaction in exactly one case, namely when you
+ 	 * delete a custom variable class while a still-open transaction has
+ 	 * SET a custom variable within this class.
+ 	 *
+ 	 * Consider the following example. In the configuration file we could have:
+ 	 *   custom_variable_classes = "foo"
+ 	 *
+ 	 * begin;
+ 	 * set foo.bar to 1;
+ 	 * <delete foo.bar from configuration file and send SIGHUP>
+ 	 * commit;
+ 	 *
+ 	 * This will result in an error because foo.bar is no longer available
+ 	 * but commit would have to guarantee that the value is preserved.
+ 	 */
+ 	AtEOXact_GUC(true, false);
+ 
+ 	/*
  	 * Update flat files if we changed pg_database, pg_authid or
  	 * pg_auth_members.  This should be the last step before commit.
  	 */
***************
*** 1623,1629 ****
  	/* Check we've released all catcache entries */
  	AtEOXact_CatCache(true);
  
- 	AtEOXact_GUC(true, false);
  	AtEOXact_SPI(true);
  	AtEOXact_on_commit_actions(true);
  	AtEOXact_Namespace(true);
--- 1641,1646 ----
Index: src/backend/utils/misc/guc-file.l
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/guc-file.l,v
retrieving revision 1.47
diff -c -r1.47 guc-file.l
*** src/backend/utils/misc/guc-file.l	10 Feb 2007 14:58:55 -0000	1.47
--- src/backend/utils/misc/guc-file.l	19 Feb 2007 12:44:59 -0000
***************
*** 54,59 ****
--- 54,61 ----
  static void free_name_value_list(struct name_value_pair * list);
  static char *GUC_scanstr(const char *s);
  
+ static char *custom_variable_classes_backup;
+ 
  %}
  
  %option 8bit
***************
*** 114,121 ****
  void
  ProcessConfigFile(GucContext context)
  {
! 	int			elevel;
  	struct name_value_pair *item, *head, *tail;
  
  	Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
  
--- 116,126 ----
  void
  ProcessConfigFile(GucContext context)
  {
! 	int						elevel, i;
  	struct name_value_pair *item, *head, *tail;
+ 	bool				   *in_conffile = NULL;
+ 	const char			   *var;
+ 	bool					success = false;
  
  	Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
  
***************
*** 132,137 ****
--- 137,153 ----
  
  	head = tail = NULL;
  
+ 	/* We do not know if we will read the configuration file
+ 	 * without error. If we encounter an error we have to restore the
+ 	 * previous value of the custom_variable_classes variable for
+ 	 * consistency. Hence we have to save its value.
+ 	 */
+ 	var = GetConfigOption("custom_variable_classes");
+ 	if (var)
+ 		custom_variable_classes_backup = pstrdup(var);
+ 	set_config_option("custom_variable_classes", NULL, context,
+ 					  PGC_S_DEFAULT, false, true);
+ 
  	if (!ParseConfigFile(ConfigFileName, NULL,
  						 0, context, elevel,
  						 &head, &tail))
***************
*** 140,159 ****
  	/* Check if all options are valid */
  	for (item = head; item; item = item->next)
  	{
  		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. */
  	for (item = head; item; item = item->next)
  	{
  		set_config_option(item->name, item->value, context,
  						  PGC_S_FILE, false, true);
! 	}
  
   cleanup_list:
  	free_name_value_list(head);
  }
  
  
--- 156,345 ----
  	/* Check if all options are valid */
  	for (item = head; item; item = item->next)
  	{
+ 		char *sep = strchr(item->name, GUC_QUALIFIER_SEPARATOR);
+ 		if (sep != NULL && !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;
  	}
  
! 
! 	/*
! 	 * 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)
  	{
+ 		/*
+ 		 * 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] && strchr(gconf->name, GUC_QUALIFIER_SEPARATOR))
+ 		{
+ 			/* handle custom variables here */
+ 			int j;
+ 			/* guc_delete_variable will re-sort the array of configuration
+ 			 * options and decrease num_guc_variables by one. */
+ 			guc_delete_custom_variable(gconf->name);
+ 			/*
+ 			 * Since the array is always sorted we just have to shift all
+ 			 * boolean values after position i by one position to the left
+ 			 */
+ 			for (j = i; j < num_guc_variables; j++)
+ 				in_conffile[j] = in_conffile[j+1];
+ 			/* decrease the loop variable to re-test the entry at the
+ 			 * current position that is now a different one */
+ 			i--;
+ 			continue;
+ 		}
+ 		else 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 "
+ 									"(commented) 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 comment 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);
! 
! 	success = true;
  
   cleanup_list:
+ 	if (in_conffile)
+ 		free(in_conffile);
  	free_name_value_list(head);
+ 	if (success == false)
+ 		set_config_option("custom_variable_classes",
+ 						  custom_variable_classes_backup,
+ 						  context, PGC_S_FILE, false, true);
+ 	if (custom_variable_classes_backup)
+ 	{
+ 		pfree(custom_variable_classes_backup);
+ 		custom_variable_classes_backup = NULL;
+ 	}
  }
  
  
***************
*** 312,325 ****
  			{
  				pfree(opt_name);
  				pfree(opt_value);
  				/* we assume error message was logged already */
  				OK = false;
  				goto cleanup_exit;
  			}
- 			pfree(opt_name);
- 			pfree(opt_value);
  		}
! 		else
  		{
  			/* append to list */
  			struct name_value_pair *item;
--- 498,511 ----
  			{
  				pfree(opt_name);
  				pfree(opt_value);
+ 
  				/* we assume error message was logged already */
  				OK = false;
  				goto cleanup_exit;
  			}
  		}
! 
! 		if (pg_strcasecmp(opt_name, "include") != 0)
  		{
  			/* append to list */
  			struct name_value_pair *item;
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.376
diff -c -r1.376 guc.c
*** src/backend/utils/misc/guc.c	16 Feb 2007 17:07:00 -0000	1.376
--- src/backend/utils/misc/guc.c	19 Feb 2007 12:44:59 -0000
***************
*** 2442,2448 ****
  	if (oldval == NULL ||
  		oldval == *(conf->variable) ||
  		oldval == conf->reset_val ||
! 		oldval == conf->tentative_val)
  		return;
  	for (stack = conf->gen.stack; stack; stack = stack->prev)
  	{
--- 2442,2449 ----
  	if (oldval == NULL ||
  		oldval == *(conf->variable) ||
  		oldval == conf->reset_val ||
! 		oldval == conf->tentative_val ||
! 		oldval == conf->boot_val)
  		return;
  	for (stack = conf->gen.stack; stack; stack = stack->prev)
  	{
***************
*** 2465,2471 ****
  
  	if (strval == *(conf->variable) ||
  		strval == conf->reset_val ||
! 		strval == conf->tentative_val)
  		return true;
  	for (stack = conf->gen.stack; stack; stack = stack->prev)
  	{
--- 2466,2473 ----
  
  	if (strval == *(conf->variable) ||
  		strval == conf->reset_val ||
! 		strval == conf->tentative_val ||
! 		strval == conf->boot_val)
  		return true;
  	for (stack = conf->gen.stack; stack; stack = stack->prev)
  	{
***************
*** 2634,2639 ****
--- 2636,2736 ----
  	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;
+ }
+ 
+ static void
+ guc_delete_variable(const char *name)
+ {
+ 	struct config_generic  *gen;
+ 	int						idx;
+ 	GucStack			   *stack, *prev;
+ 	struct config_string   *conf;
+ 
+ 	idx = guc_get_index(name);
+ 	Assert(idx >= 0);
+ 
+ 	gen = guc_variables[idx];
+ 
+ 	/*
+ 	 * Even though this function could delete other types of variables as well,
+ 	 * at the moment we only call it for custom variables that always have type
+ 	 * string.
+ 	 */
+ 	Assert(gen->group == CUSTOM_OPTIONS);
+ 	Assert(gen->vartype == PGC_STRING);
+ 
+ 	conf = (struct config_string *) gen;
+ 	set_string_field(conf, &conf->reset_val, NULL);
+ 	set_string_field(conf, &conf->tentative_val, NULL);
+ 	for (stack = conf->gen.stack; stack; stack = prev)
+ 	{
+ 		set_string_field(conf, &stack->tentative_val.stringval, NULL);
+ 		set_string_field(conf, &stack->value.stringval, NULL);
+ 		prev = stack->prev;
+ 		pfree(stack);
+ 	}
+ 
+ 	/* no pfree() here, gen has been allocated via guc_malloc */
+ 	free(gen);
+ 	guc_variables[idx] = guc_variables[num_guc_variables - 1];
+ 	num_guc_variables--;
+ 	qsort((void *) guc_variables, num_guc_variables,
+ 		  sizeof(struct config_generic *), guc_var_compare);
+ }
+ 
+ static void
+ guc_delete_custom_variable(const char *name)
+ {
+ 	struct config_generic  *gen;
+ 	struct config_string   *conf;
+ 	int						idx;
+ 
+ 	idx = guc_get_index(name);
+ 	Assert(idx >= 0);
+ 
+ 	gen = guc_variables[idx];
+ 
+ 	Assert(gen->group == CUSTOM_OPTIONS);
+ 	Assert(gen->vartype == PGC_STRING);
+ 
+ 	conf = (struct config_string *) gen;
+ 	/*
+ 	 * Here we check if it is safe to really delete the variable or if we have
+ 	 * to wait for the end of the transaction.  We do not remove the physical
+ 	 * entry of a custom variable if it has been SET to another value in the
+ 	 * transaction but has been removed from the configuration file.
+ 	 */
+ 	if (gen->stack)
+ 	{
+ 		/*
+ 		 * Make sure this custom variable (which has a definition in
+ 		 * the configuration file) behaves as any other custom variable
+ 		 * from now on. We have deleted its former definition,
+ 		 * that's why "RESET foo.bar" should not fall back to this
+ 		 * deleted definition from the configuration file. The analogy
+ 		 * is that any other custom variable that gets introduced in a
+ 		 * session has no reset value either. And a variable that has
+ 		 * been SET within a transaction and has then been deleted from
+ 		 * the configuration file should behave as if it had been
+ 		 * introduced in the session.
+ 		 */
+ 		Assert(gen->vartype == PGC_STRING);
+ 		gen->reset_source = PGC_S_DEFAULT;
+ 		set_string_field(conf, &conf->reset_val, NULL);
+ 	}
+ 	else
+ 		guc_delete_variable(name);
+ }
+ 
+ 
  /*
   * Create and add a placeholder variable. It's presumed to belong
   * to a valid custom variable class at this point.
***************
*** 2812,2850 ****
  					struct config_bool *conf = (struct config_bool *) gconf;
  
  					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->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->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:
--- 2909,2947 ----
  					struct config_bool *conf = (struct config_bool *) gconf;
  
  					if (conf->assign_hook)
! 						if (!(*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;
  					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)
! 						if (!(*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; 
  					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)
! 						if (!(*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; 
  					break;
  				}
  			case PGC_STRING:
***************
*** 3338,3343 ****
--- 3435,3467 ----
  			continue;
  		Assert(stack->nest_level == my_level);
  
+ 		if (!isSubXact && gconf->group == CUSTOM_OPTIONS)
+ 		{
+ 			char *dot = strchr(gconf->name, GUC_QUALIFIER_SEPARATOR);
+ 			Assert(dot != NULL);
+ 			if (!is_custom_class(gconf->name, dot - gconf->name))
+ 			{
+ 				if (!isCommit)
+ 				{
+ 					/* We do not commit the transaction. Delete the variable */
+ 					guc_delete_variable(gconf->name);
+ 					/* call the loop with the same i again which is the next
+ 					 * variable */
+ 					i--;
+ 					continue;
+ 				}
+ 				else
+ 				{
+ 					/* We commit the transaction. Throw an error that the
+ 					 * respective custom class does not exist */
+ 					ereport(ERROR,
+ 						(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 						 errmsg("No valid custom variable class available for "
+ 								"parameter \"%s\"", gconf->name)));
+ 				}
+ 			}
+ 		}
+ 
  		/*
  		 * We will pop the stack entry.  Start by restoring outer xact status
  		 * (since we may want to modify it below).	Be careful to use
***************
*** 3998,4006 ****
  
  	/*
  	 * Should we set reset/stacked values?	(If so, the behavior is not
! 	 * transactional.)
  	 */
! 	makeDefault = changeVal && (source <= PGC_S_OVERRIDE) && (value != NULL);
  
  	/*
  	 * Ignore attempted set if overridden by previously processed setting.
--- 4122,4133 ----
  
  	/*
  	 * 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) || source == PGC_S_DEFAULT);
  
  	/*
  	 * Ignore attempted set if overridden by previously processed setting.
***************
*** 4008,4015 ****
  	 * 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.
  	 */
! 	if (record->source > source)
  	{
  		if (changeVal && !makeDefault)
  		{
--- 4135,4145 ----
  	 * 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 got commented in the configuration file. This
+ 	 * is indicated by source == PGC_S_DEFAULT.
  	 */
! 	if (record->source > source && source != PGC_S_DEFAULT)
  	{
  		if (changeVal && !makeDefault)
  		{
***************
*** 4041,4046 ****
--- 4171,4183 ----
  						return false;
  					}
  				}
+ 				/*
+ 				 * if value == NULL and source == PGC_S_DEFAULT then we reset
+ 				 * some value to its default (commented in configuration file)
+ 				 */
+ 				else if (source == PGC_S_DEFAULT)
+ 					newval = conf->boot_val;
+ 				/* else we handle a "RESET varname" command */
  				else
  				{
  					newval = conf->reset_val;
***************
*** 4125,4130 ****
--- 4262,4274 ----
  						return false;
  					}
  				}
+ 				/*
+ 				 * if value == NULL and source == PGC_S_DEFAULT then we reset
+ 				 * some value to its default (commented in configuration file)
+ 				 */
+ 				else if (source == PGC_S_DEFAULT)
+ 					newval = conf->boot_val;
+ 				/* else we handle a "RESET varname" command */
  				else
  				{
  					newval = conf->reset_val;
***************
*** 4209,4214 ****
--- 4353,4365 ----
  						return false;
  					}
  				}
+ 				/*
+ 				 * if value == NULL and source == PGC_S_DEFAULT then we reset
+ 				 * some value to its default (commented in configuration file)
+ 				 */
+ 				else if (source == PGC_S_DEFAULT)
+ 					newval = conf->boot_val;
+ 				/* else we handle a "RESET varname" command */
  				else
  				{
  					newval = conf->reset_val;
***************
*** 4287,4292 ****
--- 4438,4459 ----
  					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 (commented in 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)
  				{
  					/*
***************
*** 6303,6308 ****
--- 6470,6482 ----
  	int			c;
  	StringInfoData buf;
  
+ 	/*
+ 	 * Resetting custom_variable_classes by commenting it from the
+ 	 * configuration file will lead to newval = NULL
+ 	 */
+ 	if (newval == NULL)
+ 		return guc_strdup(ERROR, "");
+ 
  	initStringInfo(&buf);
  	while ((c = *cp++) != 0)
  	{
***************
*** 6347,6353 ****
  	if (buf.len == 0)
  		newval = NULL;
  	else if (doit)
! 		newval = strdup(buf.data);
  
  	pfree(buf.data);
  	return newval;
--- 6521,6527 ----
  	if (buf.len == 0)
  		newval = NULL;
  	else if (doit)
! 		newval = guc_strdup(ERROR, buf.data);
  
  	pfree(buf.data);
  	return newval;
Index: src/include/utils/guc_tables.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/guc_tables.h,v
retrieving revision 1.30
diff -c -r1.30 guc_tables.h
*** src/include/utils/guc_tables.h	5 Jan 2007 22:19:59 -0000	1.30
--- src/include/utils/guc_tables.h	19 Feb 2007 12:45:09 -0000
***************
*** 154,164 ****
  	/* these fields must be set correctly in initial value: */
  	/* (all but reset_val are constants) */
  	bool	   *variable;
! 	bool		reset_val;
  	GucBoolAssignHook assign_hook;
  	GucShowHook show_hook;
  	/* variable fields, initialized at runtime: */
  	bool		tentative_val;
  };
  
  struct config_int
--- 154,165 ----
  	/* these fields must be set correctly in initial value: */
  	/* (all but reset_val are constants) */
  	bool	   *variable;
! 	bool		boot_val;
  	GucBoolAssignHook assign_hook;
  	GucShowHook show_hook;
  	/* variable fields, initialized at runtime: */
  	bool		tentative_val;
+ 	bool		reset_val;
  };
  
  struct config_int
***************
*** 167,179 ****
  	/* these fields must be set correctly in initial value: */
  	/* (all but reset_val are constants) */
  	int		   *variable;
! 	int			reset_val;
  	int			min;
  	int			max;
  	GucIntAssignHook assign_hook;
  	GucShowHook show_hook;
  	/* variable fields, initialized at runtime: */
  	int			tentative_val;
  };
  
  struct config_real
--- 168,181 ----
  	/* these fields must be set correctly in initial value: */
  	/* (all but reset_val are constants) */
  	int		   *variable;
! 	int			boot_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
***************
*** 182,194 ****
  	/* these fields must be set correctly in initial value: */
  	/* (all but reset_val are constants) */
  	double	   *variable;
! 	double		reset_val;
  	double		min;
  	double		max;
  	GucRealAssignHook assign_hook;
  	GucShowHook show_hook;
  	/* variable fields, initialized at runtime: */
  	double		tentative_val;
  };
  
  struct config_string
--- 184,198 ----
  	/* these fields must be set correctly in initial value: */
  	/* (all but reset_val are constants) */
  	double	   *variable;
! 	double		boot_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
---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

               http://www.postgresql.org/docs/faq

Reply via email to