Re: BUG #16122: segfault pg_detoast_datum (datum=0x0) at fmgr.c:1833 numrange query
Andrey Borodin <[email protected]> Sat, 4 Jan 2020 22:57:57 +0500
| Newsgroups | gmane.comp.db.postgresql.bugs |
|---|---|
| Message-ID | <[email protected]> |
--Apple-Mail=_57099874-8E4A-45AA-980A-0B421AE9BE4C Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > 4 =D1=8F=D0=BD=D0=B2. 2020 =D0=B3., =D0=B2 0:05, Andrey Borodin = <[email protected]> =D0=BD=D0=B0=D0=BF=D0=B8=D1=81=D0=B0=D0=BB(=D0=B0):= >=20 > I believe line should be not like > + for (i =3D upper_index - 1; i >=3D 0; i--) > but rather > + for (i =3D min(upper_index, hist_nvalues - 2); i >=3D 0; i--) >=20 > I will dig into this during this CF. Currently, that's my 2 cents. I think I have a little more correct fix. As far as I understand, we have an array of bin lower bounds hist_lower = with size hist_nvalues. There is a function get_position(..,value, lower, upper), which = calculates relative position of value between lower and upper bound. We call get_position(typcache, lower, &hist_lower[i], &hist_lower[i + = 1]); when i is last bin, i.e. i + 1 =3D=3D hist_nvalues, thus passing = bogus upper to get_position(). PFA possible fix for this. Upper in the code same situation when upper is undefined is treated as = if get_position returned 0. Also, while get_position() is not prepared to bogus upper, but it is = well aware of infinite bounds. We could just add last infinite value to = hist_lower and remove upper_index < hist_nvalues - 1 and i + 1 !=3D = hist_nvalues checks entirely. Best regards, Andrey Borodin. --Apple-Mail=_57099874-8E4A-45AA-980A-0B421AE9BE4C Content-Disposition: attachment; filename=v2-rangetype-stat-crash-from-Andrey.diff Content-Type: application/octet-stream; x-unix-mode=0644; name="v2-rangetype-stat-crash-from-Andrey.diff" Content-Transfer-Encoding: 7bit diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c index a4d7a7ab42..607385bf44 100644 --- a/src/backend/utils/adt/rangetypes_selfuncs.c +++ b/src/backend/utils/adt/rangetypes_selfuncs.c @@ -1063,10 +1063,11 @@ calc_hist_selectivity_contained(TypeCacheEntry *typcache, /* * Subtract from bin_width the portion of this bin that we want to - * ignore. + * ignore, if current bin has finite upper bound. */ - bin_width -= get_position(typcache, lower, &hist_lower[i], - &hist_lower[i + 1]); + if (i + 1 != hist_nvalues) + bin_width -= get_position(typcache, lower, &hist_lower[i], + &hist_lower[i + 1]); if (bin_width < 0.0) bin_width = 0.0; final_bin = true; diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out index 5ed6ae47ec..8427418bb5 100644 --- a/src/test/regress/expected/rangetypes.out +++ b/src/test/regress/expected/rangetypes.out @@ -1434,3 +1434,16 @@ create function table_fail(i anyelement) returns table(i anyelement, r anyrange) as $$ select $1, '[1,10]' $$ language sql; ERROR: cannot determine result data type DETAIL: A function returning "anyrange" must have at least one "anyrange" argument. +-- Corner case with selectivity of range operators, per bug #16122. +CREATE TABLE rangetab (a numrange); +INSERT INTO rangetab +SELECT ('['|| (45.0 - a::numeric/10000000) || ',' || + (45.1 + a::numeric/10000000) || ')')::numrange + FROM generate_series(1,1000) as a; +ANALYZE rangetab; +SELECT a FROM rangetab WHERE a <@ '[89.9999998611111,90.0000001388889)'; + a +--- +(0 rows) + +DROP TABLE rangetab; diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql index 2d0ec8964e..d045cb7650 100644 --- a/src/test/regress/sql/rangetypes.sql +++ b/src/test/regress/sql/rangetypes.sql @@ -510,3 +510,13 @@ create function inoutparam_fail(inout i anyelement, out r anyrange) --should fail create function table_fail(i anyelement) returns table(i anyelement, r anyrange) as $$ select $1, '[1,10]' $$ language sql; + +-- Corner case with selectivity of range operators, per bug #16122. +CREATE TABLE rangetab (a numrange); +INSERT INTO rangetab +SELECT ('['|| (45.0 - a::numeric/10000000) || ',' || + (45.1 + a::numeric/10000000) || ')')::numrange + FROM generate_series(1,1000) as a; +ANALYZE rangetab; +SELECT a FROM rangetab WHERE a <@ '[89.9999998611111,90.0000001388889)'; +DROP TABLE rangetab; --Apple-Mail=_57099874-8E4A-45AA-980A-0B421AE9BE4C--