]> granicus.if.org Git - postgresql/commitdiff
Fix interval_mul() to not produce insane results.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 29 Mar 2016 21:21:12 +0000 (17:21 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 29 Mar 2016 21:21:12 +0000 (17:21 -0400)
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.

src/backend/utils/adt/timestamp.c

index b9c26b68544de0aca2c04e8b9adb56c6ab6e3f23..7456808a427b115a321595a466fa22a548d1afbe 100644 (file)
@@ -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")));