aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTomas Vondra <tomas.vondra@postgresql.org>2021-04-04 19:13:26 +0200
committerTomas Vondra <tomas.vondra@postgresql.org>2021-04-04 19:19:51 +0200
commit2b10e0e3c2ca14d732521479123e5d5e2094e143 (patch)
tree4903e8ea7183fb8e75dafa4eb8d25d0e4b2c4989 /src
parent55873a00e3c3349664e7215077dca74ccea08b4d (diff)
downloadpostgresql-2b10e0e3c2ca14d732521479123e5d5e2094e143.tar.gz
postgresql-2b10e0e3c2ca14d732521479123e5d5e2094e143.zip
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
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/brin/brin_minmax_multi.c21
1 files changed, 13 insertions, 8 deletions
diff --git a/src/backend/access/brin/brin_minmax_multi.c b/src/backend/access/brin/brin_minmax_multi.c
index 70109960e83..42bb177290e 100644
--- a/src/backend/access/brin/brin_minmax_multi.c
+++ b/src/backend/access/brin/brin_minmax_multi.c
@@ -2127,6 +2127,9 @@ brin_minmax_multi_distance_interval(PG_FUNCTION_ARGS)
Interval *ib = PG_GETARG_INTERVAL_P(1);
Interval *result;
+ int64 dayfraction;
+ int64 days;
+
result = (Interval *) palloc(sizeof(Interval));
result->month = ib->month - ia->month;
@@ -2152,16 +2155,18 @@ brin_minmax_multi_distance_interval(PG_FUNCTION_ARGS)
errmsg("interval out of range")));
/*
- * We assume months have 31 days - we don't need to be precise, in the
- * worst case we'll build somewhat less efficient ranges.
+ * Delta is (fractional) number of days between the intervals. Assume
+ * 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);
-
- /* convert to microseconds (just like the time part) */
- delta = 24L * 3600L * delta;
+ dayfraction = result->time % USECS_PER_DAY;
+ days = result->time / USECS_PER_DAY;
+ days += result->month * INT64CONST(30);
+ days += result->day;
- /* and add the time part */
- delta += result->time / (float8) 1000000.0;
+ /* convert to double precision */
+ delta = (double) days + dayfraction / (double) USECS_PER_DAY;
Assert(delta >= 0);