@ -3260,6 +3260,11 @@ static void InitializeGUCOptionsFromEnvironment(void);
static void InitializeOneGUCOption ( struct config_generic * gconf ) ;
static void push_old_value ( struct config_generic * gconf , GucAction action ) ;
static void ReportGUCOption ( struct config_generic * record ) ;
static void reapply_stacked_values ( struct config_generic * variable ,
struct config_string * pHolder ,
GucStack * stack ,
const char * curvalue ,
GucContext curscontext , GucSource cursource ) ;
static void ShowGUCConfigOption ( const char * name , DestReceiver * dest ) ;
static void ShowAllGUCConfig ( DestReceiver * dest ) ;
static char * _ShowOption ( struct config_generic * record , bool use_units ) ;
@ -5020,6 +5025,10 @@ config_enum_get_options(struct config_enum * record, const char *prefix,
* If changeVal is false then don ' t really set the option but do all
* the checks to see if it would work .
*
* elevel should normally be passed as zero , allowing this function to make
* its standard choice of ereport level . However some callers need to be
* able to override that choice ; they should pass the ereport level to use .
*
* Return value :
* + 1 : the value is valid and was successfully applied .
* 0 : the name or value is invalid ( but see below ) .
@ -5028,34 +5037,37 @@ config_enum_get_options(struct config_enum * record, const char *prefix,
* If there is an error ( non - existing option , invalid value ) then an
* ereport ( ERROR ) is thrown * unless * this is called for a source for which
* we don ' t want an ERROR ( currently , those are defaults , the config file ,
* and per - database or per - user settings ) . In those cases we write a
* suitable error message via ereport ( ) and return 0.
* and per - database or per - user settings , as well as callers who specify
* a less - than - ERROR elevel ) . In those cases we write a suitable error
* message via ereport ( ) and return 0.
*
* See also SetConfigOption for an external interface .
*/
int
set_config_option ( const char * name , const char * value ,
GucContext context , GucSource source ,
GucAction action , bool changeVal )
GucAction action , bool changeVal , int elevel )
{
struct config_generic * record ;
int elevel ;
bool prohibitValueChange = false ;
bool makeDefault ;
if ( source = = PGC_S_DEFAULT | | source = = PGC_S_FILE )
if ( elevel = = 0 )
{
/*
* To avoid cluttering the log , only the postmaster bleats loudly
* about problems with the config file .
*/
elevel = IsUnderPostmaster ? DEBUG3 : LOG ;
if ( source = = PGC_S_DEFAULT | | source = = PGC_S_FILE )
{
/*
* To avoid cluttering the log , only the postmaster bleats loudly
* about problems with the config file .
*/
elevel = IsUnderPostmaster ? DEBUG3 : LOG ;
}
else if ( source = = PGC_S_DATABASE | | source = = PGC_S_USER | |
source = = PGC_S_DATABASE_USER )
elevel = WARNING ;
else
elevel = ERROR ;
}
else if ( source = = PGC_S_DATABASE | | source = = PGC_S_USER | |
source = = PGC_S_DATABASE_USER )
elevel = WARNING ;
else
elevel = ERROR ;
record = find_option ( name , true , elevel ) ;
if ( record = = NULL )
@ -5798,9 +5810,11 @@ set_config_sourcefile(const char *name, char *sourcefile, int sourceline)
}
/*
* Set a config option to the given value . See also set_config_option ,
* this is just the wrapper to be called from outside GUC . NB : this
* is used only for non - transactional operations .
* Set a config option to the given value .
*
* See also set_config_option ; this is just the wrapper to be called from
* outside GUC . ( This function should be used when possible , because its API
* is more stable than set_config_option ' s . )
*
* Note : there is no support here for setting source file / line , as it
* is currently not needed .
@ -5810,7 +5824,7 @@ SetConfigOption(const char *name, const char *value,
GucContext context , GucSource source )
{
( void ) set_config_option ( name , value , context , source ,
GUC_ACTION_SET , true ) ;
GUC_ACTION_SET , true , 0 ) ;
}
@ -6072,7 +6086,8 @@ ExecSetVariableStmt(VariableSetStmt *stmt)
( superuser ( ) ? PGC_SUSET : PGC_USERSET ) ,
PGC_S_SESSION ,
action ,
true ) ;
true ,
0 ) ;
break ;
case VAR_SET_MULTI :
@ -6135,7 +6150,8 @@ ExecSetVariableStmt(VariableSetStmt *stmt)
( superuser ( ) ? PGC_SUSET : PGC_USERSET ) ,
PGC_S_SESSION ,
action ,
true ) ;
true ,
0 ) ;
break ;
case VAR_RESET_ALL :
ResetAllOptions ( ) ;
@ -6180,7 +6196,8 @@ SetPGVariable(const char *name, List *args, bool is_local)
( superuser ( ) ? PGC_SUSET : PGC_USERSET ) ,
PGC_S_SESSION ,
is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET ,
true ) ;
true ,
0 ) ;
}
/*
@ -6223,7 +6240,8 @@ set_config_by_name(PG_FUNCTION_ARGS)
( superuser ( ) ? PGC_SUSET : PGC_USERSET ) ,
PGC_S_SESSION ,
is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET ,
true ) ;
true ,
0 ) ;
/* get the new current value */
new_value = GetConfigOptionByName ( name , NULL ) ;
@ -6282,7 +6300,6 @@ define_custom_variable(struct config_generic * variable)
{
const char * name = variable - > name ;
const char * * nameAddr = & name ;
const char * value ;
struct config_string * pHolder ;
struct config_generic * * res ;
@ -6330,30 +6347,40 @@ define_custom_variable(struct config_generic * variable)
* res = variable ;
/*
* Assign the string value stored in the placeholder to the real variable .
* Assign the string value ( s ) stored in the placeholder to the real
* variable . Essentially , we need to duplicate all the active and stacked
* values , but with appropriate validation and datatype adjustment .
*
* XXX this is not really good enough - - - it should be a nontransactional
* assignment , since we don ' t want it to roll back if the current xact
* fails later . ( Or do we ? )
* If an assignment fails , we report a WARNING and keep going . We don ' t
* want to throw ERROR for bad values , because it ' d bollix the add - on
* module that ' s presumably halfway through getting loaded . In such cases
* the default or previous state will become active instead .
*/
value = * pHolder - > variable ;
if ( value )
{
if ( set_config_option ( name , value ,
pHolder - > gen . scontext , pHolder - > gen . source ,
GUC_ACTION_SET , true ) ! = 0 )
{
/* Also copy over any saved source-location information */
if ( pHolder - > gen . sourcefile )
set_config_sourcefile ( name , pHolder - > gen . sourcefile ,
pHolder - > gen . sourceline ) ;
}
}
/* First, apply the reset value if any */
if ( pHolder - > reset_val )
( void ) set_config_option ( name , pHolder - > reset_val ,
pHolder - > gen . reset_scontext ,
pHolder - > gen . reset_source ,
GUC_ACTION_SET , true , WARNING ) ;
/* That should not have resulted in stacking anything */
Assert ( variable - > stack = = NULL ) ;
/* Now, apply current and stacked values, in the order they were stacked */
reapply_stacked_values ( variable , pHolder , pHolder - > gen . stack ,
* ( pHolder - > variable ) ,
pHolder - > gen . scontext , pHolder - > gen . source ) ;
/* Also copy over any saved source-location information */
if ( pHolder - > gen . sourcefile )
set_config_sourcefile ( name , pHolder - > gen . sourcefile ,
pHolder - > gen . sourceline ) ;
/*
* Free up as much as we conveniently can of the placeholder structure
* ( this neglects any stack items . . . )
* Free up as much as we conveniently can of the placeholder structure .
* ( This neglects any stack items , so it ' s possible for some memory to be
* leaked . Since this can only happen once per session per variable , it
* doesn ' t seem worth spending much code on . )
*/
set_string_field ( pHolder , pHolder - > variable , NULL ) ;
set_string_field ( pHolder , & pHolder - > reset_val , NULL ) ;
@ -6361,6 +6388,89 @@ define_custom_variable(struct config_generic * variable)
free ( pHolder ) ;
}
/*
* Recursive subroutine for define_custom_variable : reapply non - reset values
*
* We recurse so that the values are applied in the same order as originally .
* At each recursion level , apply the upper - level value ( passed in ) in the
* fashion implied by the stack entry .
*/
static void
reapply_stacked_values ( struct config_generic * variable ,
struct config_string * pHolder ,
GucStack * stack ,
const char * curvalue ,
GucContext curscontext , GucSource cursource )
{
const char * name = variable - > name ;
GucStack * oldvarstack = variable - > stack ;
if ( stack ! = NULL )
{
/* First, recurse, so that stack items are processed bottom to top */
reapply_stacked_values ( variable , pHolder , stack - > prev ,
stack - > prior . val . stringval ,
stack - > scontext , stack - > source ) ;
/* See how to apply the passed-in value */
switch ( stack - > state )
{
case GUC_SAVE :
( void ) set_config_option ( name , curvalue ,
curscontext , cursource ,
GUC_ACTION_SAVE , true , WARNING ) ;
break ;
case GUC_SET :
( void ) set_config_option ( name , curvalue ,
curscontext , cursource ,
GUC_ACTION_SET , true , WARNING ) ;
break ;
case GUC_LOCAL :
( void ) set_config_option ( name , curvalue ,
curscontext , cursource ,
GUC_ACTION_LOCAL , true , WARNING ) ;
break ;
case GUC_SET_LOCAL :
/* first, apply the masked value as SET */
( void ) set_config_option ( name , stack - > masked . val . stringval ,
stack - > masked_scontext , PGC_S_SESSION ,
GUC_ACTION_SET , true , WARNING ) ;
/* then apply the current value as LOCAL */
( void ) set_config_option ( name , curvalue ,
curscontext , cursource ,
GUC_ACTION_LOCAL , true , WARNING ) ;
break ;
}
/* If we successfully made a stack entry, adjust its nest level */
if ( variable - > stack ! = oldvarstack )
variable - > stack - > nest_level = stack - > nest_level ;
}
else
{
/*
* We are at the end of the stack . If the active / previous value is
* different from the reset value , it must represent a previously
* committed session value . Apply it , and then drop the stack entry
* that set_config_option will have created under the impression that
* this is to be just a transactional assignment . ( We leak the stack
* entry . )
*/
if ( curvalue ! = pHolder - > reset_val | |
curscontext ! = pHolder - > gen . reset_scontext | |
cursource ! = pHolder - > gen . reset_source )
{
( void ) set_config_option ( name , curvalue ,
curscontext , cursource ,
GUC_ACTION_SET , true , WARNING ) ;
variable - > stack = NULL ;
}
}
}
void
DefineCustomBoolVariable ( const char * name ,
const char * short_desc ,
@ -7468,7 +7578,7 @@ read_nondefault_variables(void)
( void ) set_config_option ( varname , varvalue ,
varscontext , varsource ,
GUC_ACTION_SET , true ) ;
GUC_ACTION_SET , true , 0 ) ;
if ( varsourcefile [ 0 ] )
set_config_sourcefile ( varname , varsourcefile , varsourceline ) ;
@ -7569,7 +7679,9 @@ ProcessGUCArray(ArrayType *array,
continue ;
}
( void ) set_config_option ( name , value , context , source , action , true ) ;
( void ) set_config_option ( name , value ,
context , source ,
action , true , 0 ) ;
free ( name ) ;
if ( value )
@ -7873,7 +7985,7 @@ validate_option_array_item(const char *name, const char *value,
/* test for permissions and valid option value */
( void ) set_config_option ( name , value ,
superuser ( ) ? PGC_SUSET : PGC_USERSET ,
PGC_S_TEST , GUC_ACTION_SET , false ) ;
PGC_S_TEST , GUC_ACTION_SET , false , 0 ) ;
return true ;
}