|
10 | 10 | * Written by Peter Eisentraut <peter_e@gmx.net>.
|
11 | 11 | *
|
12 | 12 | * IDENTIFICATION
|
13 |
| - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.400 2007/06/20 18:31:39 tgl Exp $ |
| 13 | + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.401 2007/06/21 18:14:21 tgl Exp $ |
14 | 14 | *
|
15 | 15 | *--------------------------------------------------------------------
|
16 | 16 | */
|
|
94 | 94 | #defineKB_PER_GB (1024*1024)
|
95 | 95 |
|
96 | 96 | #defineMS_PER_S 1000
|
| 97 | +#defineS_PER_MIN 60 |
97 | 98 | #defineMS_PER_MIN (1000 * 60)
|
| 99 | +#defineMIN_PER_H 60 |
| 100 | +#defineS_PER_H (60 * 60) |
98 | 101 | #defineMS_PER_H (1000 * 60 * 60)
|
| 102 | +#defineMIN_PER_D (60 * 24) |
| 103 | +#defineS_PER_D (60 * 60 * 24) |
99 | 104 | #defineMS_PER_D (1000 * 60 * 60 * 24)
|
100 | 105 |
|
101 | 106 | /* XXX these should appear in other modules' header files */
|
@@ -3783,124 +3788,209 @@ parse_bool(const char *value, bool *result)
|
3783 | 3788 |
|
3784 | 3789 | /*
|
3785 | 3790 | * Try to parse value as an integer. The accepted formats are the
|
3786 |
| - * usual decimal, octal, or hexadecimal formats. If the string parses |
3787 |
| - * okay, return true, else false. If result is not NULL, return the |
3788 |
| - * value there. |
| 3791 | + * usual decimal, octal, or hexadecimal formats, optionally followed by |
| 3792 | + * a unit name if "flags" indicates a unit is allowed. |
| 3793 | + * |
| 3794 | + * If the string parses okay, return true, else false. |
| 3795 | + * If okay and result is not NULL, return the value in *result. |
| 3796 | + * If not okay and hintmsg is not NULL, *hintmsg is set to a suitable |
| 3797 | + *HINT message, or NULL if no hint provided. |
3789 | 3798 | */
|
3790 | 3799 | staticbool
|
3791 |
| -parse_int(constchar*value,int*result,intflags) |
| 3800 | +parse_int(constchar*value,int*result,intflags,constchar**hintmsg) |
3792 | 3801 | {
|
3793 |
| -longval; |
| 3802 | +int64val; |
3794 | 3803 | char*endptr;
|
3795 | 3804 |
|
| 3805 | +/* To suppress compiler warnings, always set output params */ |
| 3806 | +if (result) |
| 3807 | +*result=0; |
| 3808 | +if (hintmsg) |
| 3809 | +*hintmsg=NULL; |
| 3810 | + |
| 3811 | +/* We assume here that int64 is at least as wide as long */ |
3796 | 3812 | errno=0;
|
3797 | 3813 | val=strtol(value,&endptr,0);
|
3798 | 3814 |
|
3799 |
| -if ((flags&GUC_UNIT_MEMORY)&&endptr!=value) |
| 3815 | +if (endptr==value) |
| 3816 | +return false;/* no HINT for integer syntax error */ |
| 3817 | + |
| 3818 | +if (errno==ERANGE||val!= (int64) ((int32)val)) |
3800 | 3819 | {
|
3801 |
| -boolused= false; |
| 3820 | +if (hintmsg) |
| 3821 | +*hintmsg=gettext_noop("Value exceeds integer range."); |
| 3822 | +return false; |
| 3823 | +} |
3802 | 3824 |
|
3803 |
| -while (*endptr==' ') |
3804 |
| -endptr++; |
| 3825 | +/* allow whitespace between integer and unit */ |
| 3826 | +while (isspace((unsignedchar)*endptr)) |
| 3827 | +endptr++; |
3805 | 3828 |
|
3806 |
| -if (strcmp(endptr,"kB")==0) |
3807 |
| -{ |
3808 |
| -used= true; |
3809 |
| -endptr+=2; |
3810 |
| -} |
3811 |
| -elseif (strcmp(endptr,"MB")==0) |
3812 |
| -{ |
3813 |
| -val *=KB_PER_MB; |
3814 |
| -used= true; |
3815 |
| -endptr+=2; |
3816 |
| -} |
3817 |
| -elseif (strcmp(endptr,"GB")==0) |
| 3829 | +/* Handle possible unit */ |
| 3830 | +if (*endptr!='\0') |
| 3831 | +{ |
| 3832 | +/* |
| 3833 | + * Note: the multiple-switch coding technique here is a bit tedious, |
| 3834 | + * but seems necessary to avoid intermediate-value overflows. |
| 3835 | + * |
| 3836 | + * If INT64_IS_BUSTED (ie, it's really int32) we will fail to detect |
| 3837 | + * overflow due to units conversion, but there are few enough such |
| 3838 | + * machines that it does not seem worth trying to be smarter. |
| 3839 | + */ |
| 3840 | +if (flags&GUC_UNIT_MEMORY) |
3818 | 3841 | {
|
3819 |
| -val *=KB_PER_GB; |
3820 |
| -used= true; |
3821 |
| -endptr+=2; |
3822 |
| -} |
| 3842 | +/* Set hint for use if no match or trailing garbage */ |
| 3843 | +if (hintmsg) |
| 3844 | +*hintmsg=gettext_noop("Valid units for this parameter are \"kB\", \"MB\", and \"GB\"."); |
3823 | 3845 |
|
3824 |
| -#ifBLCKSZ<1024 |
3825 |
| -#error BLCKSZ must be >= 1024 |
| 3846 | +#ifBLCKSZ<1024||BLCKSZ> (1024*1024) |
| 3847 | +#error BLCKSZ must be between 1KB and 1MB |
| 3848 | +#endif |
| 3849 | +#ifXLOG_BLCKSZ<1024||XLOG_BLCKSZ> (1024*1024) |
| 3850 | +#error XLOG_BLCKSZ must be between 1KB and 1MB |
3826 | 3851 | #endif
|
3827 | 3852 |
|
3828 |
| -if (used) |
3829 |
| -{ |
3830 |
| -switch (flags&GUC_UNIT_MEMORY) |
| 3853 | +if (strncmp(endptr,"kB",2)==0) |
3831 | 3854 | {
|
3832 |
| -caseGUC_UNIT_BLOCKS: |
3833 |
| -val /= (BLCKSZ /1024); |
3834 |
| -break; |
3835 |
| -caseGUC_UNIT_XBLOCKS: |
3836 |
| -val /= (XLOG_BLCKSZ /1024); |
3837 |
| -break; |
| 3855 | +endptr+=2; |
| 3856 | +switch (flags&GUC_UNIT_MEMORY) |
| 3857 | +{ |
| 3858 | +caseGUC_UNIT_BLOCKS: |
| 3859 | +val /= (BLCKSZ /1024); |
| 3860 | +break; |
| 3861 | +caseGUC_UNIT_XBLOCKS: |
| 3862 | +val /= (XLOG_BLCKSZ /1024); |
| 3863 | +break; |
| 3864 | +} |
| 3865 | +} |
| 3866 | +elseif (strncmp(endptr,"MB",2)==0) |
| 3867 | +{ |
| 3868 | +endptr+=2; |
| 3869 | +switch (flags&GUC_UNIT_MEMORY) |
| 3870 | +{ |
| 3871 | +caseGUC_UNIT_KB: |
| 3872 | +val *=KB_PER_MB; |
| 3873 | +break; |
| 3874 | +caseGUC_UNIT_BLOCKS: |
| 3875 | +val *=KB_PER_MB / (BLCKSZ /1024); |
| 3876 | +break; |
| 3877 | +caseGUC_UNIT_XBLOCKS: |
| 3878 | +val *=KB_PER_MB / (XLOG_BLCKSZ /1024); |
| 3879 | +break; |
| 3880 | +} |
| 3881 | +} |
| 3882 | +elseif (strncmp(endptr,"GB",2)==0) |
| 3883 | +{ |
| 3884 | +endptr+=2; |
| 3885 | +switch (flags&GUC_UNIT_MEMORY) |
| 3886 | +{ |
| 3887 | +caseGUC_UNIT_KB: |
| 3888 | +val *=KB_PER_GB; |
| 3889 | +break; |
| 3890 | +caseGUC_UNIT_BLOCKS: |
| 3891 | +val *=KB_PER_GB / (BLCKSZ /1024); |
| 3892 | +break; |
| 3893 | +caseGUC_UNIT_XBLOCKS: |
| 3894 | +val *=KB_PER_GB / (XLOG_BLCKSZ /1024); |
| 3895 | +break; |
| 3896 | +} |
3838 | 3897 | }
|
3839 | 3898 | }
|
3840 |
| -} |
| 3899 | +elseif (flags&GUC_UNIT_TIME) |
| 3900 | +{ |
| 3901 | +/* Set hint for use if no match or trailing garbage */ |
| 3902 | +if (hintmsg) |
| 3903 | +*hintmsg=gettext_noop("Valid units for this parameter are \"ms\", \"s\", \"min\", \"h\", and \"d\"."); |
3841 | 3904 |
|
3842 |
| -if ((flags&GUC_UNIT_TIME)&&endptr!=value) |
3843 |
| -{ |
3844 |
| -boolused= false; |
| 3905 | +if (strncmp(endptr,"ms",2)==0) |
| 3906 | +{ |
| 3907 | +endptr+=2; |
| 3908 | +switch (flags&GUC_UNIT_TIME) |
| 3909 | +{ |
| 3910 | +caseGUC_UNIT_S: |
| 3911 | +val /=MS_PER_S; |
| 3912 | +break; |
| 3913 | +caseGUC_UNIT_MIN: |
| 3914 | +val /=MS_PER_MIN; |
| 3915 | +break; |
| 3916 | +} |
| 3917 | +} |
| 3918 | +elseif (strncmp(endptr,"s",1)==0) |
| 3919 | +{ |
| 3920 | +endptr+=1; |
| 3921 | +switch (flags&GUC_UNIT_TIME) |
| 3922 | +{ |
| 3923 | +caseGUC_UNIT_MS: |
| 3924 | +val *=MS_PER_S; |
| 3925 | +break; |
| 3926 | +caseGUC_UNIT_MIN: |
| 3927 | +val /=S_PER_MIN; |
| 3928 | +break; |
| 3929 | +} |
| 3930 | +} |
| 3931 | +elseif (strncmp(endptr,"min",3)==0) |
| 3932 | +{ |
| 3933 | +endptr+=3; |
| 3934 | +switch (flags&GUC_UNIT_TIME) |
| 3935 | +{ |
| 3936 | +caseGUC_UNIT_MS: |
| 3937 | +val *=MS_PER_MIN; |
| 3938 | +break; |
| 3939 | +caseGUC_UNIT_S: |
| 3940 | +val *=S_PER_MIN; |
| 3941 | +break; |
| 3942 | +} |
| 3943 | +} |
| 3944 | +elseif (strncmp(endptr,"h",1)==0) |
| 3945 | +{ |
| 3946 | +endptr+=1; |
| 3947 | +switch (flags&GUC_UNIT_TIME) |
| 3948 | +{ |
| 3949 | +caseGUC_UNIT_MS: |
| 3950 | +val *=MS_PER_H; |
| 3951 | +break; |
| 3952 | +caseGUC_UNIT_S: |
| 3953 | +val *=S_PER_H; |
| 3954 | +break; |
| 3955 | +caseGUC_UNIT_MIN: |
| 3956 | +val *=MIN_PER_H; |
| 3957 | +break; |
| 3958 | +} |
| 3959 | +} |
| 3960 | +elseif (strncmp(endptr,"d",1)==0) |
| 3961 | +{ |
| 3962 | +endptr+=1; |
| 3963 | +switch (flags&GUC_UNIT_TIME) |
| 3964 | +{ |
| 3965 | +caseGUC_UNIT_MS: |
| 3966 | +val *=MS_PER_D; |
| 3967 | +break; |
| 3968 | +caseGUC_UNIT_S: |
| 3969 | +val *=S_PER_D; |
| 3970 | +break; |
| 3971 | +caseGUC_UNIT_MIN: |
| 3972 | +val *=MIN_PER_D; |
| 3973 | +break; |
| 3974 | +} |
| 3975 | +} |
| 3976 | +} |
3845 | 3977 |
|
3846 |
| -while (*endptr==' ') |
| 3978 | +/* allow whitespace after unit */ |
| 3979 | +while (isspace((unsignedchar)*endptr)) |
3847 | 3980 | endptr++;
|
3848 | 3981 |
|
3849 |
| -if (strcmp(endptr,"ms")==0) |
3850 |
| -{ |
3851 |
| -used= true; |
3852 |
| -endptr+=2; |
3853 |
| -} |
3854 |
| -elseif (strcmp(endptr,"s")==0) |
3855 |
| -{ |
3856 |
| -val *=MS_PER_S; |
3857 |
| -used= true; |
3858 |
| -endptr+=1; |
3859 |
| -} |
3860 |
| -elseif (strcmp(endptr,"min")==0) |
3861 |
| -{ |
3862 |
| -val *=MS_PER_MIN; |
3863 |
| -used= true; |
3864 |
| -endptr+=3; |
3865 |
| -} |
3866 |
| -elseif (strcmp(endptr,"h")==0) |
3867 |
| -{ |
3868 |
| -val *=MS_PER_H; |
3869 |
| -used= true; |
3870 |
| -endptr+=1; |
3871 |
| -} |
3872 |
| -elseif (strcmp(endptr,"d")==0) |
3873 |
| -{ |
3874 |
| -val *=MS_PER_D; |
3875 |
| -used= true; |
3876 |
| -endptr+=1; |
3877 |
| -} |
| 3982 | +if (*endptr!='\0') |
| 3983 | +return false;/* appropriate hint, if any, already set */ |
3878 | 3984 |
|
3879 |
| -if (used) |
| 3985 | +/* Check for overflow due to units conversion */ |
| 3986 | +if (val!= (int64) ((int32)val)) |
3880 | 3987 | {
|
3881 |
| -switch (flags&GUC_UNIT_TIME) |
3882 |
| -{ |
3883 |
| -caseGUC_UNIT_S: |
3884 |
| -val /=MS_PER_S; |
3885 |
| -break; |
3886 |
| -caseGUC_UNIT_MIN: |
3887 |
| -val /=MS_PER_MIN; |
3888 |
| -break; |
3889 |
| -} |
| 3988 | +if (hintmsg) |
| 3989 | +*hintmsg=gettext_noop("Value exceeds integer range."); |
| 3990 | +return false; |
3890 | 3991 | }
|
3891 | 3992 | }
|
3892 | 3993 |
|
3893 |
| -if (endptr==value||*endptr!='\0'||errno==ERANGE |
3894 |
| -#ifdefHAVE_LONG_INT_64 |
3895 |
| -/* if long > 32 bits, check for overflow of int4 */ |
3896 |
| -||val!= (long) ((int32)val) |
3897 |
| -#endif |
3898 |
| -) |
3899 |
| -{ |
3900 |
| -if (result) |
3901 |
| -*result=0;/* suppress compiler warning */ |
3902 |
| -return false; |
3903 |
| -} |
3904 | 3994 | if (result)
|
3905 | 3995 | *result= (int)val;
|
3906 | 3996 | return true;
|
@@ -4243,12 +4333,15 @@ set_config_option(const char *name, const char *value,
|
4243 | 4333 |
|
4244 | 4334 | if (value)
|
4245 | 4335 | {
|
4246 |
| -if (!parse_int(value,&newval,conf->gen.flags)) |
| 4336 | +constchar*hintmsg; |
| 4337 | + |
| 4338 | +if (!parse_int(value,&newval,conf->gen.flags,&hintmsg)) |
4247 | 4339 | {
|
4248 | 4340 | ereport(elevel,
|
4249 | 4341 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
4250 |
| -errmsg("parameter \"%s\" requires an integer value", |
4251 |
| -name))); |
| 4342 | +errmsg("invalid value for parameter \"%s\": \"%s\"", |
| 4343 | +name,value), |
| 4344 | +hintmsg ?errhint(hintmsg) :0)); |
4252 | 4345 | return false;
|
4253 | 4346 | }
|
4254 | 4347 | if (newval<conf->min||newval>conf->max)
|
@@ -5674,21 +5767,24 @@ is_newvalue_equal(struct config_generic * record, const char *newvalue)
|
5674 | 5767 | structconfig_bool*conf= (structconfig_bool*)record;
|
5675 | 5768 | boolnewval;
|
5676 | 5769 |
|
5677 |
| -returnparse_bool(newvalue,&newval)&&*conf->variable==newval; |
| 5770 | +returnparse_bool(newvalue,&newval) |
| 5771 | +&&*conf->variable==newval; |
5678 | 5772 | }
|
5679 | 5773 | casePGC_INT:
|
5680 | 5774 | {
|
5681 | 5775 | structconfig_int*conf= (structconfig_int*)record;
|
5682 | 5776 | intnewval;
|
5683 | 5777 |
|
5684 |
| -returnparse_int(newvalue,&newval,record->flags)&&*conf->variable==newval; |
| 5778 | +returnparse_int(newvalue,&newval,record->flags,NULL) |
| 5779 | +&&*conf->variable==newval; |
5685 | 5780 | }
|
5686 | 5781 | casePGC_REAL:
|
5687 | 5782 | {
|
5688 | 5783 | structconfig_real*conf= (structconfig_real*)record;
|
5689 | 5784 | doublenewval;
|
5690 | 5785 |
|
5691 |
| -returnparse_real(newvalue,&newval)&&*conf->variable==newval; |
| 5786 | +returnparse_real(newvalue,&newval) |
| 5787 | +&&*conf->variable==newval; |
5692 | 5788 | }
|
5693 | 5789 | casePGC_STRING:
|
5694 | 5790 | {
|
|