Commit 2b10e0e3 authored by Tomas Vondra's avatar Tomas Vondra

Fix BRIN minmax-multi distance for interval type

The distance calculation for interval type was treating months as having
31 days, which is inconsistent with the interval comparator (using 30
days). Due to this it was possible to get negative distance (b-a) when
(a<b), trigerring an assert.

Fixed by adopting the same logic as interval_cmp_value.

Reported-by: Jaime Casanova
Discussion: https://postgr.es/m/CAJKUy5jKH0Xhneau2mNftNPtTy-BVgQfXc8zQkEvRvBHfeUThQ%40mail.gmail.com
parent 55873a00
...@@ -2127,6 +2127,9 @@ brin_minmax_multi_distance_interval(PG_FUNCTION_ARGS) ...@@ -2127,6 +2127,9 @@ brin_minmax_multi_distance_interval(PG_FUNCTION_ARGS)
Interval *ib = PG_GETARG_INTERVAL_P(1); Interval *ib = PG_GETARG_INTERVAL_P(1);
Interval *result; Interval *result;
int64 dayfraction;
int64 days;
result = (Interval *) palloc(sizeof(Interval)); result = (Interval *) palloc(sizeof(Interval));
result->month = ib->month - ia->month; result->month = ib->month - ia->month;
...@@ -2152,16 +2155,18 @@ brin_minmax_multi_distance_interval(PG_FUNCTION_ARGS) ...@@ -2152,16 +2155,18 @@ brin_minmax_multi_distance_interval(PG_FUNCTION_ARGS)
errmsg("interval out of range"))); errmsg("interval out of range")));
/* /*
* We assume months have 31 days - we don't need to be precise, in the * Delta is (fractional) number of days between the intervals. Assume
* worst case we'll build somewhat less efficient ranges. * months have 30 days for consistency with interval_cmp_internal.
* We don't need to be exact, in the worst case we'll build a bit less
* efficient ranges. But we should not contradict interval_cmp.
*/ */
delta = (float8) (result->month * 31 + result->day); dayfraction = result->time % USECS_PER_DAY;
days = result->time / USECS_PER_DAY;
/* convert to microseconds (just like the time part) */ days += result->month * INT64CONST(30);
delta = 24L * 3600L * delta; days += result->day;
/* and add the time part */ /* convert to double precision */
delta += result->time / (float8) 1000000.0; delta = (double) days + dayfraction / (double) USECS_PER_DAY;
Assert(delta >= 0); Assert(delta >= 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment