8000 Make sure float4in/float8in accept all standard spellings of "infinity". · sqlparser/postgres@de27c29 · GitHub
[go: up one dir, main page]

Skip to content 8000

Commit de27c29

Browse files
committed
Make sure float4in/float8in accept all standard spellings of "infinity".
The C99 and POSIX standards require strtod() to accept all these spellings (case-insensitively): "inf", "+inf", "-inf", "infinity", "+infinity", "-infinity". However, pre-C99 systems might accept only some or none of these, and apparently Windows still doesn't accept "inf". To avoid surprising cross-platform behavioral differences, manually check for each of these spellings if strtod() fails. We were previously handling just "infinity" and "-infinity" that way, but since C99 is most of the world now, it seems likely that applications are expecting all these spellings to work. Per bug #8355 from Basil Peace. It turns out this fix won't actually resolve his problem, because Python isn't being this careful; but that doesn't mean we shouldn't be.
1 parent 1bd148c commit de27c29

File tree

1 file changed

+81
-25
lines changed

1 file changed

+81
-25
lines changed

src/backend/utils/adt/float.c

Lines changed: 81 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,7 @@ is_infinite(double val)
174174

175175

176176
/*
177-
* float4in - converts "num" to float
178-
* restricted syntax:
179-
* {<sp>} [+|-] {digit} [.{digit}] [<exp>]
180-
* where <sp> is a space, digit is 0-9,
181-
* <exp> is "e" or "E" followed by an integer.
177+
* float4in - converts "num" to float4
182178
*/
183179
Datum
184180
float4in(PG_FUNCTION_ARGS)
@@ -195,6 +191,10 @@ float4in(PG_FUNCTION_ARGS)
195191
*/
196192
orig_num = num;
197193

194+
/* skip leading whitespace */
195+
while (*num != '\0' && isspace((unsigned char) *num))
196+
num++;
197+
198198
/*
199199
* Check for an empty-string input to begin with, to avoid the vagaries of
200200
* strtod() on different platforms.
@@ -205,20 +205,23 @@ float4in(PG_FUNCTION_ARGS)
205205
errmsg("invalid input syntax for type real: \"%s\"",
206206
orig_num)));
207207

208-
/* skip leading whitespace */
209-
while (*num != '\0' && isspace((unsigned char) *num))
210-
num++;
211-
212208
errno = 0;
213209
val = strtod(num, &endptr);
214210

