Skip system attributes when applying mvdistinct stats

When estimating number of distinct groups, we failed to ignore system
attributes when matching the group expressions to mvdistinct stats,
causing failures like

  ERROR: negative bitmapset member not allowed

Fix that by simply skipping anything that is not a regular attribute.
Backpatch to PostgreSQL 10, where the extended stats were introduced.

Bug: #16111
Reported-by: Tuomas Leikola
Author: Tomas Vondra
Backpatch-through: 10
Discussion: https://postgr.es/m/16111-687799584c3a7e73@postgresql.org
pull/44/head
Tomas Vondra 6 years ago
parent 76cbfcdf3a
commit d482f7f867
  1. 19
      src/backend/utils/adt/selfuncs.c
  2. 7
      src/test/regress/expected/stats_ext.out
  3. 3
      src/test/regress/sql/stats_ext.sql

@ -3582,14 +3582,19 @@ estimate_multivariate_ndistinct(PlannerInfo *root, RelOptInfo *rel,
foreach(lc, *varinfos)
{
GroupVarInfo *varinfo = (GroupVarInfo *) lfirst(lc);
AttrNumber attnum;
Assert(varinfo->rel == rel);
if (IsA(varinfo->var, Var))
{
attnums = bms_add_member(attnums,
((Var *) varinfo->var)->varattno);
}
if (!IsA(varinfo->var, Var))
continue;
attnum = ((Var *) varinfo->var)->varattno;
if (!AttrNumberIsForUserDefinedAttr(attnum))
continue;
attnums = bms_add_member(attnums, attnum);
}
/* look for the ndistinct statistics matching the most vars */
@ -3669,6 +3674,10 @@ estimate_multivariate_ndistinct(PlannerInfo *root, RelOptInfo *rel,
}
attnum = ((Var *) varinfo->var)->varattno;
if (!AttrNumberIsForUserDefinedAttr(attnum))
continue;
if (!bms_is_member(attnum, matched))
newlist = lappend(newlist, varinfo);
}

@ -233,6 +233,13 @@ SELECT s.stxkind, d.stxdndistinct
{d,f,m} | {"3, 4": 11, "3, 6": 11, "4, 6": 11, "3, 4, 6": 11}
(1 row)
-- minor improvement, make sure the ctid does not break the matching
SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY ctid, a, b');
estimated | actual
-----------+--------
11 | 1000
(1 row)
-- Hash Aggregate, thanks to estimates improved by the statistic
SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, b');
estimated | actual

@ -167,6 +167,9 @@ SELECT s.stxkind, d.stxdndistinct
WHERE s.stxrelid = 'ndistinct'::regclass
AND d.stxoid = s.oid;
-- minor improvement, make sure the ctid does not break the matching
SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY ctid, a, b');
-- Hash Aggregate, thanks to estimates improved by the statistic
SELECT * FROM check_estimated_rows('SELECT COUNT(*) FROM ndistinct GROUP BY a, b');

Loading…
Cancel
Save