mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +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 #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.
This commit is contained in:
@ -174,11 +174,7 @@ is_infinite(double val)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* float4in - converts "num" to float
|
* float4in - converts "num" to float4
|
||||||
* 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
|
Datum
|
||||||
float4in(PG_FUNCTION_ARGS)
|
float4in(PG_FUNCTION_ARGS)
|
||||||
@ -195,6 +191,10 @@ float4in(PG_FUNCTION_ARGS)
|
|||||||
*/
|
*/
|
||||||
orig_num = num;
|
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
|
* Check for an empty-string input to begin with, to avoid the vagaries of
|
||||||
* strtod() on different platforms.
|
* strtod() on different platforms.
|
||||||
@ -205,20 +205,23 @@ float4in(PG_FUNCTION_ARGS)
|
|||||||
errmsg("invalid input syntax for type real: \"%s\"",
|
errmsg("invalid input syntax for type real: \"%s\"",
|
||||||
orig_num)));
|
orig_num)));
|
||||||
|
|
||||||
/* skip leading whitespace */
|
|
||||||
while (*num != '\0' && isspace((unsigned char) *num))
|
|
||||||
num++;
|
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
val = strtod(num, &endptr);
|
val = strtod(num, &endptr);
|
||||||
|
|
||||||
/* did we not see anything that looks like a double? */
|
/* did we not see anything that looks like a double? */
|
||||||
if (endptr == num || errno != 0)
|
if (endptr == num || errno != 0)
|
||||||
{
|
{
|
||||||
|
int save_errno = errno;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* C99 requires that strtod() accept NaN and [-]Infinity, but not all
|
* C99 requires that strtod() accept NaN, [+-]Infinity, and [+-]Inf,
|
||||||
* platforms support that yet (and some accept them but set ERANGE
|
* but not all platforms support all of these (and some accept them
|
||||||
* anyway...) Therefore, we check for these inputs ourselves.
|
* 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)
|
if (pg_strncasecmp(num, "NaN", 3) == 0)
|
||||||
{
|
{
|
||||||
@ -230,12 +233,32 @@ float4in(PG_FUNCTION_ARGS)
|
|||||||
val = get_float4_infinity();
|
val = get_float4_infinity();
|
||||||
endptr = num + 8;
|
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)
|
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
|
||||||
{
|
{
|
||||||
val = -get_float4_infinity();
|
val = -get_float4_infinity();
|
||||||
endptr = num + 9;
|
endptr = num + 9;
|
||||||
}
|
}
|
||||||
else if (errno == ERANGE)
|
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)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||||
errmsg("\"%s\" is out of range for type real",
|
errmsg("\"%s\" is out of range for type real",
|
||||||
@ -273,6 +296,11 @@ float4in(PG_FUNCTION_ARGS)
|
|||||||
val = get_float4_infinity();
|
val = get_float4_infinity();
|
||||||
endptr = num + 8;
|
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)
|
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
|
||||||
{
|
{
|
||||||
val = -get_float4_infinity();
|
val = -get_float4_infinity();
|
||||||
@ -368,10 +396,6 @@ float4send(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* float8in - converts "num" to float8
|
* 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
|
Datum
|
||||||
float8in(PG_FUNCTION_ARGS)
|
float8in(PG_FUNCTION_ARGS)
|
||||||
@ -388,6 +412,10 @@ float8in(PG_FUNCTION_ARGS)
|
|||||||
*/
|
*/
|
||||||
orig_num = num;
|
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
|
* Check for an empty-string input to begin with, to avoid the vagaries of
|
||||||
* strtod() on different platforms.
|
* strtod() on different platforms.
|
||||||
@ -398,20 +426,23 @@ float8in(PG_FUNCTION_ARGS)
|
|||||||
errmsg("invalid input syntax for type double precision: \"%s\"",
|
errmsg("invalid input syntax for type double precision: \"%s\"",
|
||||||
orig_num)));
|
orig_num)));
|
||||||
|
|
||||||
/* skip leading whitespace */
|
|
||||||
while (*num != '\0' && isspace((unsigned char) *num))
|
|
||||||
num++;
|
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
val = strtod(num, &endptr);
|
val = strtod(num, &endptr);
|
||||||
|
|
||||||
/* did we not see anything that looks like a double? */
|
/* did we not see anything that looks like a double? */
|
||||||
if (endptr == num || errno != 0)
|
if (endptr == num || errno != 0)
|
||||||
{
|
{
|
||||||
|
int save_errno = errno;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* C99 requires that strtod() accept NaN and [-]Infinity, but not all
|
* C99 requires that strtod() accept NaN, [+-]Infinity, and [+-]Inf,
|
||||||
* platforms support that yet (and some accept them but set ERANGE
|
* but not all platforms support all of these (and some accept them
|
||||||
* anyway...) Therefore, we check for these inputs ourselves.
|
* 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)
|
if (pg_strncasecmp(num, "NaN", 3) == 0)
|
||||||
{
|
{
|
||||||
@ -423,12 +454,32 @@ float8in(PG_FUNCTION_ARGS)
|
|||||||
val = get_float8_infinity();
|
val = get_float8_infinity();
|
||||||
endptr = num + 8;
|
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)
|
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
|
||||||
{
|
{
|
||||||
val = -get_float8_infinity();
|
val = -get_float8_infinity();
|
||||||
endptr = num + 9;
|
endptr = num + 9;
|
||||||
}
|
}
|
||||||
else if (errno == ERANGE)
|
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)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||||
errmsg("\"%s\" is out of range for type double precision",
|
errmsg("\"%s\" is out of range for type double precision",
|
||||||
@ -466,6 +517,11 @@ float8in(PG_FUNCTION_ARGS)
|
|||||||
val = get_float8_infinity();
|
val = get_float8_infinity();
|
||||||
endptr = num + 8;
|
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)
|
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
|
||||||
{
|
{
|
||||||
val = -get_float8_infinity();
|
val = -get_float8_infinity();
|
||||||
|
Reference in New Issue
Block a user