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
This commit is contained in:
Tomas Vondra 2019-11-16 01:17:15 +01:00
parent bc049d0d46
commit 25a9ff6cad
3 changed files with 30 additions and 5 deletions

View File

@ -3931,14 +3931,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 */
@ -4018,6 +4023,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);
}

View File

@ -217,6 +217,18 @@ SELECT stxkind, stxndistinct
{d,f} | {"3, 4": 301, "3, 6": 301, "4, 6": 301, "3, 4, 6": 301}
(1 row)
-- minor improvement, make sure the ctid does not break the matching
EXPLAIN (COSTS off)
SELECT COUNT(*) FROM ndistinct GROUP BY ctid, a, b;
QUERY PLAN
-----------------------------------
GroupAggregate
Group Key: ctid, a, b
-> Sort
Sort Key: ctid, a, b
-> Seq Scan on ndistinct
(5 rows)
-- Hash Aggregate, thanks to estimates improved by the statistic
EXPLAIN (COSTS off)
SELECT COUNT(*) FROM ndistinct GROUP BY a, b;

View File

@ -144,6 +144,10 @@ ANALYZE ndistinct;
SELECT stxkind, stxndistinct
FROM pg_statistic_ext WHERE stxrelid = 'ndistinct'::regclass;
-- minor improvement, make sure the ctid does not break the matching
EXPLAIN (COSTS off)
SELECT COUNT(*) FROM ndistinct GROUP BY ctid, a, b;
-- Hash Aggregate, thanks to estimates improved by the statistic
EXPLAIN (COSTS off)
SELECT COUNT(*) FROM ndistinct GROUP BY a, b;