Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip system attributes when applying mvdistinct stats
authorTomas Vondra <tomas.vondra@postgresql.org>
Sat, 16 Nov 2019 00:17:15 +0000 (01:17 +0100)
committerTomas Vondra <tomas.vondra@postgresql.org>
Sat, 16 Nov 2019 00:58:38 +0000 (01:58 +0100)
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
src/test/regress/expected/stats_ext.out
src/test/regress/sql/stats_ext.sql

index 7622edb9dd4cc52ccc8a26a3f2f0119a8f3cd6ea..126ffad67d0ae3851cc1f1bb4889e86d0ec07cc3 100644 (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);
        }
index eebf250998e1959c03b2d21e17911ced0753d793..5b7e1d466088eeab330822c5c439e0c0e0bd8fbc 100644 (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;
index 43ff77c5344e0f2b07bd5c5585da67e566d1c51f..2543dbfffa70ff800061451f1ff7968c4b75f7dd 100644 (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;