aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/access/brin/brin_minmax_multi.c33
-rw-r--r--src/test/regress/expected/brin_multi.out29
-rw-r--r--src/test/regress/sql/brin_multi.sql21
3 files changed, 54 insertions, 29 deletions
diff --git a/src/backend/access/brin/brin_minmax_multi.c b/src/backend/access/brin/brin_minmax_multi.c
index 978acb87e27..c045691819c 100644
--- a/src/backend/access/brin/brin_minmax_multi.c
+++ b/src/backend/access/brin/brin_minmax_multi.c
@@ -2154,45 +2154,20 @@ brin_minmax_multi_distance_interval(PG_FUNCTION_ARGS)
Interval *ia = PG_GETARG_INTERVAL_P(0);
Interval *ib = PG_GETARG_INTERVAL_P(1);
- Interval *result;
int64 dayfraction;
int64 days;
- result = (Interval *) palloc(sizeof(Interval));
-
- result->month = ib->month - ia->month;
- /* overflow check copied from int4mi */
- if (!SAMESIGN(ib->month, ia->month) &&
- !SAMESIGN(result->month, ib->month))
- ereport(ERROR,
- (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
- errmsg("interval out of range")));
-
- result->day = ib->day - ia->day;
- if (!SAMESIGN(ib->day, ia->day) &&
- !SAMESIGN(result->day, ib->day))
- ereport(ERROR,
- (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
- errmsg("interval out of range")));
-
- result->time = ib->time - ia->time;
- if (!SAMESIGN(ib->time, ia->time) &&
- !SAMESIGN(result->time, ib->time))
- ereport(ERROR,
- (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
- errmsg("interval out of range")));
-
/*
* 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.
*/
- dayfraction = result->time % USECS_PER_DAY;
- days = result->time / USECS_PER_DAY;
- days += result->month * INT64CONST(30);
- days += result->day;
+ dayfraction = (ib->time % USECS_PER_DAY) - (ia->time % USECS_PER_DAY);
+ days = (ib->time / USECS_PER_DAY) - (ia->time / USECS_PER_DAY);
+ days += (int64) ib->day - (int64) ia->day;
+ days += ((int64) ib->month - (int64) ia->month) * INT64CONST(30);
/* convert to double precision */
delta = (double) days + dayfraction / (double) USECS_PER_DAY;
diff --git a/src/test/regress/expected/brin_multi.out b/src/test/regress/expected/brin_multi.out
index 2155b7bfc38..838d0c7f2be 100644
--- a/src/test/regress/expected/brin_multi.out
+++ b/src/test/regress/expected/brin_multi.out
@@ -558,3 +558,32 @@ SELECT * FROM brin_date_test WHERE a = '1900-01-01'::date;
DROP TABLE brin_date_test;
RESET enable_seqscan;
RESET datestyle;
+-- test handling of overflow for interval values
+CREATE TABLE brin_interval_test(a INTERVAL);
+INSERT INTO brin_interval_test SELECT (i || ' years')::interval FROM generate_series(-178000000, -177999980) s(i);
+INSERT INTO brin_interval_test SELECT (i || ' years')::interval FROM generate_series( 177999980, 178000000) s(i);
+CREATE INDEX ON brin_interval_test USING brin (a interval_minmax_multi_ops) WITH (pages_per_range=1);
+SET enable_seqscan = off;
+EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
+SELECT * FROM brin_interval_test WHERE a = '-30 years'::interval;
+ QUERY PLAN
+-----------------------------------------------------------------------------
+ Bitmap Heap Scan on brin_interval_test (actual rows=0 loops=1)
+ Recheck Cond: (a = '@ 30 years ago'::interval)
+ -> Bitmap Index Scan on brin_interval_test_a_idx (actual rows=0 loops=1)
+ Index Cond: (a = '@ 30 years ago'::interval)
+(4 rows)
+
+EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
+SELECT * FROM brin_interval_test WHERE a = '30 years'::interval;
+ QUERY PLAN
+-----------------------------------------------------------------------------
+ Bitmap Heap Scan on brin_interval_test (actual rows=0 loops=1)
+ Recheck Cond: (a = '@ 30 years'::interval)
+ -> Bitmap Index Scan on brin_interval_test_a_idx (actual rows=0 loops=1)
+ Index Cond: (a = '@ 30 years'::interval)
+(4 rows)
+
+DROP TABLE brin_interval_test;
+RESET enable_seqscan;
+RESET datestyle;
diff --git a/src/test/regress/sql/brin_multi.sql b/src/test/regress/sql/brin_multi.sql
index feb47ae3059..81a4b959f4f 100644
--- a/src/test/regress/sql/brin_multi.sql
+++ b/src/test/regress/sql/brin_multi.sql
@@ -499,3 +499,24 @@ SELECT * FROM brin_date_test WHERE a = '1900-01-01'::date;
DROP TABLE brin_date_test;
RESET enable_seqscan;
RESET datestyle;
+
+-- test handling of overflow for interval values
+CREATE TABLE brin_interval_test(a INTERVAL);
+
+INSERT INTO brin_interval_test SELECT (i || ' years')::interval FROM generate_series(-178000000, -177999980) s(i);
+
+INSERT INTO brin_interval_test SELECT (i || ' years')::interval FROM generate_series( 177999980, 178000000) s(i);
+
+CREATE INDEX ON brin_interval_test USING brin (a interval_minmax_multi_ops) WITH (pages_per_range=1);
+
+SET enable_seqscan = off;
+
+EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
+SELECT * FROM brin_interval_test WHERE a = '-30 years'::interval;
+
+EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
+SELECT * FROM brin_interval_test WHERE a = '30 years'::interval;
+
+DROP TABLE brin_interval_test;
+RESET enable_seqscan;
+RESET datestyle;