Commit c318aeed authored by Tom Lane's avatar Tom Lane

Try to be more consistent about accepting denormalized float8 numbers.

On some platforms, strtod() reports ERANGE for a denormalized value (ie,
one that can be represented as distinct from zero, but is too small to have
full precision).  On others, it doesn't.  It seems better to try to accept
these values consistently, so add a test to see if the result value
indicates a true out-of-range condition.  This should be okay per Single
Unix Spec.  On machines where the underlying math isn't IEEE standard, the
behavior for such small numbers may not be very consistent, but then it
wouldn't be anyway.

Marti Raudsepp, after a proposal by Jeroen Vermeulen
parent b2e431a4
...@@ -217,6 +217,8 @@ float4in(PG_FUNCTION_ARGS) ...@@ -217,6 +217,8 @@ float4in(PG_FUNCTION_ARGS)
/* 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 and [-]Infinity, but not all
* platforms support that yet (and some accept them but set ERANGE * platforms support that yet (and some accept them but set ERANGE
...@@ -237,11 +239,21 @@ float4in(PG_FUNCTION_ARGS) ...@@ -237,11 +239,21 @@ float4in(PG_FUNCTION_ARGS)
val = -get_float4_infinity(); val = -get_float4_infinity();
endptr = num + 9; endptr = num + 9;
} }
else if (errno == ERANGE) else if (save_errno == ERANGE)
ereport(ERROR, {
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), /*
errmsg("\"%s\" is out of range for type real", * Some platforms return ERANGE for denormalized numbers (those
orig_num))); * that are not zero, but are too close to zero to have full
* precision). We'd prefer not to throw error for that, so try
* to detect whether it's a "real" out-of-range condition by
* checking to see if the result is zero or huge.
*/
if (val == 0.0 || val >= HUGE_VAL || val <= -HUGE_VAL)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("\"%s\" is out of range for type real",
orig_num)));
}
else else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
...@@ -410,6 +422,8 @@ float8in(PG_FUNCTION_ARGS) ...@@ -410,6 +422,8 @@ float8in(PG_FUNCTION_ARGS)
/* 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 and [-]Infinity, but not all
* platforms support that yet (and some accept them but set ERANGE * platforms support that yet (and some accept them but set ERANGE
...@@ -430,11 +444,21 @@ float8in(PG_FUNCTION_ARGS) ...@@ -430,11 +444,21 @@ float8in(PG_FUNCTION_ARGS)
val = -get_float8_infinity(); val = -get_float8_infinity();
endptr = num + 9; endptr = num + 9;
} }
else if (errno == ERANGE) else if (save_errno == ERANGE)
ereport(ERROR, {
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), /*
errmsg("\"%s\" is out of range for type double precision", * Some platforms return ERANGE for denormalized numbers (those
orig_num))); * that are not zero, but are too close to zero to have full
* precision). We'd prefer not to throw error for that, so try
* to detect whether it's a "real" out-of-range condition by
* checking to see if the result is zero or huge.
*/
if (val == 0.0 || val >= HUGE_VAL || val <= -HUGE_VAL)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("\"%s\" is out of range for type double precision",
orig_num)));
}
else else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment