aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2016-03-29 17:21:12 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2016-03-29 17:21:12 -0400
commita898b409f66f956e99694710f537829db02652c0 (patch)
treeda7dda9c1cbad477f74a0b7ae3f776b5c6558daf /src
parente511d878f3bbc205cd260a79740e646eea3c1cd3 (diff)
downloadpostgresql-a898b409f66f956e99694710f537829db02652c0.tar.gz
postgresql-a898b409f66f956e99694710f537829db02652c0.zip
Fix interval_mul() to not produce insane results.
interval_mul() attempts to prevent its calculations from producing silly results, but it forgot that zero times infinity yields NaN in IEEE arithmetic. Hence, a case like '1 second'::interval * 'infinity'::float8 produced a NaN for the months product, which didn't trigger the range check, resulting in bogus and possibly platform-dependent output. This isn't terribly obvious to the naked eye because if you try that exact case, you get "interval out of range" which is what you expect --- but if you look closer, the error is coming from interval_out not interval_mul. interval_mul has allowed a bogus value into the system. Fix by adding isnan tests. Noted while testing Vitaly Burovoy's fix for infinity input to to_timestamp(). Given the lack of field complaints, I doubt this is worth a back-patch.
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/timestamp.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index b9c26b68544..7456808a427 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -3351,14 +3351,16 @@ interval_mul(PG_FUNCTION_ARGS)
result = (Interval *) palloc(sizeof(Interval));
result_double = span->month * factor;
- if (result_double > INT_MAX || result_double < INT_MIN)
+ if (isnan(result_double) ||
+ result_double > INT_MAX || result_double < INT_MIN)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
result->month = (int32) result_double;
result_double = span->day * factor;
- if (result_double > INT_MAX || result_double < INT_MIN)
+ if (isnan(result_double) ||
+ result_double > INT_MAX || result_double < INT_MIN)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));