This is an automated email from the ASF dual-hosted git repository.

tuhaihe pushed a commit to branch REL_2_STABLE
in repository https://gitbox.apache.org/repos/asf/cloudberry.git

commit 4dc519e2e9ab81f9304b07f7a7dceb7cb41bc08e
Author: Tomas Vondra <[email protected]>
AuthorDate: Fri Oct 27 17:56:27 2023 +0200

    Fix overflow when calculating timestamp distance in BRIN
    
    When calculating distances for timestamp values for BRIN minmax-multi
    indexes, we need to be careful about overflows for extreme values. If
    the value overflows into a negative value, the index may be inefficient.
    
    The new regression test checks this for the timestamp type by adding a
    table with enough values to force range compaction/merging. The values
    are close to min/max, which means a risk of overflow.
    
    Fixed by converting the int64 values to double first, before calculating
    the distance. This prevents the overflow. We may lose some precision, of
    course, but that's good enough. In the worst case we build a slightly
    less efficient index, but for large distances this won't matter.
    
    This only affects minmax-multi indexes on timestamp columns, with ranges
    containing values sufficiently distant to cause an overflow. That seems
    like a fairly rare case in practice.
    
    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/[email protected]
    (cherry picked from commit 31c67145ce49103710cb37096ee8eaf368098845)
---
 src/backend/access/brin/brin_minmax_multi.c |  2 +-
 src/test/regress/expected/brin_multi.out    | 15 +++++++++++++++
 src/test/regress/sql/brin_multi.sql         | 21 +++++++++++++++++++++
 3 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/src/backend/access/brin/brin_minmax_multi.c 
b/src/backend/access/brin/brin_minmax_multi.c
index b4e50937609..270fe7a4baf 100644
--- a/src/backend/access/brin/brin_minmax_multi.c
+++ b/src/backend/access/brin/brin_minmax_multi.c
@@ -2138,7 +2138,7 @@ brin_minmax_multi_distance_timestamp(PG_FUNCTION_ARGS)
        if (TIMESTAMP_NOT_FINITE(dt1) || TIMESTAMP_NOT_FINITE(dt2))
                PG_RETURN_FLOAT8(0);
 
-       delta = dt2 - dt1;
+       delta = (float8) dt2 - (float8) dt1;
 
        Assert(delta >= 0);
 
diff --git a/src/test/regress/expected/brin_multi.out 
b/src/test/regress/expected/brin_multi.out
index 677fb45f1fd..e24935298bc 100644
--- a/src/test/regress/expected/brin_multi.out
+++ b/src/test/regress/expected/brin_multi.out
@@ -477,3 +477,18 @@ EXPLAIN (COSTS OFF) SELECT * FROM brin_test_multi WHERE b 
= 1;
  Optimizer: Postgres query optimizer
 (4 rows)
 
+-- test overflows during CREATE INDEX with extreme timestamp values
+CREATE TABLE brin_timestamp_test(a TIMESTAMPTZ);
+SET datestyle TO iso;
+-- values close to timetamp minimum
+INSERT INTO brin_timestamp_test
+SELECT '4713-01-01 00:00:01 BC'::timestamptz + (i || ' seconds')::interval
+  FROM generate_series(1,30) s(i);
+-- values close to timetamp maximum
+INSERT INTO brin_timestamp_test
+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;
+RESET enable_seqscan;
+RESET datestyle;
diff --git a/src/test/regress/sql/brin_multi.sql 
b/src/test/regress/sql/brin_multi.sql
index 327a4215bf9..06ed60b3dd0 100644
--- a/src/test/regress/sql/brin_multi.sql
+++ b/src/test/regress/sql/brin_multi.sql
@@ -424,3 +424,24 @@ VACUUM ANALYZE brin_test_multi;
 EXPLAIN (COSTS OFF) SELECT * FROM brin_test_multi WHERE a = 1;
 -- Ensure brin index is not used when values are not correlated
 EXPLAIN (COSTS OFF) SELECT * FROM brin_test_multi WHERE b = 1;
+
+-- test overflows during CREATE INDEX with extreme timestamp values
+CREATE TABLE brin_timestamp_test(a TIMESTAMPTZ);
+
+SET datestyle TO iso;
+
+-- values close to timetamp minimum
+INSERT INTO brin_timestamp_test
+SELECT '4713-01-01 00:00:01 BC'::timestamptz + (i || ' seconds')::interval
+  FROM generate_series(1,30) s(i);
+
+-- values close to timetamp maximum
+INSERT INTO brin_timestamp_test
+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;
+
+RESET enable_seqscan;
+RESET datestyle;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to