diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index 08434dc7ee..245030f531 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -217,6 +217,8 @@ float4in(PG_FUNCTION_ARGS) /* did we not see anything that looks like a double? */ if (endptr == num || errno != 0) { + 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 @@ -237,11 +239,21 @@ float4in(PG_FUNCTION_ARGS) val = -get_float4_infinity(); endptr = num + 9; } - else if (errno == ERANGE) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("\"%s\" is out of range for type real", - orig_num))); + else if (save_errno == ERANGE) + { + /* + * Some platforms return ERANGE for denormalized numbers (those + * 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 ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), @@ -410,6 +422,8 @@ float8in(PG_FUNCTION_ARGS) /* did we not see anything that looks like a double? */ if (endptr == num || errno != 0) { + 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 @@ -430,11 +444,21 @@ float8in(PG_FUNCTION_ARGS) val = -get_float8_infinity(); endptr = num + 9; } - else if (errno == ERANGE) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("\"%s\" is out of range for type double precision", - orig_num))); + else if (save_errno == ERANGE) + { + /* + * Some platforms return ERANGE for denormalized numbers (those + * 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 ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),