On 10/31/26 05:11, shihao zhong wrote: > Hi Tomas, > > Thanks for your patch.. > > I think your code is right, the subtraction only fails when the result > is too > big for numeric. > > Two small things. > > 1. A NaN boundary gives a NaN distance. The > brin_minmax_multi_distance_numeric > return infinity there. > > 2. In 0004, GiST can call numrange_subdiff with v1 < v2. Overflow > there should give -infinity, not +infinity. >
Thanks. I've pushed the three BRIN fixes. Here's an updated fix for the multirange issue, with the -infinity for (v1 < v2). regards -- Tomas Vondra
From 8ffe6330b8d3491e3f8840968e3f2674d598bae1 Mon Sep 17 00:00:00 2001 From: Tomas Vondra <[email protected]> Date: Fri, 30 Oct 2026 16:58:13 +0100 Subject: [PATCH] Handle overflow when analyzing nummultirange values The numrange_subdiff() function was calculating the difference simply by calling numeric_sub and numeric_float8, but those functions are not overflow-safe. It's possible to insert valid numeric ranges for which the difference overflows either numeric or float8. When that happened, the ANALYZE on the table failed. Fixed by handling overflows in numrange_subdiff() - extreme differences are treated as infinity. Author: Kirill Reshke <[email protected]> Reviewed-by: shihao zhong <[email protected]> Backpatch-through: 14 Discussion: https://postgr.es/m/CALdSSPgBvXz-VSF0p-5k%3D_uFfN38cWrERmm_AC4K67N6MWQhmg%40mail.gmail.com --- src/backend/utils/adt/rangetypes.c | 35 +++++++++++++++---- src/test/regress/expected/multirangetypes.out | 7 ++++ src/test/regress/sql/multirangetypes.sql | 9 +++++ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c index 84d71761c1b..cf1c5d2a364 100644 --- a/src/backend/utils/adt/rangetypes.c +++ b/src/backend/utils/adt/rangetypes.c @@ -44,7 +44,9 @@ #include "port/pg_bitutils.h" #include "utils/builtins.h" #include "utils/date.h" +#include "utils/float.h" #include "utils/lsyscache.h" +#include "utils/numeric.h" #include "utils/rangetypes.h" #include "utils/sortsupport.h" #include "utils/timestamp.h" @@ -1872,15 +1874,36 @@ int8range_subdiff(PG_FUNCTION_ARGS) Datum numrange_subdiff(PG_FUNCTION_ARGS) { - Datum v1 = PG_GETARG_DATUM(0); - Datum v2 = PG_GETARG_DATUM(1); - Datum numresult; + Numeric v1 = PG_GETARG_NUMERIC(0); + Numeric v2 = PG_GETARG_NUMERIC(1); + Numeric numresult; float8 floatresult; + ErrorSaveContext escontext = {T_ErrorSaveContext}; - numresult = DirectFunctionCall2(numeric_sub, v1, v2); + /* + * The difference can exceed numeric's range, or be unrepresentable + * in float8. Neither caller is prepared to handle an error, so + * saturate to infinity (or round to zero) instead. + */ + numresult = numeric_sub_safe(v1, v2, (Node *) &escontext); + if (SOFT_ERROR_OCCURRED(&escontext)) + { + /* The values v1 and v2 may be in arbitrary order. */ + if (DatumGetBool(DirectFunctionCall2(numeric_lt, NumericGetDatum(v1), + NumericGetDatum(v2)))) + floatresult = -get_float8_infinity(); + else + floatresult = get_float8_infinity(); + } + else + { + floatresult = DatumGetFloat8(DirectFunctionCall1( + numeric_float8_no_overflow, NumericGetDatum(numresult))); + pfree(numresult); + } - floatresult = DatumGetFloat8(DirectFunctionCall1(numeric_float8, - numresult)); + PG_FREE_IF_COPY(v1, 0); + PG_FREE_IF_COPY(v2, 1); PG_RETURN_FLOAT8(floatresult); } diff --git a/src/test/regress/expected/multirangetypes.out b/src/test/regress/expected/multirangetypes.out index d47ce4b6d6a..a57f5fa6ae6 100644 --- a/src/test/regress/expected/multirangetypes.out +++ b/src/test/regress/expected/multirangetypes.out @@ -3197,6 +3197,13 @@ ERROR: type "intr_multirange" already exists DETAIL: Failed while creating a multirange type for type "intr". HINT: You can manually specify a multirange type name using the "multirange_type_name" attribute. drop type intr_multirange; +--- +-- Check that numeric overflow during analyze does not make it fail +--- +create table multirange_analyze_test (r nummultirange); +insert into multirange_analyze_test values ('{[1e1000, 2e1000], [-9e131071, 9e131071]}'::nummultirange); +analyze multirange_analyze_test; +drop table multirange_analyze_test; -- -- Test multiple multirange types over the same subtype and manual naming of -- the multirange type. diff --git a/src/test/regress/sql/multirangetypes.sql b/src/test/regress/sql/multirangetypes.sql index cf0fff6fddd..9e7b1f0205d 100644 --- a/src/test/regress/sql/multirangetypes.sql +++ b/src/test/regress/sql/multirangetypes.sql @@ -702,6 +702,15 @@ create type intr_multirange as (x int, y int); create type intr as range(subtype=int); -- should fail drop type intr_multirange; +--- +-- Check that numeric overflow during analyze does not make it fail +--- + +create table multirange_analyze_test (r nummultirange); +insert into multirange_analyze_test values ('{[1e1000, 2e1000], [-9e131071, 9e131071]}'::nummultirange); +analyze multirange_analyze_test; +drop table multirange_analyze_test; + -- -- Test multiple multirange types over the same subtype and manual naming of -- the multirange type. -- 2.55.0
