From 28555a53cb75d00ed0e73f63a6481b4fffcc3dea 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 | 7 +++++++ src/test/regress/sql/stats_ext.sql | 3 +++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index a314ecc4fe..8f9d0211f8 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -3587,14 +3587,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 */ @@ -3674,6 +3679,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 4af61b4119..f827c8f2df 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -216,6 +216,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 diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index 279158ff02..45ad265406 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -157,6 +157,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');