Custom variable class segmentation fault
The latest HEAD is segfaulting on startup if I have the following
lines in postgresql.conf:
custom_variable_classes = 'plperl'
plperl.use_strict = on
If I comment out the second line then the server starts successfully.
Platform is Solaris 9/sparc.
(gdb) bt
#0 0xff0340a0 in strcmp () from /usr/lib/libc.so.1
#1 0x00257504 in verify_config_option (name=0x0, value=0x397258 "on", context=PGC_POSTMASTER, source=PGC_S_FILE, isNewEqual=0xffbff2cb "\001",
isContextOK=0xffbff2ca "\001\001") at guc.c:5513
#2 0x0025d3b4 in ProcessConfigFile (context=PGC_POSTMASTER) at guc-file.l:152
#3 0x0025d80c in SelectConfigFiles (userDoption=0x1 <Address 0x1 out of bounds>, progname=0x390610 "postgres") at guc.c:2867
#4 0x0019a450 in PostmasterMain (argc=5, argv=0x391240) at postmaster.c:602
#5 0x001518c8 in main (argc=5, argv=0x391240) at main.c:187
--
Michael Fuhr
Michael Fuhr wrote:
The latest HEAD is segfaulting on startup if I have the following
lines in postgresql.conf:custom_variable_classes = 'plperl'
plperl.use_strict = onIf I comment out the second line then the server starts successfully.
Platform is Solaris 9/sparc.(gdb) bt
#0 0xff0340a0 in strcmp () from /usr/lib/libc.so.1
#1 0x00257504 in verify_config_option (name=0x0, value=0x397258 "on", context=PGC_POSTMASTER, source=PGC_S_FILE, isNewEqual=0xffbff2cb "\001",
isContextOK=0xffbff2ca "\001\001") at guc.c:5513
#2 0x0025d3b4 in ProcessConfigFile (context=PGC_POSTMASTER) at guc-file.l:152
#3 0x0025d80c in SelectConfigFiles (userDoption=0x1 <Address 0x1 out of bounds>, progname=0x390610 "postgres") at guc.c:2867
#4 0x0019a450 in PostmasterMain (argc=5, argv=0x391240) at postmaster.c:602
#5 0x001518c8 in main (argc=5, argv=0x391240) at main.c:187
Thanks for the report. This attached, applied patch fixes it. The
problem was that custom variables have _no_ default value for strings on
startup, and the checking code was being too agressive.
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
Attachments:
/bjm/difftext/x-diffDownload
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.339
diff -c -c -r1.339 guc.c
*** src/backend/utils/misc/guc.c 13 Aug 2006 02:22:24 -0000 1.339
--- src/backend/utils/misc/guc.c 13 Aug 2006 15:34:13 -0000
***************
*** 5512,5518 ****
{
struct config_string *conf = (struct config_string *) record;
! return strcmp(*conf->variable, newvalue) == 0;
}
}
--- 5512,5521 ----
{
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;
}
}
Michael Fuhr <mike@fuhr.org> writes:
The latest HEAD is segfaulting on startup if I have the following
lines in postgresql.conf:
custom_variable_classes = 'plperl'
plperl.use_strict = on
Bruce, please re-revert that GUC patch and don't put it back in until
someone like Peter or me has actually reviewed it. My faith in it has
gone to zero, and I don't think you are able to fix it either.
BTW, do I need to mention that the plperl patch is breaking the
buildfarm again?
regards, tom lane
Tom Lane wrote:
BTW, do I need to mention that the plperl patch is breaking the
buildfarm again?
No :-) See my comments from about an hour ago. It needs to be removed also.
cheers
andrew
Tom Lane wrote:
Michael Fuhr <mike@fuhr.org> writes:
The latest HEAD is segfaulting on startup if I have the following
lines in postgresql.conf:custom_variable_classes = 'plperl'
plperl.use_strict = onBruce, please re-revert that GUC patch and don't put it back in until
someone like Peter or me has actually reviewed it. My faith in it has
gone to zero, and I don't think you are able to fix it either.
Peter had already reviewed it and given comments.
There were three things wrong with the original patch:
o spacing, e.g. "if( x =- 1 )"
o an incorrect API for memory freeing by parse_value()
o verify_config_option() didn't consider custom variables
These have all been corrected, so I don't see the value in removing the
patch now that it is working. I have attached the three GUC patches
that were applied to CVS, so if someone wants corrections or removal
based on specific issues, please let me know.
BTW, do I need to mention that the plperl patch is breaking the
buildfarm again?
That has been reverted, because of the regression failures and Andrew's
analysis.
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
Attachments:
/pgpatches/guc1text/x-diffDownload
Index: src/backend/utils/misc/guc-file.l
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/misc/guc-file.l,v
retrieving revision 1.42
retrieving revision 1.43
diff -c -r1.42 -r1.43
*** src/backend/utils/misc/guc-file.l 12 Aug 2006 04:12:41 -0000 1.42
--- src/backend/utils/misc/guc-file.l 13 Aug 2006 01:30:17 -0000 1.43
***************
*** 4,10 ****
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
! * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.42 2006/08/12 04:12:41 momjian Exp $
*/
%{
--- 4,10 ----
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
! * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.43 2006/08/13 01:30:17 momjian Exp $
*/
%{
***************
*** 50,56 ****
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);
static void free_name_value_list(struct name_value_pair * list);
static char *GUC_scanstr(const char *s);
--- 50,57 ----
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);
static void free_name_value_list(struct name_value_pair * list);
static char *GUC_scanstr(const char *s);
***************
*** 114,121 ****
void
ProcessConfigFile(GucContext context)
{
! int elevel;
struct name_value_pair *item, *head, *tail;
Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
--- 115,124 ----
void
ProcessConfigFile(GucContext context)
{
! int elevel, i;
struct name_value_pair *item, *head, *tail;
+ bool *apply_list = NULL;
+ int varcount = 0;
Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
***************
*** 134,158 ****
if (!ParseConfigFile(ConfigFileName, NULL,
0, context, elevel,
! &head, &tail))
goto cleanup_list;
/* 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);
}
--- 137,192 ----
if (!ParseConfigFile(ConfigFileName, NULL,
0, context, elevel,
! &head, &tail, &varcount))
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++)
{
! 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")));
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);
!
! cleanup_list:
! if (apply_list)
! pfree(apply_list);
free_name_value_list(head);
}
***************
*** 189,201 ****
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)
{
! bool OK = true;
! char abs_path[MAXPGPATH];
! FILE *fp;
YY_BUFFER_STATE lex_buffer;
! int token;
/*
* Reject too-deep include nesting depth. This is just a safety check
--- 223,236 ----
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)
{
! bool OK = true;
! char abs_path[MAXPGPATH];
! FILE *fp;
YY_BUFFER_STATE lex_buffer;
! int token;
/*
* Reject too-deep include nesting depth. This is just a safety check
***************
*** 289,295 ****
if (!ParseConfigFile(opt_value, config_file,
depth + 1, context, elevel,
! head_p, tail_p))
{
pfree(opt_name);
pfree(opt_value);
--- 324,330 ----
if (!ParseConfigFile(opt_value, config_file,
depth + 1, context, elevel,
! head_p, tail_p, varcount))
{
pfree(opt_name);
pfree(opt_value);
***************
*** 333,338 ****
--- 368,374 ----
else
(*tail_p)->next = item;
*tail_p = item;
+ (*varcount)++;
}
/* break out of loop if read EOF, else loop for next line */
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.337
retrieving revision 1.338
diff -c -r1.337 -r1.338
*** src/backend/utils/misc/guc.c 12 Aug 2006 04:12:41 -0000 1.337
--- src/backend/utils/misc/guc.c 13 Aug 2006 01:30:17 -0000 1.338
***************
*** 10,16 ****
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
! * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.337 2006/08/12 04:12:41 momjian Exp $
*
*--------------------------------------------------------------------
*/
--- 10,16 ----
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
! * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.338 2006/08/13 01:30:17 momjian Exp $
*
*--------------------------------------------------------------------
*/
***************
*** 2313,2319 ****
* states).
*/
static void
! set_string_field(struct config_string * conf, char **field, char *newval)
{
char *oldval = *field;
GucStack *stack;
--- 2313,2319 ----
* states).
*/
static void
! set_string_field(struct config_string *conf, char **field, char *newval)
{
char *oldval = *field;
GucStack *stack;
***************
*** 2535,2542 ****
gen = &var->gen;
memset(var, 0, sz);
! gen->name = guc_strdup(elevel, name);
! if (gen->name == NULL)
{
free(var);
return NULL;
--- 2535,2541 ----
gen = &var->gen;
memset(var, 0, sz);
! if ((gen->name = guc_strdup(elevel, name)) == NULL)
{
free(var);
return NULL;
***************
*** 3690,3785 ****
return result;
}
-
/*
! * 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;
!
! 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;
! record = find_option(name, elevel);
! if (record == NULL)
! {
! ereport(elevel,
! (errcode(ERRCODE_UNDEFINED_OBJECT),
! errmsg("unrecognized configuration parameter \"%s\"", name)));
! return false;
}
! /*
! * 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",
! name)));
return false;
}
break;
case PGC_POSTMASTER:
if (context == PGC_SIGHUP)
! {
! 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",
! name)));
return false;
}
break;
--- 3689,3942 ----
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.
*/
! static bool
! parse_value(int elevel, const struct config_generic *record,
! const char *value, GucSource *source, bool changeVal,
! union config_var_value *retval)
{
! /*
! * 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
! {
! 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, (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
! {
! 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
! {
! 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",
! 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 (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);
!
! /*
! * 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 (retval)
! retval->stringval = newval;
! else
! free(newval);
! break;
! }
}
+ 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)
! {
switch (record->context)
{
case PGC_INTERNAL:
if (context != PGC_INTERNAL)
{
ereport(elevel,
(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
errmsg("parameter \"%s\" cannot be changed",
! record->name)));
return false;
}
break;
case PGC_POSTMASTER:
if (context == PGC_SIGHUP)
! return false;
if (context != PGC_POSTMASTER)
{
ereport(elevel,
(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
errmsg("parameter \"%s\" cannot be changed after server start",
! record->name)));
return false;
}
break;
***************
*** 3789,3795 ****
ereport(elevel,
(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
errmsg("parameter \"%s\" cannot be changed now",
! name)));
return false;
}
--- 3946,3952 ----
ereport(elevel,
(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
errmsg("parameter \"%s\" cannot be changed now",
! record->name)));
return false;
}
***************
*** 3812,3825 ****
* backend start.
*/
if (IsUnderPostmaster)
! 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",
! name)));
return false;
}
break;
--- 3969,3984 ----
* backend start.
*/
if (IsUnderPostmaster)
! {
! return false;
! }
}
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)));
return false;
}
break;
***************
*** 3829,3835 ****
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
! name)));
return false;
}
break;
--- 3988,3994 ----
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
! record->name)));
return false;
}
break;
***************
*** 3837,3842 ****
--- 3996,4109 ----
/* 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))
+ {
+ 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
***************
*** 3871,3914 ****
{
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",
! 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;
--- 4138,4160 ----
{
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 (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;
***************
*** 3948,3998 ****
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",
! 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;
--- 4194,4215 ----
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 (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;
***************
*** 4032,4082 ****
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",
! 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;
--- 4249,4270 ----
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 (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;
***************
*** 4116,4197 ****
struct config_string *conf = (struct config_string *) record;
char *newval;
! 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;
--- 4304,4325 ----
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 (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;
***************
*** 4767,4774 ****
/* need a tuple descriptor representing a single TEXT column */
tupdesc = CreateTemplateTupleDesc(1, false);
! TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname,
! TEXTOID, -1, 0);
}
return tupdesc;
}
--- 4895,4901 ----
/* need a tuple descriptor representing a single TEXT column */
tupdesc = CreateTemplateTupleDesc(1, false);
! TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname, TEXTOID, -1, 0);
}
return tupdesc;
}
***************
*** 4860,4866 ****
/* send it to dest */
do_tup_output(tstate, values);
- /* clean up */
if (values[1] != NULL)
pfree(values[1]);
}
--- 4987,4992 ----
***************
*** 5314,5319 ****
--- 5440,5448 ----
static bool
is_newvalue_equal(struct config_generic *record, const char *newvalue)
{
+ if (!newvalue)
+ return false;
+
switch (record->vartype)
{
case PGC_BOOL:
Index: src/include/utils/guc.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/utils/guc.h,v
retrieving revision 1.73
retrieving revision 1.74
diff -c -r1.73 -r1.74
*** src/include/utils/guc.h 12 Aug 2006 04:12:41 -0000 1.73
--- src/include/utils/guc.h 13 Aug 2006 01:30:17 -0000 1.74
***************
*** 7,13 ****
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
! * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.73 2006/08/12 04:12:41 momjian Exp $
*--------------------------------------------------------------------
*/
#ifndef GUC_H
--- 7,13 ----
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
! * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.74 2006/08/13 01:30:17 momjian Exp $
*--------------------------------------------------------------------
*/
#ifndef GUC_H
***************
*** 193,198 ****
--- 193,201 ----
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);
/pgpatches/guc2text/x-diffDownload
Index: src/backend/utils/misc/guc-file.l
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/misc/guc-file.l,v
retrieving revision 1.43
retrieving revision 1.44
diff -c -r1.43 -r1.44
*** src/backend/utils/misc/guc-file.l 13 Aug 2006 01:30:17 -0000 1.43
--- src/backend/utils/misc/guc-file.l 13 Aug 2006 02:22:24 -0000 1.44
***************
*** 4,10 ****
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
! * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.43 2006/08/13 01:30:17 momjian Exp $
*/
%{
--- 4,10 ----
*
* 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 $
*/
%{
***************
*** 117,122 ****
--- 117,123 ----
{
int elevel, i;
struct name_value_pair *item, *head, *tail;
+ char *env;
bool *apply_list = NULL;
int varcount = 0;
***************
*** 183,188 ****
--- 184,242 ----
set_config_option(item->name, item->value, context,
PGC_S_FILE, false, true);
+ if (context == PGC_SIGHUP)
+ {
+ /*
+ * 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);
+ }
cleanup_list:
if (apply_list)
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.338
retrieving revision 1.339
diff -c -r1.338 -r1.339
*** src/backend/utils/misc/guc.c 13 Aug 2006 01:30:17 -0000 1.338
--- src/backend/utils/misc/guc.c 13 Aug 2006 02:22:24 -0000 1.339
***************
*** 10,16 ****
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
! * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.338 2006/08/13 01:30:17 momjian Exp $
*
*--------------------------------------------------------------------
*/
--- 10,16 ----
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
! * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.339 2006/08/13 02:22:24 momjian Exp $
*
*--------------------------------------------------------------------
*/
***************
*** 2692,2731 ****
{
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:
--- 2692,2731 ----
{
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;
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;
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;
break;
}
case PGC_STRING:
***************
*** 2738,2747 ****
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;
--- 2738,2745 ----
***************
*** 2753,2762 ****
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);
--- 2751,2758 ----
***************
*** 2796,2807 ****
if (env != NULL)
SetConfigOption("port", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
! env = getenv("PGDATESTYLE");
! if (env != NULL)
SetConfigOption("datestyle", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
! env = getenv("PGCLIENTENCODING");
! if (env != NULL)
SetConfigOption("client_encoding", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
}
--- 2792,2801 ----
if (env != NULL)
SetConfigOption("port", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
! if ((env = getenv("PGDATESTYLE")) != NULL)
SetConfigOption("datestyle", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
! if ((env = getenv("PGCLIENTENCODING")) != NULL)
SetConfigOption("client_encoding", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
}
***************
*** 3178,3184 ****
for (i = 0; i < num_guc_variables; i++)
{
struct config_generic *gconf = guc_variables[i];
! int my_status = gconf->status;
GucStack *stack = gconf->stack;
bool useTentative;
bool changed;
--- 3172,3178 ----
for (i = 0; i < num_guc_variables; i++)
{
struct config_generic *gconf = guc_variables[i];
! int my_status = gconf->status & (~GUC_IN_CONFFILE);
GucStack *stack = gconf->stack;
bool useTentative;
bool changed;
***************
*** 3723,3734 ****
}
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),
--- 3717,3738 ----
}
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),
***************
*** 3767,3774 ****
}
else
{
! newval = conf->reset_val;
! *source = conf->gen.reset_source;
}
if (conf->assign_hook)
--- 3771,3788 ----
}
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)
***************
*** 3811,3822 ****
}
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),
--- 3825,3846 ----
}
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),
***************
*** 3845,3850 ****
--- 3869,3886 ----
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)
{
/*
***************
*** 3856,3865 ****
*source = conf->gen.reset_source;
}
else
- {
/* Nothing to reset to, as yet; so do nothing */
break;
- }
if (conf->assign_hook)
{
--- 3892,3899 ----
***************
*** 4047,4052 ****
--- 4081,4093 ----
if (parse_value(elevel, record, value, &source, false, NULL))
{
+ /*
+ * Mark record like presented in the config file. Be carefull if
+ * you use this function for another purpose than config file
+ * verification. It causes confusion configfile parser.
+ */
+ record->status |= GUC_IN_CONFFILE;
+
if (isNewEqual != NULL)
*isNewEqual = is_newvalue_equal(record, value);
if (isContextOK != NULL)
***************
*** 4109,4115 ****
* 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.
--- 4150,4157 ----
* 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);
/*
* Ignore attempted set if overridden by previously processed setting.
Index: src/include/utils/guc_tables.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/utils/guc_tables.h,v
retrieving revision 1.26
retrieving revision 1.27
diff -c -r1.26 -r1.27
*** src/include/utils/guc_tables.h 12 Aug 2006 04:11:50 -0000 1.26
--- src/include/utils/guc_tables.h 13 Aug 2006 02:22:24 -0000 1.27
***************
*** 7,13 ****
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
*
! * $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.26 2006/08/12 04:11:50 momjian Exp $
*
*-------------------------------------------------------------------------
*/
--- 7,13 ----
*
* 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 $
*
*-------------------------------------------------------------------------
*/
***************
*** 143,149 ****
#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) */
!
/* GUC records for specific variable types */
--- 143,150 ----
#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 */
***************
*** 153,163 ****
/* 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
***************
*** 166,178 ****
/* 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
***************
*** 181,193 ****
/* 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
/pgpatches/guc3text/x-diffDownload
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.339
retrieving revision 1.340
diff -c -r1.339 -r1.340
*** src/backend/utils/misc/guc.c 13 Aug 2006 02:22:24 -0000 1.339
--- src/backend/utils/misc/guc.c 13 Aug 2006 15:37:02 -0000 1.340
***************
*** 10,16 ****
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
! * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.339 2006/08/13 02:22:24 momjian Exp $
*
*--------------------------------------------------------------------
*/
--- 10,16 ----
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
! * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.340 2006/08/13 15:37:02 momjian Exp $
*
*--------------------------------------------------------------------
*/
***************
*** 4082,4090 ****
if (parse_value(elevel, record, value, &source, false, NULL))
{
/*
! * Mark record like presented in the config file. Be carefull if
* you use this function for another purpose than config file
! * verification. It causes confusion configfile parser.
*/
record->status |= GUC_IN_CONFFILE;
--- 4082,4090 ----
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;
***************
*** 5512,5518 ****
{
struct config_string *conf = (struct config_string *) record;
! return strcmp(*conf->variable, newvalue) == 0;
}
}
--- 5512,5521 ----
{
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;
}
}
Bruce Momjian <bruce@momjian.us> writes:
There were three things wrong with the original patch:
o spacing, e.g. "if( x =- 1 )"
o an incorrect API for memory freeing by parse_value()
o verify_config_option() didn't consider custom variables
These have all been corrected, so I don't see the value in removing the
patch now that it is working.
You mean, there were three things wrong that we've identified so far,
and as for "it's working now", you thought it worked each previous
time you applied or patched it. I repeat my statement that I've got
zero confidence in it. It needs line-by-line review, and not by you.
I don't have time for it right now (I have more important things
to worry about, like bitmap indexes). Unless Peter or someone else
who knows the GUC code very well is willing to look it over pronto,
I want it out so it's not destabilizing things while we try to get
other patches committed.
I've always found it easier to review uncommitted patches than committed
ones anyway. When you're playing catch-up by reviewing a committed
patch, you have to deal with three states of the code rather than two
(pre-patch, post-patch, your own mods). That gets rapidly worse if the
patch has been in there awhile and other changes go in on top of it.
Plus, once other changes accumulate on top, it becomes extremely painful
to revert if the conclusion is that the patch is completely broken.
(A conclusion that I don't think is at all unlikely with respect to
this patch.)
regards, tom lane
Tom Lane wrote:
I've always found it easier to review uncommitted patches than committed
ones anyway. When you're playing catch-up by reviewing a committed
patch, you have to deal with three states of the code rather than two
(pre-patch, post-patch, your own mods). That gets rapidly worse if the
patch has been in there awhile and other changes go in on top of it.
Plus, once other changes accumulate on top, it becomes extremely painful
to revert if the conclusion is that the patch is completely broken.
(A conclusion that I don't think is at all unlikely with respect to
this patch.)
Easy or not this strikes me as good policy. And nothing is urgent quite
yet - we still have another 18 days to the end of the month, which is
the stated deadline for getting patches reviewed and committed.
cheers
andrew
OK, with two people now concerned, patch reverted.
---------------------------------------------------------------------------
Andrew Dunstan wrote:
Tom Lane wrote:
I've always found it easier to review uncommitted patches than committed
ones anyway. When you're playing catch-up by reviewing a committed
patch, you have to deal with three states of the code rather than two
(pre-patch, post-patch, your own mods). That gets rapidly worse if the
patch has been in there awhile and other changes go in on top of it.
Plus, once other changes accumulate on top, it becomes extremely painful
to revert if the conclusion is that the patch is completely broken.
(A conclusion that I don't think is at all unlikely with respect to
this patch.)Easy or not this strikes me as good policy. And nothing is urgent quite
yet - we still have another 18 days to the end of the month, which is
the stated deadline for getting patches reviewed and committed.cheers
andrew
---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
Bruce, Andrew, Tom.
I little bit confuse now, what status of this patch is? I check your
observation and I agree with them. But I don't where is "ball" now and
what I can/must do now like author of this patch?
Thanks for explanation
Zdenek
Bruce Momjian napsal(a):
Show quoted text
OK, with two people now concerned, patch reverted.
---------------------------------------------------------------------------
Andrew Dunstan wrote:
Tom Lane wrote:
I've always found it easier to review uncommitted patches than committed
ones anyway. When you're playing catch-up by reviewing a committed
patch, you have to deal with three states of the code rather than two
(pre-patch, post-patch, your own mods). That gets rapidly worse if the
patch has been in there awhile and other changes go in on top of it.
Plus, once other changes accumulate on top, it becomes extremely painful
to revert if the conclusion is that the patch is completely broken.
(A conclusion that I don't think is at all unlikely with respect to
this patch.)Easy or not this strikes me as good policy. And nothing is urgent quite
yet - we still have another 18 days to the end of the month, which is
the stated deadline for getting patches reviewed and committed.cheers
andrew
---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster
Zdenek Kotala wrote:
Bruce, Andrew, Tom.
I little bit confuse now, what status of this patch is? I check your
observation and I agree with them. But I don't where is "ball" now and
what I can/must do now like author of this patch?
I am unsure too. I would not back out a patch for nonspecific concerns
from one person, but from two people I reverted it. Tom wants more eyes
on it, but I don't know how that is going to happen, especially since
Peter, who has done a lot of GUC work, has reviewed it already, and so
have I.
I will keep the patches and if no one works on it, again ask to apply it
before we finish 8.2, and see if there are still objections. If there
are still objections, we will have to vote on whether we want it
applied.
---------------------------------------------------------------------------
Bruce Momjian napsal(a):
OK, with two people now concerned, patch reverted.
---------------------------------------------------------------------------
Andrew Dunstan wrote:
Tom Lane wrote:
I've always found it easier to review uncommitted patches than committed
ones anyway. When you're playing catch-up by reviewing a committed
patch, you have to deal with three states of the code rather than two
(pre-patch, post-patch, your own mods). That gets rapidly worse if the
patch has been in there awhile and other changes go in on top of it.
Plus, once other changes accumulate on top, it becomes extremely painful
to revert if the conclusion is that the patch is completely broken.
(A conclusion that I don't think is at all unlikely with respect to
this patch.)Easy or not this strikes me as good policy. And nothing is urgent quite
yet - we still have another 18 days to the end of the month, which is
the stated deadline for getting patches reviewed and committed.cheers
andrew
---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
Bruce,
I think you have misunderstood.
If you and Peter have reviewed it thoroughly then I see no reason the
patch should not be applied.
My post below was merely to agree with Tom that in principle, patches
should be be reviewed before application and not after. I still think
that's right - I have been concerned lately that the buildfarm has been
broken a bit too much.
cheers
andrew
Bruce Momjian wrote:
Show quoted text
Zdenek Kotala wrote:
Bruce, Andrew, Tom.
I little bit confuse now, what status of this patch is? I check your
observation and I agree with them. But I don't where is "ball" now and
what I can/must do now like author of this patch?I am unsure too. I would not back out a patch for nonspecific concerns
from one person, but from two people I reverted it. Tom wants more eyes
on it, but I don't know how that is going to happen, especially since
Peter, who has done a lot of GUC work, has reviewed it already, and so
have I.I will keep the patches and if no one works on it, again ask to apply it
before we finish 8.2, and see if there are still objections. If there
are still objections, we will have to vote on whether we want it
applied.---------------------------------------------------------------------------
Bruce Momjian napsal(a):
OK, with two people now concerned, patch reverted.
---------------------------------------------------------------------------
Andrew Dunstan wrote:
Tom Lane wrote:
I've always found it easier to review uncommitted patches than committed
ones anyway. When you're playing catch-up by reviewing a committed
patch, you have to deal with three states of the code rather than two
(pre-patch, post-patch, your own mods). That gets rapidly worse if the
patch has been in there awhile and other changes go in on top of it.
Plus, once other changes accumulate on top, it becomes extremely painful
to revert if the conclusion is that the patch is completely broken.
(A conclusion that I don't think is at all unlikely with respect to
this patch.)Easy or not this strikes me as good policy. And nothing is urgent quite
yet - we still have another 18 days to the end of the month, which is
the stated deadline for getting patches reviewed and committed.cheers
andrew
---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster
Andrew Dunstan wrote:
Bruce,
I think you have misunderstood.
If you and Peter have reviewed it thoroughly then I see no reason the
patch should not be applied.
We have. I did extensive rework, and Peter exchanged emails with the
author asking questions. I did have questions about how the original
patch was freeing memory, but didn't second-guess the author. Turns out
it needed rework, and that was done after build farm failures.
My post below was merely to agree with Tom that in principle, patches
should be be reviewed before application and not after. I still think
that's right - I have been concerned lately that the buildfarm has been
broken a bit too much.
Well, just because they are reviewed doesn't mean they aren't going to
break the build farm. In fact, the build farm is there to be broken ---
if all patches worked fine on all machines, we wouldn't need the build
farm. Let's not get into a case where keeping the build farm green is
our primary goal, "Oh, let's not apply that patch or it might break the
build farm". Hey, I have an idea, let's stop CVS update on the build
farm, and it will stay green forever. :-) LOL (Of course, we don't
want the build farm to stay broken or it masks newly introduced errors.)
If you withdraw your object to the GUC patch, then with a single person
objecting, the patch either goes in or that person takes responsibility
for getting it into 8.2, or the blame for leaving it for 8.3.
---------------------------------------------------------------------------
cheers
andrew
Bruce Momjian wrote:
Zdenek Kotala wrote:
Bruce, Andrew, Tom.
I little bit confuse now, what status of this patch is? I check your
observation and I agree with them. But I don't where is "ball" now and
what I can/must do now like author of this patch?I am unsure too. I would not back out a patch for nonspecific concerns
from one person, but from two people I reverted it. Tom wants more eyes
on it, but I don't know how that is going to happen, especially since
Peter, who has done a lot of GUC work, has reviewed it already, and so
have I.I will keep the patches and if no one works on it, again ask to apply it
before we finish 8.2, and see if there are still objections. If there
are still objections, we will have to vote on whether we want it
applied.---------------------------------------------------------------------------
Bruce Momjian napsal(a):
OK, with two people now concerned, patch reverted.
---------------------------------------------------------------------------
Andrew Dunstan wrote:
Tom Lane wrote:
I've always found it easier to review uncommitted patches than committed
ones anyway. When you're playing catch-up by reviewing a committed
patch, you have to deal with three states of the code rather than two
(pre-patch, post-patch, your own mods). That gets rapidly worse if the
patch has been in there awhile and other changes go in on top of it.
Plus, once other changes accumulate on top, it becomes extremely painful
to revert if the conclusion is that the patch is completely broken.
(A conclusion that I don't think is at all unlikely with respect to
this patch.)Easy or not this strikes me as good policy. And nothing is urgent quite
yet - we still have another 18 days to the end of the month, which is
the stated deadline for getting patches reviewed and committed.cheers
andrew
---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
Bruce Momjian wrote:
My post below was merely to agree with Tom that in principle, patches
should be be reviewed before application and not after. I still think
that's right - I have been concerned lately that the buildfarm has been
broken a bit too much.Well, just because they are reviewed doesn't mean they aren't going to
break the build farm. In fact, the build farm is there to be broken ---
if all patches worked fine on all machines, we wouldn't need the build
farm. Let's not get into a case where keeping the build farm green is
our primary goal, "Oh, let's not apply that patch or it might break the
build farm". Hey, I have an idea, let's stop CVS update on the build
farm, and it will stay green forever. :-) LOL (Of course, we don't
want the build farm to stay broken or it masks newly introduced errors.)
I certainly expect buildfarm to break. But it is not intended as a
substitute for review either. We shouldn't be in the business of saying
"let's apply it and see if buildfarm breaks". We should be saying "I
have looked at this and my best guess is that it won't break." That
won't avoid all breakage, certainly. But it will keep it down.
If you withdraw your object to the GUC patch, then with a single person
objecting, the patch either goes in or that person takes responsibility
for getting it into 8.2, or the blame for leaving it for 8.3.
As I pointed out - I did not object to the patch being applied, I just
stated an agreement with a general principle, so there is nothing to
withdraw.
cheers
andrew
Andrew Dunstan wrote:
If you and Peter have reviewed it thoroughly then I see no reason the
patch should not be applied.
I merely said that the way the patch was presented, with significant
code refactoring mixed in, I couldn't review it (as effectively as
perhaps otherwise). FWIW, I believe that the general approach is
sound, but I haven't actually "reviewed" the patch completely.
--
Peter Eisentraut
http://developer.postgresql.org/~petere/
Peter Eisentraut <peter_e@gmx.net> writes:
I merely said that the way the patch was presented, with significant
code refactoring mixed in, I couldn't review it (as effectively as
perhaps otherwise). FWIW, I believe that the general approach is
sound, but I haven't actually "reviewed" the patch completely.
Given the multiple problems already found, I feel quite uncomfortable
with putting it back in until another set of eyeballs has been over
it. Do you have time to do a full review anytime soon? I'm trying
to deal with all the other stuff in the queue, and so would prefer
not to spend my own time on it ...
regards, tom lane
Andrew Dunstan wrote:
Bruce Momjian wrote:
My post below was merely to agree with Tom that in principle, patches
should be be reviewed before application and not after. I still think
that's right - I have been concerned lately that the buildfarm has been
broken a bit too much.Well, just because they are reviewed doesn't mean they aren't going to
break the build farm. In fact, the build farm is there to be broken ---
if all patches worked fine on all machines, we wouldn't need the build
farm. Let's not get into a case where keeping the build farm green is
our primary goal, "Oh, let's not apply that patch or it might break the
build farm". Hey, I have an idea, let's stop CVS update on the build
farm, and it will stay green forever. :-) LOL (Of course, we don't
want the build farm to stay broken or it masks newly introduced errors.)I certainly expect buildfarm to break. But it is not intended as a
substitute for review either. We shouldn't be in the business of saying
"let's apply it and see if buildfarm breaks". We should be saying "I
have looked at this and my best guess is that it won't break." That
won't avoid all breakage, certainly. But it will keep it down.
Are you saying that's what is happening, that people aren't reviewing
and letting the buildfarm catch it. I have seen that only in cases
where we can't guess how an platform will be affected by the patch.
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
Tom Lane wrote:
Peter Eisentraut <peter_e@gmx.net> writes:
I merely said that the way the patch was presented, with significant
code refactoring mixed in, I couldn't review it (as effectively as
perhaps otherwise). FWIW, I believe that the general approach is
sound, but I haven't actually "reviewed" the patch completely.Given the multiple problems already found, I feel quite uncomfortable
with putting it back in until another set of eyeballs has been over
it. Do you have time to do a full review anytime soon? I'm trying
to deal with all the other stuff in the queue, and so would prefer
not to spend my own time on it ...
Peter, you also commented on an error message displayed, so I assume
you did look it over somewhat. I agree it would be best for Peter to
review it.
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
Where are we on the GUC comment/reload to defaults patch? Do we have
multiple people objecting to its application? Previously only Tom
objected, and Andrew partially.
---------------------------------------------------------------------------
Bruce Momjian wrote:
Tom Lane wrote:
Michael Fuhr <mike@fuhr.org> writes:
The latest HEAD is segfaulting on startup if I have the following
lines in postgresql.conf:custom_variable_classes = 'plperl'
plperl.use_strict = onBruce, please re-revert that GUC patch and don't put it back in until
someone like Peter or me has actually reviewed it. My faith in it has
gone to zero, and I don't think you are able to fix it either.Peter had already reviewed it and given comments.
There were three things wrong with the original patch:
o spacing, e.g. "if( x =- 1 )"
o an incorrect API for memory freeing by parse_value()
o verify_config_option() didn't consider custom variablesThese have all been corrected, so I don't see the value in removing the
patch now that it is working. I have attached the three GUC patches
that were applied to CVS, so if someone wants corrections or removal
based on specific issues, please let me know.BTW, do I need to mention that the plperl patch is breaking the
buildfarm again?That has been reverted, because of the regression failures and Andrew's
analysis.--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com+ If your life is a hard drive, Christ can be your backup. +
---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
choose an index scan if your joining column's datatypes do not
match
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +