Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit80ac9b0

Browse files
author
Neil Conway
committed
Portability fixes and bug fixes for recent floating point input changes.
In particular, don't depend on strtod() to accept 'NaN' and 'Infinity'inputs (while this is required by C99, not all platforms are compliantwith that yet). Also, don't require glibc's behavior from isinf():it seems that on a lot of platforms isinf() does not itself distinguishbetween negative and positive infinity.
1 parent7665d1b commit80ac9b0

File tree

1 file changed

+157
-66
lines changed

1 file changed

+157
-66
lines changed

‎src/backend/utils/adt/float.c

Lines changed: 157 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.99 2004/03/12 00:25:40 neilc Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.100 2004/03/14 05:22:52 neilc Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -109,9 +109,30 @@ intextra_float_digits = 0;/* Added to DBL_DIG or FLT_DIG */
109109

110110
staticvoidCheckFloat4Val(doubleval);
111111
staticvoidCheckFloat8Val(doubleval);
112+
staticintis_infinite(doubleval);
112113
staticintfloat4_cmp_internal(float4a,float4b);
113114
staticintfloat8_cmp_internal(float8a,float8b);
114115

116+
/*
117+
* Returns -1 if 'val' represents negative infinity, 1 if 'val'
118+
* represents (positive) infinity, and 0 otherwise. On some platforms,
119+
* this is equivalent to the isinf() macro, but not everywhere: C99
120+
* does not specify that isinf() needs to distinguish between positive
121+
* and negative infinity.
122+
*/
123+
staticint
124+
is_infinite(doubleval)
125+
{
126+
intinf=isinf(val);
127+
128+
if (inf==0)
129+
return0;
130+
131+
if (val>0)
132+
return1;
133+
134+
return-1;
135+
}
115136

116137
/*
117138
* check to see if a float4 val is outside of the FLOAT4_MIN,
@@ -162,48 +183,78 @@ Datum
162183
float4in(PG_FUNCTION_ARGS)
163184
{
164185
char*num=PG_GETARG_CSTRING(0);
186+
char*orig_num;
165187
doubleval;
166188
char*endptr;
167189

190+
/*
191+
* endptr points to the first character _after_ the sequence we
192+
* recognized as a valid floating point number. orig_num points to
193+
* the original input string.
194+
*/
195+
orig_num=num;
196+
197+
/*
198+
* Check for an empty-string input to begin with, to avoid
199+
* the vagaries of strtod() on different platforms.
200+
*
201+
* In releases prior to 7.5, we accepted an empty string as valid
202+
* input (yielding a float4 of 0). In 7.5, we accept empty
203+
* strings, but emit a warning noting that the feature is
204+
* deprecated. In 7.6+, the warning should be replaced by an
205+
* error.
206+
*/
207+
if (*num=='\0')
208+
{
209+
ereport(WARNING,
210+
(errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
211+
errmsg("deprecated input syntax for type real: \"\""),
212+
errdetail("This input will be rejected in "
213+
"a future release of PostgreSQL.")));
214+
PG_RETURN_FLOAT4((float4)0.0);
215+
}
216+
217+
/* skip leading whitespace */
218+
while (*num!='\0'&&isspace(*num))
219+
num++;
220+
168221
errno=0;
169222
val=strtod(num,&endptr);
170223

171224
if (errno==ERANGE)
172225
ereport(ERROR,
173226
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
174-
errmsg("\"%s\" is out of range for type real",num)));
227+
errmsg("\"%s\" is out of range for type real",
228+
orig_num)));
175229

230+
/* did we not see anything that looks like a double? */
176231
if (num==endptr)
177232
{
178233
/*
179-
* We didn't find anything that looks like a float in the input
180-
*
181-
* In releases prior to 7.5, we accepted an empty string as
182-
* valid input (yielding a float8 of 0). In 7.5, we accept
183-
* empty strings, but emit a warning noting that the feature
184-
* is deprecated. In 7.6+, the warning should be replaced by
185-
* an error.
234+
* C99 requires that strtod() accept NaN and [-]Infinity, but
235+
* not all platforms support that yet. Therefore, we check for
236+
* these inputs ourselves.
186237
*/
187-
if (*num=='\0')
238+
if (strncasecmp(num,"NaN",3)==0)
188239
{
189-
ereport(WARNING,
190-
(errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
191-
errmsg("deprecated input syntax for type real: \"\""),
192-
errdetail("This input will be rejected in "
193-
"a future release of PostgreSQL.")));
194-
Assert(val==0.0);
195-
}
196-
elseif (strcasecmp(num,"NaN")==0)
197240
val=NAN;
198-
elseif (strcasecmp(num,"Infinity")==0)
241+
endptr=num+3;
242+
}
243+
elseif (strncasecmp(num,"Infinity",8)==0)
244+
{
199245
val=HUGE_VAL;
200-
elseif (strcasecmp(num,"-Infinity")==0)
246+
endptr=num+8;
247+
}
248+
elseif (strncasecmp(num,"-Infinity",9)==0)
249+
{
201250
val=-HUGE_VAL;
251+
endptr=num+9;
252+
}
202253
else
203254
ereport(ERROR,
204255
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
205256
errmsg("invalid input syntax for type real: \"%s\"",
206-
num)));
257+
orig_num)));
207258
}
208259

209260
/* skip trailing whitespace */
@@ -215,11 +266,11 @@ float4in(PG_FUNCTION_ARGS)
215266
ereport(ERROR,
216267
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
217268
errmsg("invalid input syntax for type real: \"%s\"",
218-
num)));
269+
orig_num)));
219270

220271
/*
221272
* if we get here, we have a legal double, still need to check to see
222-
* if it's a legalfloat
273+
* if it's a legalfloat4
223274
*/
224275
if (!isinf(val))
225276
CheckFloat4Val(val);
@@ -236,22 +287,27 @@ float4out(PG_FUNCTION_ARGS)
236287
{
237288
float4num=PG_GETARG_FLOAT4(0);
238289
char*ascii= (char*)palloc(MAXFLOATWIDTH+1);
239-
intinfflag;
240-
intndig;
241290

242291
if (isnan(num))
243292
PG_RETURN_CSTRING(strcpy(ascii,"NaN"));
244-
infflag=isinf(num);
245-
if (infflag>0)
246-
PG_RETURN_CSTRING(strcpy(ascii,"Infinity"));
247-
if (infflag<0)
248-
PG_RETURN_CSTRING(strcpy(ascii,"-Infinity"));
249293

250-
ndig=FLT_DIG+extra_float_digits;
251-
if (ndig<1)
252-
ndig=1;
294+
switch (is_infinite(num))
295+
{
296+
case1:
297+
strcpy(ascii,"Infinity");
298+
break;
299+
case-1:
300+
strcpy(ascii,"-Infinity");
301+
break;
302+
default:
303+
{
304+
intndig=FLT_DIG+extra_float_digits;
305+
if (ndig<1)
306+
ndig=1;
253307

254-
sprintf(ascii,"%.*g",ndig,num);
308+
sprintf(ascii,"%.*g",ndig,num);
309+
}
310+
}
255311

256312
PG_RETURN_CSTRING(ascii);
257313
}
@@ -292,48 +348,78 @@ Datum
292348
float8in(PG_FUNCTION_ARGS)
293349
{
294350
char*num=PG_GETARG_CSTRING(0);
351+
char*orig_num;
295352
doubleval;
296353
char*endptr;
297354

355+
/*
356+
* endptr points to the first character _after_ the sequence we
357+
* recognized as a valid floating point number. orig_num points to
358+
* the original input string.
359+
*/
360+
orig_num=num;
361+
362+
/*
363+
* Check for an empty-string input to begin with, to avoid
364+
* the vagaries of strtod() on different platforms.
365+
*
366+
* In releases prior to 7.5, we accepted an empty string as valid
367+
* input (yielding a float8 of 0). In 7.5, we accept empty
368+
* strings, but emit a warning noting that the feature is
369+
* deprecated. In 7.6+, the warning should be replaced by an
370+
* error.
371+
*/
372+
if (*num=='\0')
373+
{
374+
ereport(WARNING,
375+
(errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
376+
errmsg("deprecated input syntax for type double precision: \"\""),
377+
errdetail("This input will be rejected in "
378+
"a future release of PostgreSQL.")));
379+
PG_RETURN_FLOAT8(0.0);
380+
}
381+
382+
/* skip leading whitespace */
383+
while (*num!='\0'&&isspace(*num))
384+
num++;
385+
298386
errno=0;
299387
val=strtod(num,&endptr);
300388

301389
if (errno==ERANGE)
302390
ereport(ERROR,
303391
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
304-
errmsg("\"%s\" is out of range for type double precision",num)));
392+
errmsg("\"%s\" is out of range for type double precision",
393+
orig_num)));
305394

395+
/* did we not see anything that looks like a double? */
306396
if (num==endptr)
307397
{
308398
/*
309-
* We didn't find anything that looks like a float in the input
310-
*
311-
* In releases prior to 7.5, we accepted an empty string as
312-
* valid input (yielding a float8 of 0). In 7.5, we accept
313-
* empty strings, but emit a warning noting that the feature
314-
* is deprecated. In 7.6+, the warning should be replaced by
315-
* an error.
399+
* C99 requires that strtod() accept NaN and [-]Infinity, but
400+
* not all platforms support that yet. Therefore, we check for
401+
* these inputs ourselves.
316402
*/
317-
if (*num=='\0')
403+
if (strncasecmp(num,"NaN",3)==0)
318404
{
319-
ereport(WARNING,
320-
(errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
321-
errmsg("deprecated input syntax for type double precision: \"\""),
322-
errdetail("This input will be rejected in "
323-
"a future release of PostgreSQL.")));
324-
Assert(val==0.0);
325-
}
326-
elseif (strcasecmp(num,"NaN")==0)
327405
val=NAN;
328-
elseif (strcasecmp(num,"Infinity")==0)
406+
endptr=num+3;
407+
}
408+
elseif (strncasecmp(num,"Infinity",8)==0)
409+
{
329410
val=HUGE_VAL;
330-
elseif (strcasecmp(num,"-Infinity")==0)
411+
endptr=num+8;
412+
}
413+
elseif (strncasecmp(num,"-Infinity",9)==0)
414+
{
331415
val=-HUGE_VAL;
416+
endptr=num+9;
417+
}
332418
else
333419
ereport(ERROR,
334420
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
335421
errmsg("invalid input syntax for type double precision: \"%s\"",
336-
num)));
422+
orig_num)));
337423
}
338424

339425
/* skip trailing whitespace */
@@ -345,7 +431,7 @@ float8in(PG_FUNCTION_ARGS)
345431
ereport(ERROR,
346432
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
347433
errmsg("invalid input syntax for type double precision: \"%s\"",
348-
num)));
434+
orig_num)));
349435

350436
if (!isinf(val))
351437
CheckFloat8Val(val);
@@ -362,22 +448,27 @@ float8out(PG_FUNCTION_ARGS)
362448
{
363449
float8num=PG_GETARG_FLOAT8(0);
364450
char*ascii= (char*)palloc(MAXDOUBLEWIDTH+1);
365-
intinfflag;
366-
intndig;
367451

368452
if (isnan(num))
369453
PG_RETURN_CSTRING(strcpy(ascii,"NaN"));
370-
infflag=isinf(num);
371-
if (infflag>0)
372-
PG_RETURN_CSTRING(strcpy(ascii,"Infinity"));
373-
if (infflag<0)
374-
PG_RETURN_CSTRING(strcpy(ascii,"-Infinity"));
375454

376-
ndig=DBL_DIG+extra_float_digits;
377-
if (ndig<1)
378-
ndig=1;
455+
switch (is_infinite(num))
456+
{
457+
case1:
458+
strcpy(ascii,"Infinity");
459+
break;
460+
case-1:
461+
strcpy(ascii,"-Infinity");
462+
break;
463+
default:
464+
{
465+
intndig=DBL_DIG+extra_float_digits;
466+
if (ndig<1)
467+
ndig=1;
379468

380-
sprintf(ascii,"%.*g",ndig,num);
469+
sprintf(ascii,"%.*g",ndig,num);
470+
}
471+
}
381472

382473
PG_RETURN_CSTRING(ascii);
383474
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp