aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/float.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/float.c')
-rw-r--r--src/backend/utils/adt/float.c44
1 files changed, 34 insertions, 10 deletions
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 08434dc7ee4..245030f531c 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),