Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c318aee

Browse files
committed
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
1 parent b2e431a commit c318aee

File tree

1 file changed

+34
-10
lines changed

1 file changed

+34
-10
lines changed

src/backend/utils/adt/float.c

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ float4in(PG_FUNCTION_ARGS)
217217
/* did we not see anything that looks like a double? */
218218
if (endptr == num || errno != 0)
219219
{
220+
int save_errno = errno;
221+
220222
/*
221223
* C99 requires that strtod() accept NaN and [-]Infinity, but not all
222224
* platforms support that yet (and some accept them but set ERANGE
@@ -237,11 +239,21 @@ float4in(PG_FUNCTION_ARGS)
237239
val = -get_float4_infinity();
238240
endptr = num + 9;
239241
}
240-
else if (errno == ERANGE)
241-
ereport(ERROR,
242-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
243-
errmsg("\"%s\" is out of range for type real",
244-
orig_num)));
242+
else if (save_errno == ERANGE)
243+
{
244+
/*
245+
* Some platforms return ERANGE for denormalized numbers (those
246+
* that are not zero, but are too close to zero to have full
247+
* precision). We'd prefer not to throw error for that, so try
248+
* to detect whether it's a "real" out-of-range condition by
249+
* checking to see if the result is zero or huge.
250+
*/
251+
if (val == 0.0 || val >= HUGE_VAL || val <= -HUGE_VAL)
252+
ereport(ERROR,
253+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
254+
errmsg("\"%s\" is out of range for type real",
255+
orig_num)));
256+
}
245257
else
246258
ereport(ERROR,
247259
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
@@ -410,6 +422,8 @@ float8in(PG_FUNCTION_ARGS)
410422
/* did we not see anything that looks like a double? */
411423
if (endptr == num || errno != 0)
412424
{
425+
int save_errno = errno;
426+
413427
/*
414428
* C99 requires that strtod() accept NaN and [-]Infinity, but not all
415429
* platforms support that yet (and some accept them but set ERANGE
@@ -430,11 +444,21 @@ float8in(PG_FUNCTION_ARGS)
430444
val = -get_float8_infinity();
431445
endptr = num + 9;
432446
}
433-
else if (errno == ERANGE)
434-
ereport(ERROR,
435-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
436-
errmsg("\"%s\" is out of range for type double precision",
437-
orig_num)));
447+
else if (save_errno == ERANGE)
448+
{
449+
/*
450+
* Some platforms return ERANGE for denormalized numbers (those
451+
* that are not zero, but are too close to zero to have full
452+
* precision). We'd prefer not to throw error for that, so try
453+
* to detect whether it's a "real" out-of-range condition by
454+
* checking to see if the result is zero or huge.
455+
*/
456+
if (val == 0.0 || val >= HUGE_VAL || val <= -HUGE_VAL)
457+
ereport(ERROR,
458+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
459+
errmsg("\"%s\" is out of range for type double precision",
460+
orig_num)));
461+
}
438462
else
439463
ereport(ERROR,
440464
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),

0 commit comments

Comments
 (0)