1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-01 14:21:49 +03:00

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  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.
This commit is contained in:
Tom Lane 2013-08-03 12:39:51 -04:00
parent 69fdc9577b
commit b5a20ab3e0

@ -176,11 +176,7 @@ is_infinite(double val)
/*
* float4in - converts "num" to float
* restricted syntax:
* {<sp>} [+|-] {digit} [.{digit}] [<exp>]
* where <sp> is a space, digit is 0-9,
* <exp> is "e" or "E" followed by an integer.
* float4in - converts "num" to float4
*/
Datum
float4in(PG_FUNCTION_ARGS)
@ -197,6 +193,10 @@ float4in(PG_FUNCTION_ARGS)
*/
orig_num = num;
/* skip leading whitespace */
while (*num != '\0' && isspace((unsigned char) *num))
num++;
/*
* Check for an empty-string input to begin with, to avoid the vagaries of
* strtod() on different platforms.
@ -207,10 +207,6 @@ float4in(PG_FUNCTION_ARGS)
errmsg("invalid input syntax for type real: \"%s\"",
orig_num)));
/* skip leading whitespace */
while (*num != '\0' && isspace((unsigned char) *num))
num++;
errno = 0;
val = strtod(num, &endptr);
@ -220,9 +216,14 @@ float4in(PG_FUNCTION_ARGS)
int save_errno = errno;
/*
* C99 requires that strtod() accept NaN and [-]Infinity, but not all
* platforms support that yet (and some accept them but set ERANGE
* anyway...) Therefore, we check for these inputs ourselves.
* C99 requires that strtod() accept NaN, [+-]Infinity, and [+-]Inf,
* but not all platforms support all of these (and some accept them
* but set ERANGE anyway...) Therefore, we check for these inputs
* ourselves if strtod() fails.
*
* Note: C99 also requires hexadecimal input as well as some extended
* forms of NaN, but we consider these forms unportable and don't try
* to support them. You can use 'em if your strtod() takes 'em.
*/
if (pg_strncasecmp(num, "NaN", 3) == 0)
{
@ -234,11 +235,31 @@ float4in(PG_FUNCTION_ARGS)
val = get_float4_infinity();
endptr = num + 8;
}
else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
{
val = get_float4_infinity();
endptr = num + 9;
}
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
{
val = -get_float4_infinity();
endptr = num + 9;
}
else if (pg_strncasecmp(num, "inf", 3) == 0)
{
val = get_float4_infinity();
endptr = num + 3;
}
else if (pg_strncasecmp(num, "+inf", 4) == 0)
{
val = get_float4_infinity();
endptr = num + 4;
}
else if (pg_strncasecmp(num, "-inf", 4) == 0)
{
val = -get_float4_infinity();
endptr = num + 4;
}
else if (save_errno == ERANGE)
{
/*
@ -287,6 +308,11 @@ float4in(PG_FUNCTION_ARGS)
val = get_float4_infinity();
endptr = num + 8;
}
else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
{
val = get_float4_infinity();
endptr = num + 9;
}
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
{
val = -get_float4_infinity();
@ -382,10 +408,6 @@ float4send(PG_FUNCTION_ARGS)
/*
* float8in - converts "num" to float8
* restricted syntax:
* {<sp>} [+|-] {digit} [.{digit}] [<exp>]
* where <sp> is a space, digit is 0-9,
* <exp> is "e" or "E" followed by an integer.
*/
Datum
float8in(PG_FUNCTION_ARGS)
@ -402,6 +424,10 @@ float8in(PG_FUNCTION_ARGS)
*/
orig_num = num;
/* skip leading whitespace */
while (*num != '\0' && isspace((unsigned char) *num))
num++;
/*
* Check for an empty-string input to begin with, to avoid the vagaries of
* strtod() on different platforms.
@ -412,10 +438,6 @@ float8in(PG_FUNCTION_ARGS)
errmsg("invalid input syntax for type double precision: \"%s\"",
orig_num)));
/* skip leading whitespace */
while (*num != '\0' && isspace((unsigned char) *num))
num++;
errno = 0;
val = strtod(num, &endptr);
@ -425,9 +447,14 @@ float8in(PG_FUNCTION_ARGS)
int save_errno = errno;
/*
* C99 requires that strtod() accept NaN and [-]Infinity, but not all
* platforms support that yet (and some accept them but set ERANGE
* anyway...) Therefore, we check for these inputs ourselves.
* C99 requires that strtod() accept NaN, [+-]Infinity, and [+-]Inf,
* but not all platforms support all of these (and some accept them
* but set ERANGE anyway...) Therefore, we check for these inputs
* ourselves if strtod() fails.
*
* Note: C99 also requires hexadecimal input as well as some extended
* forms of NaN, but we consider these forms unportable and don't try
* to support them. You can use 'em if your strtod() takes 'em.
*/
if (pg_strncasecmp(num, "NaN", 3) == 0)
{
@ -439,11 +466,31 @@ float8in(PG_FUNCTION_ARGS)
val = get_float8_infinity();
endptr = num + 8;
}
else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
{
val = get_float8_infinity();
endptr = num + 9;
}
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
{
val = -get_float8_infinity();
endptr = num + 9;
}
else if (pg_strncasecmp(num, "inf", 3) == 0)
{
val = get_float8_infinity();
endptr = num + 3;
}
else if (pg_strncasecmp(num, "+inf", 4) == 0)
{
val = get_float8_infinity();
endptr = num + 4;
}
else if (pg_strncasecmp(num, "-inf", 4) == 0)
{
val = -get_float8_infinity();
endptr = num + 4;
}
else if (save_errno == ERANGE)
{
/*
@ -492,6 +539,11 @@ float8in(PG_FUNCTION_ARGS)
val = get_float8_infinity();
endptr = num + 8;
}
else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
{
val = get_float8_infinity();
endptr = num + 9;
}
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
{
val = -get_float8_infinity();