@ -10,7 +10,7 @@
* Written by Peter Eisentraut < peter_e @ gmx . net > .
*
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / backend / utils / misc / guc . c , v 1.400 2007 / 06 / 20 18 : 31 : 39 tgl Exp $
* $ PostgreSQL : pgsql / src / backend / utils / misc / guc . c , v 1.401 2007 / 06 / 21 18 : 14 : 21 tgl Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -94,8 +94,13 @@
# define KB_PER_GB (1024*1024)
# define MS_PER_S 1000
# define S_PER_MIN 60
# define MS_PER_MIN (1000 * 60)
# define MIN_PER_H 60
# define S_PER_H (60 * 60)
# define MS_PER_H (1000 * 60 * 60)
# define MIN_PER_D (60 * 24)
# define S_PER_D (60 * 60 * 24)
# define MS_PER_D (1000 * 60 * 60 * 24)
/* XXX these should appear in other modules' header files */
@ -3783,124 +3788,209 @@ parse_bool(const char *value, bool *result)
/*
* Try to parse value as an integer . The accepted formats are the
* usual decimal , octal , or hexadecimal formats . If the string parses
* okay , return true , else false . If result is not NULL , return the
* value there .
* usual decimal , octal , or hexadecimal formats , optionally followed by
* a unit name if " flags " indicates a unit is allowed .
*
* If the string parses okay , return true , else false .
* If okay and result is not NULL , return the value in * result .
* If not okay and hintmsg is not NULL , * hintmsg is set to a suitable
* HINT message , or NULL if no hint provided .
*/
static bool
parse_int ( const char * value , int * result , int flags )
parse_int ( const char * value , int * result , int flags , const char * * hintmsg )
{
long val ;
int64 val ;
char * endptr ;
/* To suppress compiler warnings, always set output params */
if ( result )
* result = 0 ;
if ( hintmsg )
* hintmsg = NULL ;
/* We assume here that int64 is at least as wide as long */
errno = 0 ;
val = strtol ( value , & endptr , 0 ) ;
if ( ( flags & GUC_UNIT_MEMORY ) & & endptr ! = value )
if ( endptr = = value )
return false ; /* no HINT for integer syntax error */
if ( errno = = ERANGE | | val ! = ( int64 ) ( ( int32 ) val ) )
{
bool used = false ;
if ( hintmsg )
* hintmsg = gettext_noop ( " Value exceeds integer range. " ) ;
return false ;
}
while ( * endptr = = ' ' )
endptr + + ;
/* allow whitespace between integer and unit */
while ( isspace ( ( unsigned char ) * endptr ) )
endptr + + ;
if ( strcmp ( endptr , " kB " ) = = 0 )
{
used = true ;
endptr + = 2 ;
}
else if ( strcmp ( endptr , " MB " ) = = 0 )
{
val * = KB_PER_MB ;
used = true ;
endptr + = 2 ;
}
else if ( strcmp ( endptr , " GB " ) = = 0 )
/* Handle possible unit */
if ( * endptr ! = ' \0 ' )
{
/*
* Note : the multiple - switch coding technique here is a bit tedious ,
* but seems necessary to avoid intermediate - value overflows .
*
* If INT64_IS_BUSTED ( ie , it ' s really int32 ) we will fail to detect
* overflow due to units conversion , but there are few enough such
* machines that it does not seem worth trying to be smarter .
*/
if ( flags & GUC_UNIT_MEMORY )
{
val * = KB_PER_GB ;
used = true ;
endptr + = 2 ;
}
/* Set hint for use if no match or trailing garbage */
if ( hintmsg )
* hintmsg = gettext_noop ( " Valid units for this parameter are \" kB \" , \" MB \" , and \" GB \" . " ) ;
# if BLCKSZ < 1024
# error BLCKSZ must be >= 1024
# if BLCKSZ < 1024 || BLCKSZ > (1024*1024)
# error BLCKSZ must be between 1KB and 1MB
# endif
# if XLOG_BLCKSZ < 1024 || XLOG_BLCKSZ > (1024*1024)
# error XLOG_BLCKSZ must be between 1KB and 1MB
# endif
if ( used )
{
switch ( flags & GUC_UNIT_MEMORY )
if ( strncmp ( endptr , " kB " , 2 ) = = 0 )
{
case GUC_UNIT_BLOCKS :
val / = ( BLCKSZ / 1024 ) ;
break ;
case GUC_UNIT_XBLOCKS :
val / = ( XLOG_BLCKSZ / 1024 ) ;
break ;
endptr + = 2 ;
switch ( flags & GUC_UNIT_MEMORY )
{
case GUC_UNIT_BLOCKS :
val / = ( BLCKSZ / 1024 ) ;
break ;
case GUC_UNIT_XBLOCKS :
val / = ( XLOG_BLCKSZ / 1024 ) ;
break ;
}
}
else if ( strncmp ( endptr , " MB " , 2 ) = = 0 )
{
endptr + = 2 ;
switch ( flags & GUC_UNIT_MEMORY )
{
case GUC_UNIT_KB :
val * = KB_PER_MB ;
break ;
case GUC_UNIT_BLOCKS :
val * = KB_PER_MB / ( BLCKSZ / 1024 ) ;
break ;
case GUC_UNIT_XBLOCKS :
val * = KB_PER_MB / ( XLOG_BLCKSZ / 1024 ) ;
break ;
}
}
else if ( strncmp ( endptr , " GB " , 2 ) = = 0 )
{
endptr + = 2 ;
switch ( flags & GUC_UNIT_MEMORY )
{
case GUC_UNIT_KB :
val * = KB_PER_GB ;
break ;
case GUC_UNIT_BLOCKS :
val * = KB_PER_GB / ( BLCKSZ / 1024 ) ;
break ;
case GUC_UNIT_XBLOCKS :
val * = KB_PER_GB / ( XLOG_BLCKSZ / 1024 ) ;
break ;
}
}
}
}
else if ( flags & GUC_UNIT_TIME )
{
/* Set hint for use if no match or trailing garbage */
if ( hintmsg )
* hintmsg = gettext_noop ( " Valid units for this parameter are \" ms \" , \" s \" , \" min \" , \" h \" , and \" d \" . " ) ;
if ( ( flags & GUC_UNIT_TIME ) & & endptr ! = value )
{
bool used = false ;
if ( strncmp ( endptr , " ms " , 2 ) = = 0 )
{
endptr + = 2 ;
switch ( flags & GUC_UNIT_TIME )
{
case GUC_UNIT_S :
val / = MS_PER_S ;
break ;
case GUC_UNIT_MIN :
val / = MS_PER_MIN ;
break ;
}
}
else if ( strncmp ( endptr , " s " , 1 ) = = 0 )
{
endptr + = 1 ;
switch ( flags & GUC_UNIT_TIME )
{
case GUC_UNIT_MS :
val * = MS_PER_S ;
break ;
case GUC_UNIT_MIN :
val / = S_PER_MIN ;
break ;
}
}
else if ( strncmp ( endptr , " min " , 3 ) = = 0 )
{
endptr + = 3 ;
switch ( flags & GUC_UNIT_TIME )
{
case GUC_UNIT_MS :
val * = MS_PER_MIN ;
break ;
case GUC_UNIT_S :
val * = S_PER_MIN ;
break ;
}
}
else if ( strncmp ( endptr , " h " , 1 ) = = 0 )
{
endptr + = 1 ;
switch ( flags & GUC_UNIT_TIME )
{
case GUC_UNIT_MS :
val * = MS_PER_H ;
break ;
case GUC_UNIT_S :
val * = S_PER_H ;
break ;
case GUC_UNIT_MIN :
val * = MIN_PER_H ;
break ;
}
}
else if ( strncmp ( endptr , " d " , 1 ) = = 0 )
{
endptr + = 1 ;
switch ( flags & GUC_UNIT_TIME )
{
case GUC_UNIT_MS :
val * = MS_PER_D ;
break ;
case GUC_UNIT_S :
val * = S_PER_D ;
break ;
case GUC_UNIT_MIN :
val * = MIN_PER_D ;
break ;
}
}
}
while ( * endptr = = ' ' )
/* allow whitespace after unit */
while ( isspace ( ( unsigned char ) * endptr ) )
endptr + + ;
if ( strcmp ( endptr , " ms " ) = = 0 )
{
used = true ;
endptr + = 2 ;
}
else if ( strcmp ( endptr , " s " ) = = 0 )
{
val * = MS_PER_S ;
used = true ;
endptr + = 1 ;
}
else if ( strcmp ( endptr , " min " ) = = 0 )
{
val * = MS_PER_MIN ;
used = true ;
endptr + = 3 ;
}
else if ( strcmp ( endptr , " h " ) = = 0 )
{
val * = MS_PER_H ;
used = true ;
endptr + = 1 ;
}
else if ( strcmp ( endptr , " d " ) = = 0 )
{
val * = MS_PER_D ;
used = true ;
endptr + = 1 ;
}
if ( * endptr ! = ' \0 ' )
return false ; /* appropriate hint, if any, already set */
if ( used )
/* Check for overflow due to units conversion */
if ( val ! = ( int64 ) ( ( int32 ) val ) )
{
switch ( flags & GUC_UNIT_TIME )
{
case GUC_UNIT_S :
val / = MS_PER_S ;
break ;
case GUC_UNIT_MIN :
val / = MS_PER_MIN ;
break ;
}
if ( hintmsg )
* hintmsg = gettext_noop ( " Value exceeds integer range. " ) ;
return false ;
}
}
if ( endptr = = value | | * endptr ! = ' \0 ' | | errno = = ERANGE
# ifdef HAVE_LONG_INT_64
/* if long > 32 bits, check for overflow of int4 */
| | val ! = ( long ) ( ( int32 ) val )
# endif
)
{
if ( result )
* result = 0 ; /* suppress compiler warning */
return false ;
}
if ( result )
* result = ( int ) val ;
return true ;
@ -4243,12 +4333,15 @@ set_config_option(const char *name, const char *value,
if ( value )
{
if ( ! parse_int ( value , & newval , conf - > gen . flags ) )
const char * hintmsg ;
if ( ! parse_int ( value , & newval , conf - > gen . flags , & hintmsg ) )
{
ereport ( elevel ,
( errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) ,
errmsg ( " parameter \" %s \" requires an integer value " ,
name ) ) ) ;
errmsg ( " invalid value for parameter \" %s \" : \" %s \" " ,
name , value ) ,
hintmsg ? errhint ( hintmsg ) : 0 ) ) ;
return false ;
}
if ( newval < conf - > min | | newval > conf - > max )
@ -5674,21 +5767,24 @@ is_newvalue_equal(struct config_generic * record, const char *newvalue)
struct config_bool * conf = ( struct config_bool * ) record ;
bool newval ;
return parse_bool ( newvalue , & newval ) & & * conf - > variable = = newval ;
return parse_bool ( newvalue , & newval )
& & * conf - > variable = = newval ;
}
case PGC_INT :
{
struct config_int * conf = ( struct config_int * ) record ;
int newval ;
return parse_int ( newvalue , & newval , record - > flags ) & & * conf - > variable = = newval ;
return parse_int ( newvalue , & newval , record - > flags , NULL )
& & * conf - > variable = = newval ;
}
case PGC_REAL :
{
struct config_real * conf = ( struct config_real * ) record ;
double newval ;
return parse_real ( newvalue , & newval ) & & * conf - > variable = = newval ;
return parse_real ( newvalue , & newval )
& & * conf - > variable = = newval ;
}
case PGC_STRING :
{