From 25a9ff6cadbb2099a5f53876d9e29f35a080df43 Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Sat, 16 Nov 2019 01:17:15 +0100 Subject: [PATCH] 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 --- src/backend/utils/adt/selfuncs.c | 19 ++++++++++++++----- src/test/regress/expected/stats_ext.out | 12 ++++++++++++ src/test/regress/sql/stats_ext.sql | 4 ++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 7622edb9dd..126ffad67d 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -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); } diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out index eebf250998..5b7e1d4660 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -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; diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index 43ff77c534..2543dbfffa 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -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;