summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomas Vondra <tomas.vondra@postgresql.org>2019-11-16 01:17:15 +0100
committerTomas Vondra <tomas.vondra@postgresql.org>2019-11-16 01:42:20 +0100
commit0b0f281cc0fe383162b170889e79502e21e6b35a (patch)
tree7914c8137336a94c210fdc0528f1cdfd3ae2eaf1
parent4be69e2ea14d4f00c77a1185e68b7f9235aeb95f (diff)
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
-rw-r--r--src/backend/utils/adt/selfuncs.c19
-rw-r--r--src/test/regress/expected/stats_ext.out12
-rw-r--r--src/test/regress/sql/stats_ext.sql4
3 files changed, 30 insertions, 5 deletions
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index eb0fed49634..443647298eb 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3757,14 +3757,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 */
@@ -3844,6 +3849,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;