postgres.git / summary / log / commit / refs

commit    25a9ff6cadbb2099a5f53876d9e29f35a080df43
Author:   Tomas Vondra <tomas.vondra@postgresql.org>
Date:     Sat Nov 16 00:17:15 2019 +0000
First released in: 13.0, 10.12, 11.7, 12.2

    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 7622edb9dd4..126ffad67d0 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 eebf250998e..5b7e1d46608 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 43ff77c5344..2543dbfffa7 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; [parent: bc049d0d460a]