Peter Eisentraut wrote:
> Joachim Wieland wrote:
> > 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.
>
> I have applied your patch with some of the discussed corrections. 
> The use of memory allocation in the GUC code might still need some
> review.

Reverted for further fixes.  Attached is the latest patch I was working 
with.

-- 
Peter Eisentraut
http://developer.postgresql.org/~petere/
diff -cr ./src/backend/access/transam/xact.c ../cvs-pgsql/src/backend/access/transam/xact.c
*** ./src/backend/access/transam/xact.c	2007-03-13 15:16:36.000000000 +0100
--- ../cvs-pgsql/src/backend/access/transam/xact.c	2007-03-13 13:28:26.000000000 +0100
***************
*** 1513,1518 ****
--- 1513,1521 ----
  	/* NOTIFY commit must come before lower-level cleanup */
  	AtCommit_Notify();
  
+ 	/* GUC processing could abort transaction */
+ 	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);
--- 1626,1631 ----
diff -cr ./src/backend/utils/misc/guc.c ../cvs-pgsql/src/backend/utils/misc/guc.c
*** ./src/backend/utils/misc/guc.c	2007-03-13 15:17:40.000000000 +0100
--- ../cvs-pgsql/src/backend/utils/misc/guc.c	2007-03-13 13:28:29.000000000 +0100
***************
*** 2439,2445 ****
  	if (oldval == NULL ||
  		oldval == *(conf->variable) ||
  		oldval == conf->reset_val ||
! 		oldval == conf->tentative_val)
  		return;
  	for (stack = conf->gen.stack; stack; stack = stack->prev)
  	{
--- 2439,2446 ----
  	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)
  	{
***************
*** 2462,2468 ****
  
  	if (strval == *(conf->variable) ||
  		strval == conf->reset_val ||
! 		strval == conf->tentative_val)
  		return true;
  	for (stack = conf->gen.stack; stack; stack = stack->prev)
  	{
--- 2463,2470 ----
  
  	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)
  	{
***************
*** 2631,2636 ****
--- 2633,2737 ----
  	return true;
  }
  
+ static int
+ guc_get_index(const char *name)
+ {
+ 	int i;
+ 
+ 	for (i = 0; i < num_guc_variables; i++)
+ 		if (pg_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 whether 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.
***************
*** 2809,2847 ****
  					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:
--- 2910,2948 ----
  					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:
***************
*** 3296,3303 ****
  	}
  }
  
! /*
   * Do GUC processing at transaction or subtransaction commit or abort.
   */
  void
  AtEOXact_GUC(bool isCommit, bool isSubXact)
--- 3397,3421 ----
  	}
  }
  
! /*------
   * Do GUC processing at transaction or subtransaction commit or abort.
+  *
+  * 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.
   */
  void
  AtEOXact_GUC(bool isCommit, bool isSubXact)
***************
*** 3335,3340 ****
--- 3453,3485 ----
  			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,4016 ****
  	}
  
  	/*
! 	 * 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.
! 	 * 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.
  	 */
! 	if (record->source > source)
  	{
  		if (changeVal && !makeDefault)
  		{
--- 4143,4168 ----
  	}
  
  	/*
! 	 * 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.  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 && source != PGC_S_DEFAULT)
  	{
  		if (changeVal && !makeDefault)
  		{
***************
*** 4042,4047 ****
--- 4194,4207 ----
  						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;
***************
*** 4126,4131 ****
--- 4286,4299 ----
  						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;
***************
*** 4210,4215 ****
--- 4378,4391 ----
  						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;
***************
*** 4288,4293 ****
--- 4464,4486 ----
  					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)
  				{
  					/*
***************
*** 6304,6309 ****
--- 6497,6509 ----
  	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)
  	{
***************
*** 6348,6354 ****
  	if (buf.len == 0)
  		newval = NULL;
  	else if (doit)
! 		newval = strdup(buf.data);
  
  	pfree(buf.data);
  	return newval;
--- 6548,6554 ----
  	if (buf.len == 0)
  		newval = NULL;
  	else if (doit)
! 		newval = guc_strdup(ERROR, buf.data);
  
  	pfree(buf.data);
  	return newval;
diff -cr ./src/backend/utils/misc/guc-file.l ../cvs-pgsql/src/backend/utils/misc/guc-file.l
*** ./src/backend/utils/misc/guc-file.l	2007-03-13 15:16:36.000000000 +0100
--- ../cvs-pgsql/src/backend/utils/misc/guc-file.l	2007-03-13 13:28:29.000000000 +0100
***************
*** 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
***************
*** 116,121 ****
--- 118,127 ----
  {
  	int			elevel;
  	struct name_value_pair *item, *head, *tail;
+ 	int						i;
+ 	bool				   *in_conffile = NULL;
+ 	const char			   *var;
+ 	bool					success = false;
  
  	Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
  
***************
*** 132,137 ****
--- 138,155 ----
  
  	head = tail = NULL;
  
+ 	/*
+ 	 * We do not know whether 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.  Therefore 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);
  }
  
  
--- 158,355 ----
  	/* 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;
  	}
  
! 
! 	/*
! 	 * 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 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);
! 
! 	success = true;
  
   cleanup_list:
+ 	free(in_conffile);
  	free_name_value_list(head);
+ 	if (!success)
+ 		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;
--- 508,521 ----
  			{
  				pfree(opt_name);
  				pfree(opt_value);
! 
! 				/* We assume the 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;
diff -cr ./src/include/utils/guc_tables.h ../cvs-pgsql/src/include/utils/guc_tables.h
*** ./src/include/utils/guc_tables.h	2007-03-13 15:16:36.000000000 +0100
--- ../cvs-pgsql/src/include/utils/guc_tables.h	2007-03-13 13:28:33.000000000 +0100
***************
*** 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,197 ----
  	/* 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
Nur in ./src/test/regress/expected: largeobject_1.out.
---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster

Reply via email to