summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTomas Vondra <tomas.vondra@postgresql.org>2023-10-27 17:57:11 +0200
committerTomas Vondra <tomas.vondra@postgresql.org>2023-10-27 18:28:19 +0200
commite7965226d5518796cb2c1a48635ae92b5fe4e6ef (patch)
tree14e74f984efc3e0cf43cfe96be0761f9a3433682 /src
parent0635fe02b426573d62e2389cf90b688c285f072a (diff)
Fix calculation in brin_minmax_multi_distance_date
When calculating the distance between date values, make sure to subtract them in the right order, i.e. (larger - smaller). The distance is used to determine which values to merge, and is expected to be a positive value. The code unfortunately did the subtraction in the opposite order, i.e. (smaller - larger), thus producing negative values and merging values the most distant values first. The resulting index is correct (i.e. produces correct results), but may be significantly less efficient. This affects all minmax-multi indexes on date columns. Backpatch to 14, where minmax-multi indexes were introduced. Reported-by: Ashutosh Bapat Reviewed-by: Ashutosh Bapat, Dean Rasheed Backpatch-through: 14 Discussion: https://postgr.es/m/eef0ea8c-4aaa-8d0d-027f-58b1f35dd170@enterprisedb.com
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/brin/brin_minmax_multi.c7
-rw-r--r--src/test/regress/expected/brin_multi.out20
-rw-r--r--src/test/regress/sql/brin_multi.sql18
3 files changed, 44 insertions, 1 deletions
diff --git a/src/backend/access/brin/brin_minmax_multi.c b/src/backend/access/brin/brin_minmax_multi.c
index 1a7a80d20e6..3bac8c98a00 100644
--- a/src/backend/access/brin/brin_minmax_multi.c
+++ b/src/backend/access/brin/brin_minmax_multi.c
@@ -2075,13 +2075,18 @@ brin_minmax_multi_distance_uuid(PG_FUNCTION_ARGS)
Datum
brin_minmax_multi_distance_date(PG_FUNCTION_ARGS)
{
+ float8 delta = 0;
DateADT dateVal1 = PG_GETARG_DATEADT(0);
DateADT dateVal2 = PG_GETARG_DATEADT(1);
if (DATE_NOT_FINITE(dateVal1) || DATE_NOT_FINITE(dateVal2))
PG_RETURN_FLOAT8(0);
- PG_RETURN_FLOAT8(dateVal1 - dateVal2);
+ delta = (float8) dateVal2 - (float8) dateVal1;
+
+ Assert(delta >= 0);
+
+ PG_RETURN_FLOAT8(delta);
}
/*
diff --git a/src/test/regress/expected/brin_multi.out b/src/test/regress/expected/brin_multi.out
index b6a2ef195d8..ce10147afee 100644
--- a/src/test/regress/expected/brin_multi.out
+++ b/src/test/regress/expected/brin_multi.out
@@ -479,5 +479,25 @@ SELECT '294276-12-01 00:00:01'::timestamptz + (i || ' seconds')::interval
FROM generate_series(1,30) s(i);
CREATE INDEX ON brin_timestamp_test USING brin (a timestamptz_minmax_multi_ops) WITH (pages_per_range=1);
DROP TABLE brin_timestamp_test;
+-- test overflows during CREATE INDEX with extreme date values
+CREATE TABLE brin_date_test(a DATE);
+-- insert values close to date minimum
+INSERT INTO brin_date_test SELECT '4713-01-01 BC'::date + i FROM generate_series(1, 30) s(i);
+-- insert values close to date minimum
+INSERT INTO brin_date_test SELECT '5874897-12-01'::date + i FROM generate_series(1, 30) s(i);
+CREATE INDEX ON brin_date_test USING brin (a date_minmax_multi_ops) WITH (pages_per_range=1);
+SET enable_seqscan = off;
+-- make sure the ranges were built correctly and 2023-01-01 eliminates all
+EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
+SELECT * FROM brin_date_test WHERE a = '2023-01-01'::date;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Bitmap Heap Scan on brin_date_test (actual rows=0 loops=1)
+ Recheck Cond: (a = '2023-01-01'::date)
+ -> Bitmap Index Scan on brin_date_test_a_idx (actual rows=0 loops=1)
+ Index Cond: (a = '2023-01-01'::date)
+(4 rows)
+
+DROP TABLE brin_date_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 95710511ca9..b0dac67f5b0 100644
--- a/src/test/regress/sql/brin_multi.sql
+++ b/src/test/regress/sql/brin_multi.sql
@@ -440,5 +440,23 @@ SELECT '294276-12-01 00:00:01'::timestamptz + (i || ' seconds')::interval
CREATE INDEX ON brin_timestamp_test USING brin (a timestamptz_minmax_multi_ops) WITH (pages_per_range=1);
DROP TABLE brin_timestamp_test;
+-- test overflows during CREATE INDEX with extreme date values
+CREATE TABLE brin_date_test(a DATE);
+
+-- insert values close to date minimum
+INSERT INTO brin_date_test SELECT '4713-01-01 BC'::date + i FROM generate_series(1, 30) s(i);
+
+-- insert values close to date minimum
+INSERT INTO brin_date_test SELECT '5874897-12-01'::date + i FROM generate_series(1, 30) s(i);
+
+CREATE INDEX ON brin_date_test USING brin (a date_minmax_multi_ops) WITH (pages_per_range=1);
+
+SET enable_seqscan = off;
+
+-- make sure the ranges were built correctly and 2023-01-01 eliminates all
+EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
+SELECT * FROM brin_date_test WHERE a = '2023-01-01'::date;
+
+DROP TABLE brin_date_test;
RESET enable_seqscan;
RESET datestyle;