215211
/* did we not see anything that looks like a double? */
216212
if (endptr == num || errno != 0)
217213
{
214+
int save_errno = errno;
215+
218216
/*
219-
* C99 requires that strtod() accept NaN and [-]Infinity, but not all
220-
* platforms support that yet (and some accept them but set ERANGE
221-
* anyway...) Therefore, we check for these inputs ourselves.
217+
* C99 requires that strtod() accept NaN, [+-]Infinity, and [+-]Inf,
218+
* but not all platforms support all of these (and some accept them
219+
* but set ERANGE anyway...) Therefore, we check for these inputs
220+
* ourselves if strtod() fails.
221+
*
222+
* Note: C99 also requires hexadecimal input as well as some extended
223+
* forms of NaN, but we consider these forms unportable and don't try
224+
* to support them. You can use 'em if your strtod() takes 'em.
222225
*/
223226
if (pg_strncasecmp(num, "NaN", 3) == 0)
224227
{
@@ -230,12 +233,32 @@ float4in(PG_FUNCTION_ARGS)
230233
val = get_float4_infinity();
231234
endptr = num + 8;
232235
}
236+
else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
237+
{
238+
val = get_float4_infinity();
239+
endptr = num + 9;
240+
}
233241
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
234242
{
235243
val = -get_float4_infinity();
236244
endptr = num + 9;
237245
}
238-
else if (errno == ERANGE)
246+
else if (pg_strncasecmp(num, "inf", 3) == 0)
247+
{
248+
val = get_float4_infinity();
249+
endptr = num + 3;
250+
}
251+
else if (pg_strncasecmp(num, "+inf", 4) == 0)
252+
{
253+
val = get_float4_infinity();
254+
endptr = num + 4;
255+
}
256+
else if (pg_strncasecmp(num, "-inf", 4) == 0)
257+
{
258+
val = -get_float4_infinity();
259+
endptr = num + 4;
260+
}
261+
else if (save_errno == ERANGE)
239262
ereport(ERROR,
240263
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
241264
errmsg("\"%s\" is out of range for type real",
@@ -273,6 +296,11 @@ float4in(PG_FUNCTION_ARGS)
273296
val = get_float4_infinity();
274297
endptr = num + 8;
275298
}
299+
else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
300+
{
301+
val = get_float4_infinity();
302+
endptr = num + 9;
303+
}
276304
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
277305
{
278306
val = -get_float4_infinity();
@@ -368,10 +396,6 @@ float4send(PG_FUNCTION_ARGS)
368396

369397
/*
370398
* float8in - converts "num" to float8
371-
* restricted syntax:
372-
* {<sp>} [+|-] {digit} [.{digit}] [<exp>]
373-
* where <sp> is a space, digit is 0-9,
374-
* <exp> is "e" or "E" followed by an integer.
375399
*/
376400
Datum
377401
float8in(PG_FUNCTION_ARGS)
@@ -388,6 +412,10 @@ float8in(PG_FUNCTION_ARGS)
388412
*/
389413
orig_num = num;
390414

415+
/* skip leading whitespace */
416+
while (*num != '\0' && isspace((unsigned char) *num))
417+
num++;
418+
391419
/*
392420
* Check for an empty-string input to begin with, to avoid the vagaries of
393421
* strtod() on different platforms.
@@ -398,20 +426,23 @@ float8in(PG_FUNCTION_ARGS)
398426
errmsg("invalid input syntax for type double precision: \"%s\"",
399427
orig_num)));
400428

401-
/* skip leading whitespace */
402-
while (*num != '\0' && isspace((unsigned char) *num))
403-
num++;
404-
405429
errno = 0;
406430
val = strtod(num, &endptr);
407431

408432
/* did we not see anything that looks like a double? */
409433
if (endptr == num || errno != 0)
410434
{
435+
int save_errno = errno;
436+
411437
/*
412-
* C99 requires that strtod() accept NaN and [-]Infinity, but not all
413-
* platforms support that yet (and some accept them but set ERANGE
414-
* anyway...) Therefore, we check for these inputs ourselves.
438+
* C99 requires that strtod() accept NaN, [+-]Infinity, and [+-]Inf,
439+
* but not all platforms support all of these (and some accept them
440+
* but set ERANGE anyway...) Therefore, we check for these inputs
441+
* ourselves if strtod() fails.
442+
*
443+
* Note: C99 also requires hexadecimal input as well as some extended
444+
* forms of NaN, but we consider these forms unportable and don't try
445+
* to support them. You can use 'em if your strtod() takes 'em.
415446
*/
416447
if (pg_strncasecmp(num, "NaN", 3) == 0)
417448
{
@@ -423,12 +454,32 @@ float8in(PG_FUNCTION_ARGS)
423454
val = get_float8_infinity();
424455
endptr = num + 8;
425456
}
457+
else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
458+
{
459+
val = get_float8_infinity();
460+
endptr = num + 9;
461+
}
426462
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
427463
{
428464
val = -get_float8_infinity();
429465
endptr = num + 9;
430466
}
431-
else if (errno == ERANGE)
467+
else if (pg_strncasecmp(num, "inf", 3) == 0)
468+
{
469+
val = get_float8_infinity();
470+
endptr = num + 3;
471+
}
472+
else if (pg_strncasecmp(num, "+inf", 4) == 0)
473+
{
474+
val = get_float8_infinity();
475+
endptr = num + 4;
476+
}
477+
else if (pg_strncasecmp(num, "-inf", 4) == 0)
478+
{
479+
val = -get_float8_infinity();
480+
endptr = num + 4;
481+
}
482+
else if (save_errno == ERANGE)
432483
ereport(ERROR,
433484
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
434485
errmsg("\"%s\" is out of range for type double precision",
@@ -466,6 +517,11 @@ float8in(PG_FUNCTION_ARGS)
466517
val = get_float8_infinity();
467518
endptr = num + 8;
468519
}
520+
else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
521+
{
522+
val = get_float8_infinity();
523+
endptr = num + 9;
524+
}
469525
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
470526
{
471527
val = -get_float8_infinity();

0 commit comments

Comments
 (0)
0