</entry>
      </row>
 
+     <row>
+      <entry><structfield>relallvisible</structfield></entry>
+      <entry><type>int4</type></entry>
+      <entry></entry>
+      <entry>
+       Number of pages that are marked all-visible in the table's
+       visibility map.  This is only an estimate used by the
+       planner.  It is updated by <command>VACUUM</command>,
+       <command>ANALYZE</command>, and a few DDL commands such as
+       <command>CREATE INDEX</command>.
+      </entry>
+     </row>
+
      <row>
       <entry><structfield>reltoastrelid</structfield></entry>
       <entry><type>oid</type></entry>
 
    IndexBuildResult *result;
    BlockNumber relpages;
    double      reltuples;
+   double      allvisfrac;
    uint32      num_buckets;
    HashBuildState buildstate;
 
             RelationGetRelationName(index));
 
    /* Estimate the number of rows currently present in the table */
-   estimate_rel_size(heap, NULL, &relpages, &reltuples);
+   estimate_rel_size(heap, NULL, &relpages, &reltuples, &allvisfrac);
 
    /* Initialize the hash index metadata page and initial buckets */
    num_buckets = _hash_metapinit(index, reltuples, MAIN_FORKNUM);
 
  *     visibilitymap_pin_ok - check whether correct map page is already pinned
  *     visibilitymap_set    - set a bit in a previously pinned page
  *     visibilitymap_test   - test if a bit is set
+ *     visibilitymap_count  - count number of bits set in visibility map
+ *     visibilitymap_truncate  - truncate the visibility map
  *
  * NOTES
  *
 #define HEAPBLK_TO_MAPBYTE(x) (((x) % HEAPBLOCKS_PER_PAGE) / HEAPBLOCKS_PER_BYTE)
 #define HEAPBLK_TO_MAPBIT(x) ((x) % HEAPBLOCKS_PER_BYTE)
 
+/* table for fast counting of set bits */
+static const uint8 number_of_ones[256] = {
+   0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+   1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+   1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+   2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+   1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+   2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+   2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+   3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+   1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+   2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+   2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+   3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+   2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+   3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+   3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+   4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
 /* prototypes for internal routines */
 static Buffer vm_readbuf(Relation rel, BlockNumber blkno, bool extend);
 static void vm_extend(Relation rel, BlockNumber nvmblocks);
    return result;
 }
 
+/*
+ * visibilitymap_count  - count number of bits set in visibility map
+ *
+ * Note: we ignore the possibility of race conditions when the table is being
+ * extended concurrently with the call.  New pages added to the table aren't
+ * going to be marked all-visible, so they won't affect the result.
+ */
+BlockNumber
+visibilitymap_count(Relation rel)
+{
+   BlockNumber result = 0;
+   BlockNumber mapBlock;
+
+   for (mapBlock = 0; ; mapBlock++)
+   {
+       Buffer      mapBuffer;
+       unsigned char *map;
+       int         i;
+
+       /*
+        * Read till we fall off the end of the map.  We assume that any
+        * extra bytes in the last page are zeroed, so we don't bother
+        * excluding them from the count.
+        */
+       mapBuffer = vm_readbuf(rel, mapBlock, false);
+       if (!BufferIsValid(mapBuffer))
+           break;
+
+       /*
+        * We choose not to lock the page, since the result is going to be
+        * immediately stale anyway if anyone is concurrently setting or
+        * clearing bits, and we only really need an approximate value.
+        */
+       map = (unsigned char *) PageGetContents(BufferGetPage(mapBuffer));
+
+       for (i = 0; i < MAPSIZE; i++)
+       {
+           result += number_of_ones[map[i]];
+       }
+
+       ReleaseBuffer(mapBuffer);
+   }
+
+   return result;
+}
+
 /*
  * visibilitymap_truncate - truncate the visibility map
  *
 
    values[Anum_pg_class_reltablespace - 1] = ObjectIdGetDatum(rd_rel->reltablespace);
    values[Anum_pg_class_relpages - 1] = Int32GetDatum(rd_rel->relpages);
    values[Anum_pg_class_reltuples - 1] = Float4GetDatum(rd_rel->reltuples);
+   values[Anum_pg_class_relallvisible - 1] = Int32GetDatum(rd_rel->relallvisible);
    values[Anum_pg_class_reltoastrelid - 1] = ObjectIdGetDatum(rd_rel->reltoastrelid);
    values[Anum_pg_class_reltoastidxid - 1] = ObjectIdGetDatum(rd_rel->reltoastidxid);
    values[Anum_pg_class_relhasindex - 1] = BoolGetDatum(rd_rel->relhasindex);
            /* The relation is real, but as yet empty */
            new_rel_reltup->relpages = 0;
            new_rel_reltup->reltuples = 0;
+           new_rel_reltup->relallvisible = 0;
            break;
        case RELKIND_SEQUENCE:
            /* Sequences always have a known size */
            new_rel_reltup->relpages = 1;
            new_rel_reltup->reltuples = 1;
+           new_rel_reltup->relallvisible = 0;
            break;
        default:
            /* Views, etc, have no disk storage */
            new_rel_reltup->relpages = 0;
            new_rel_reltup->reltuples = 0;
+           new_rel_reltup->relallvisible = 0;
            break;
    }
 
 
 #include "access/relscan.h"
 #include "access/sysattr.h"
 #include "access/transam.h"
+#include "access/visibilitymap.h"
 #include "access/xact.h"
 #include "bootstrap/bootstrap.h"
 #include "catalog/catalog.h"
                           true,
                           isprimary,
                           InvalidOid,
-                          heapRelation->rd_rel->reltuples);
+                          -1.0);
        /* Make the above update visible */
        CommandCounterIncrement();
    }
                           true,
                           true,
                           InvalidOid,
-                          heapRelation->rd_rel->reltuples);
+                          -1.0);
 
    /*
     * If needed, mark the index as primary and/or deferred in pg_index.
  * isprimary: if true, set relhaspkey true; else no change
  * reltoastidxid: if not InvalidOid, set reltoastidxid to this value;
  *     else no change
- * reltuples: set reltuples to this value
+ * reltuples: if >= 0, set reltuples to this value; else no change
  *
- * relpages is also updated (using RelationGetNumberOfBlocks()).
+ * If reltuples >= 0, relpages and relallvisible are also updated (using
+ * RelationGetNumberOfBlocks() and visibilitymap_count()).
  *
  * NOTE: an important side-effect of this operation is that an SI invalidation
  * message is sent out to all backends --- including me --- causing relcache
                   bool hasindex, bool isprimary,
                   Oid reltoastidxid, double reltuples)
 {
-   BlockNumber relpages = RelationGetNumberOfBlocks(rel);
    Oid         relid = RelationGetRelid(rel);
    Relation    pg_class;
    HeapTuple   tuple;
     * It is safe to use a non-transactional update even though our
     * transaction could still fail before committing.  Setting relhasindex
     * true is safe even if there are no indexes (VACUUM will eventually fix
-    * it), likewise for relhaspkey.  And of course the relpages and reltuples
-    * counts are correct (or at least more so than the old values)
-    * regardless.
+    * it), likewise for relhaspkey.  And of course the new relpages and
+    * reltuples counts are correct regardless.  However, we don't want to
+    * change relpages (or relallvisible) if the caller isn't providing an
+    * updated reltuples count, because that would bollix the
+    * reltuples/relpages ratio which is what's really important.
     */
 
    pg_class = heap_open(RelationRelationId, RowExclusiveLock);
            dirty = true;
        }
    }
-   if (rd_rel->reltuples != (float4) reltuples)
-   {
-       rd_rel->reltuples = (float4) reltuples;
-       dirty = true;
-   }
-   if (rd_rel->relpages != (int32) relpages)
+
+   if (reltuples >= 0)
    {
-       rd_rel->relpages = (int32) relpages;
-       dirty = true;
+       BlockNumber relpages = RelationGetNumberOfBlocks(rel);
+       BlockNumber relallvisible;
+
+       if (rd_rel->relkind != RELKIND_INDEX)
+           relallvisible = visibilitymap_count(rel);
+       else                    /* don't bother for indexes */
+           relallvisible = 0;
+
+       if (rd_rel->relpages != (int32) relpages)
+       {
+           rd_rel->relpages = (int32) relpages;
+           dirty = true;
+       }
+       if (rd_rel->reltuples != (float4) reltuples)
+       {
+           rd_rel->reltuples = (float4) reltuples;
+           dirty = true;
+       }
+       if (rd_rel->relallvisible != (int32) relallvisible)
+       {
+           rd_rel->relallvisible = (int32) relallvisible;
+           dirty = true;
+       }
    }
 
    /*
 
 #include "access/transam.h"
 #include "access/tupconvert.h"
 #include "access/tuptoaster.h"
+#include "access/visibilitymap.h"
 #include "access/xact.h"
 #include "catalog/index.h"
 #include "catalog/indexing.h"
    if (!inh)
        vac_update_relstats(onerel,
                            RelationGetNumberOfBlocks(onerel),
-                           totalrows, hasindex, InvalidTransactionId);
+                           totalrows,
+                           visibilitymap_count(onerel),
+                           hasindex,
+                           InvalidTransactionId);
 
    /*
     * Same for indexes. Vacuum always scans all indexes, so if we're part of
            totalindexrows = ceil(thisdata->tupleFract * totalrows);
            vac_update_relstats(Irel[ind],
                                RelationGetNumberOfBlocks(Irel[ind]),
-                               totalindexrows, false, InvalidTransactionId);
+                               totalindexrows,
+                               0,
+                               false,
+                               InvalidTransactionId);
        }
    }
 
 
    {
        int4        swap_pages;
        float4      swap_tuples;
+       int4        swap_allvisible;
 
        swap_pages = relform1->relpages;
        relform1->relpages = relform2->relpages;
        swap_tuples = relform1->reltuples;
        relform1->reltuples = relform2->reltuples;
        relform2->reltuples = swap_tuples;
+
+       swap_allvisible = relform1->relallvisible;
+       relform1->relallvisible = relform2->relallvisible;
+       relform2->relallvisible = swap_allvisible;
    }
 
    /*
 
 void
 vac_update_relstats(Relation relation,
                    BlockNumber num_pages, double num_tuples,
+                   BlockNumber num_all_visible_pages,
                    bool hasindex, TransactionId frozenxid)
 {
    Oid         relid = RelationGetRelid(relation);
        pgcform->reltuples = (float4) num_tuples;
        dirty = true;
    }
+   if (pgcform->relallvisible != (int32) num_all_visible_pages)
+   {
+       pgcform->relallvisible = (int32) num_all_visible_pages;
+       dirty = true;
+   }
    if (pgcform->relhasindex != hasindex)
    {
        pgcform->relhasindex = hasindex;
 
    TransactionId freezeTableLimit;
    BlockNumber new_rel_pages;
    double      new_rel_tuples;
+   BlockNumber new_rel_allvisible;
    TransactionId new_frozen_xid;
 
    /* measure elapsed time iff autovacuum logging requires it */
     * density") with nonzero relpages and reltuples=0 (which means "zero
     * tuple density") unless there's some actual evidence for the latter.
     *
+    * We do update relallvisible even in the corner case, since if the
+    * table is all-visible we'd definitely like to know that.  But clamp
+    * the value to be not more than what we're setting relpages to.
+    *
     * Also, don't change relfrozenxid if we skipped any pages, since then
     * we don't know for certain that all tuples have a newer xmin.
     */
        new_rel_tuples = vacrelstats->old_rel_tuples;
    }
 
+   new_rel_allvisible = visibilitymap_count(onerel);
+   if (new_rel_allvisible > new_rel_pages)
+       new_rel_allvisible = new_rel_pages;
+
    new_frozen_xid = FreezeLimit;
    if (vacrelstats->scanned_pages < vacrelstats->rel_pages)
        new_frozen_xid = InvalidTransactionId;
 
    vac_update_relstats(onerel,
-                       new_rel_pages, new_rel_tuples,
+                       new_rel_pages,
+                       new_rel_tuples,
+                       new_rel_allvisible,
                        vacrelstats->hasindex,
                        new_frozen_xid);
 
     */
    if (!stats->estimated_count)
        vac_update_relstats(indrel,
-                           stats->num_pages, stats->num_index_tuples,
-                           false, InvalidTransactionId);
+                           stats->num_pages,
+                           stats->num_index_tuples,
+                           0,
+                           false,
+                           InvalidTransactionId);
 
    ereport(elevel,
            (errmsg("index \"%s\" now contains %.0f row versions in %u pages",
 
    WRITE_NODE_FIELD(indexlist);
    WRITE_UINT_FIELD(pages);
    WRITE_FLOAT_FIELD(tuples, "%.0f");
+   WRITE_FLOAT_FIELD(allvisfrac, "%.6f");
    WRITE_NODE_FIELD(subplan);
    WRITE_NODE_FIELD(subroot);
    WRITE_NODE_FIELD(baserestrictinfo);
 
 bool       enable_mergejoin = true;
 bool       enable_hashjoin = true;
 
-/* Possibly this should become a GUC too */
-static double visibility_fraction = 0.9;
-
 typedef struct
 {
    PlannerInfo *root;
     *
     * If it's an index-only scan, then we will not need to fetch any heap
     * pages for which the visibility map shows all tuples are visible.
-    * Unfortunately, we have no stats as to how much of the heap is
-    * all-visible, and that's likely to be a rather unstable number anyway.
-    * We use an arbitrary constant visibility_fraction to estimate this.
+    * Hence, reduce the estimated number of heap fetches accordingly.
+    * We use the measured fraction of the entire heap that is all-visible,
+    * which might not be particularly relevant to the subset of the heap
+    * that this query will fetch; but it's not clear how to do better.
     *----------
     */
    if (outer_rel != NULL && outer_rel->rows > 1)
                                            root);
 
        if (indexonly)
-           pages_fetched = ceil(pages_fetched * visibility_fraction);
+           pages_fetched = ceil(pages_fetched * (1.0 - baserel->allvisfrac));
 
        max_IO_cost = (pages_fetched * spc_random_page_cost) / num_scans;
 
                                            root);
 
        if (indexonly)
-           pages_fetched = ceil(pages_fetched * visibility_fraction);
+           pages_fetched = ceil(pages_fetched * (1.0 - baserel->allvisfrac));
 
        min_IO_cost = (pages_fetched * spc_random_page_cost) / num_scans;
    }
                                            root);
 
        if (indexonly)
-           pages_fetched = ceil(pages_fetched * visibility_fraction);
+           pages_fetched = ceil(pages_fetched * (1.0 - baserel->allvisfrac));
 
        /* max_IO_cost is for the perfectly uncorrelated case (csquared=0) */
        max_IO_cost = pages_fetched * spc_random_page_cost;
        pages_fetched = ceil(indexSelectivity * (double) baserel->pages);
 
        if (indexonly)
-           pages_fetched = ceil(pages_fetched * visibility_fraction);
+           pages_fetched = ceil(pages_fetched * (1.0 - baserel->allvisfrac));
 
        min_IO_cost = spc_random_page_cost;
        if (pages_fetched > 1)
 
     */
    if (!inhparent)
        estimate_rel_size(relation, rel->attr_widths - rel->min_attr,
-                         &rel->pages, &rel->tuples);
+                         &rel->pages, &rel->tuples, &rel->allvisfrac);
 
    /*
     * Make list of indexes.  Ignore indexes on system catalogs if told to.
            }
            else
            {
+               double      allvisfrac;             /* dummy */
+
                estimate_rel_size(indexRelation, NULL,
-                                 &info->pages, &info->tuples);
+                                 &info->pages, &info->tuples, &allvisfrac);
                if (info->tuples > rel->tuples)
                    info->tuples = rel->tuples;
            }
 /*
  * estimate_rel_size - estimate # pages and # tuples in a table or index
  *
+ * We also estimate the fraction of the pages that are marked all-visible in
+ * the visibility map, for use in estimation of index-only scans.
+ *
  * If attr_widths isn't NULL, it points to the zero-index entry of the
  * relation's attr_widths[] cache; we fill this in if we have need to compute
  * the attribute widths for estimation purposes.
  */
 void
 estimate_rel_size(Relation rel, int32 *attr_widths,
-                 BlockNumber *pages, double *tuples)
+                 BlockNumber *pages, double *tuples, double *allvisfrac)
 {
    BlockNumber curpages;
    BlockNumber relpages;
    double      reltuples;
+   BlockNumber relallvisible;
    double      density;
 
    switch (rel->rd_rel->relkind)
            if (curpages == 0)
            {
                *tuples = 0;
+               *allvisfrac = 0;
                break;
            }
            /* coerce values in pg_class to more desirable types */
            relpages = (BlockNumber) rel->rd_rel->relpages;
            reltuples = (double) rel->rd_rel->reltuples;
+           relallvisible = (BlockNumber) rel->rd_rel->relallvisible;
 
            /*
             * If it's an index, discount the metapage while estimating the
                density = (BLCKSZ - SizeOfPageHeaderData) / tuple_width;
            }
            *tuples = rint(density * (double) curpages);
+
+           /*
+            * We use relallvisible as-is, rather than scaling it up like we
+            * do for the pages and tuples counts, on the theory that any
+            * pages added since the last VACUUM are most likely not marked
+            * all-visible.  But costsize.c wants it converted to a fraction.
+            */
+           if (relallvisible == 0 || curpages <= 0)
+               *allvisfrac = 0;
+           else if ((double) relallvisible >= curpages)
+               *allvisfrac = 1;
+           else
+               *allvisfrac = (double) relallvisible / curpages;
            break;
        case RELKIND_SEQUENCE:
            /* Sequences always have a known size */
            *pages = 1;
            *tuples = 1;
+           *allvisfrac = 0;
            break;
        case RELKIND_FOREIGN_TABLE:
            /* Just use whatever's in pg_class */
            *pages = rel->rd_rel->relpages;
            *tuples = rel->rd_rel->reltuples;
+           *allvisfrac = 0;
            break;
        default:
            /* else it has no disk storage; probably shouldn't get here? */
            *pages = 0;
            *tuples = 0;
+           *allvisfrac = 0;
            break;
    }
 }
 
    rel->indexlist = NIL;
    rel->pages = 0;
    rel->tuples = 0;
+   rel->allvisfrac = 0;
    rel->subplan = NULL;
    rel->subroot = NULL;
    rel->baserestrictinfo = NIL;
    joinrel->indexlist = NIL;
    joinrel->pages = 0;
    joinrel->tuples = 0;
+   joinrel->allvisfrac = 0;
    joinrel->subplan = NULL;
    joinrel->subroot = NULL;
    joinrel->baserestrictinfo = NIL;
 
 
    relation->rd_rel->relpages = 0;
    relation->rd_rel->reltuples = 0;
+   relation->rd_rel->relallvisible = 0;
    relation->rd_rel->relkind = RELKIND_RELATION;
    relation->rd_rel->relhasoids = hasoids;
    relation->rd_rel->relnatts = (int16) natts;
    {
        classform->relpages = 0;    /* it's empty until further notice */
        classform->reltuples = 0;
+       classform->relallvisible = 0;
    }
    classform->relfrozenxid = freezeXid;
 
 
 extern void visibilitymap_set(Relation rel, BlockNumber heapBlk,
                  XLogRecPtr recptr, Buffer vmbuf);
 extern bool visibilitymap_test(Relation rel, BlockNumber heapBlk, Buffer *vmbuf);
-extern void visibilitymap_truncate(Relation rel, BlockNumber heapblk);
+extern BlockNumber visibilitymap_count(Relation rel);
+extern void visibilitymap_truncate(Relation rel, BlockNumber nheapblocks);
 
 #endif   /* VISIBILITYMAP_H */
 
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 201110071
+#define CATALOG_VERSION_NO 201110141
 
 #endif
 
    Oid         reltablespace;  /* identifier of table space for relation */
    int4        relpages;       /* # of blocks (not always up-to-date) */
    float4      reltuples;      /* # of tuples (not always up-to-date) */
+   int4        relallvisible;  /* # of all-visible blocks (not always
+                                * up-to-date) */
    Oid         reltoastrelid;  /* OID of toast table; 0 if none */
    Oid         reltoastidxid;  /* if toast table, OID of chunk_id index */
    bool        relhasindex;    /* T if has (or has had) any indexes */
  * ----------------
  */
 
-#define Natts_pg_class                 26
+#define Natts_pg_class                 27
 #define Anum_pg_class_relname          1
 #define Anum_pg_class_relnamespace     2
 #define Anum_pg_class_reltype          3
 #define Anum_pg_class_reltablespace        8
 #define Anum_pg_class_relpages         9
 #define Anum_pg_class_reltuples            10
-#define Anum_pg_class_reltoastrelid        11
-#define Anum_pg_class_reltoastidxid        12
-#define Anum_pg_class_relhasindex      13
-#define Anum_pg_class_relisshared      14
-#define Anum_pg_class_relpersistence   15
-#define Anum_pg_class_relkind          16
-#define Anum_pg_class_relnatts         17
-#define Anum_pg_class_relchecks            18
-#define Anum_pg_class_relhasoids       19
-#define Anum_pg_class_relhaspkey       20
-#define Anum_pg_class_relhasrules      21
-#define Anum_pg_class_relhastriggers   22
-#define Anum_pg_class_relhassubclass   23
-#define Anum_pg_class_relfrozenxid     24
-#define Anum_pg_class_relacl           25
-#define Anum_pg_class_reloptions       26
+#define Anum_pg_class_relallvisible        11
+#define Anum_pg_class_reltoastrelid        12
+#define Anum_pg_class_reltoastidxid        13
+#define Anum_pg_class_relhasindex      14
+#define Anum_pg_class_relisshared      15
+#define Anum_pg_class_relpersistence   16
+#define Anum_pg_class_relkind          17
+#define Anum_pg_class_relnatts         18
+#define Anum_pg_class_relchecks            19
+#define Anum_pg_class_relhasoids       20
+#define Anum_pg_class_relhaspkey       21
+#define Anum_pg_class_relhasrules      22
+#define Anum_pg_class_relhastriggers   23
+#define Anum_pg_class_relhassubclass   24
+#define Anum_pg_class_relfrozenxid     25
+#define Anum_pg_class_relacl           26
+#define Anum_pg_class_reloptions       27
 
 /* ----------------
  *     initial contents of pg_class
  */
 
 /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
-DATA(insert OID = 1247 (  pg_type      PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 29 0 t f f f f 3 _null_ _null_ ));
+DATA(insert OID = 1247 (  pg_type      PGNSP 71 0 PGUID 0 0 0 0 0 0 0 0 f f p r 29 0 t f f f f 3 _null_ _null_ ));
 DESCR("");
-DATA(insert OID = 1249 (  pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 21 0 f f f f f 3 _null_ _null_ ));
+DATA(insert OID = 1249 (  pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 0 f f p r 21 0 f f f f f 3 _null_ _null_ ));
 DESCR("");
-DATA(insert OID = 1255 (  pg_proc      PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 26 0 t f f f f 3 _null_ _null_ ));
+DATA(insert OID = 1255 (  pg_proc      PGNSP 81 0 PGUID 0 0 0 0 0 0 0 0 f f p r 26 0 t f f f f 3 _null_ _null_ ));
 DESCR("");
-DATA(insert OID = 1259 (  pg_class     PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f p r 26 0 t f f f f 3 _null_ _null_ ));
+DATA(insert OID = 1259 (  pg_class     PGNSP 83 0 PGUID 0 0 0 0 0 0 0 0 f f p r 27 0 t f f f f 3 _null_ _null_ ));
 DESCR("");
 
 
 
 extern void vac_update_relstats(Relation relation,
                    BlockNumber num_pages,
                    double num_tuples,
+                   BlockNumber num_all_visible_pages,
                    bool hasindex,
                    TransactionId frozenxid);
 extern void vacuum_set_xid_limits(int freeze_min_age, int freeze_table_age,
 
  *                 (always NIL if it's not a table)
  *     pages - number of disk pages in relation (zero if not a table)
  *     tuples - number of tuples in relation (not considering restrictions)
+ *     allvisfrac - fraction of disk pages that are marked all-visible
  *     subplan - plan for subquery (NULL if it's not a subquery)
  *     subroot - PlannerInfo for subquery (NULL if it's not a subquery)
  *
    Relids     *attr_needed;    /* array indexed [min_attr .. max_attr] */
    int32      *attr_widths;    /* array indexed [min_attr .. max_attr] */
    List       *indexlist;      /* list of IndexOptInfo */
-   BlockNumber pages;
+   BlockNumber pages;          /* size estimates derived from pg_class */
    double      tuples;
+   double      allvisfrac;
    struct Plan *subplan;       /* if subquery */
    PlannerInfo *subroot;       /* if subquery */
 
 
                  bool inhparent, RelOptInfo *rel);
 
 extern void estimate_rel_size(Relation rel, int32 *attr_widths,
-                 BlockNumber *pages, double *tuples);
+                 BlockNumber *pages, double *tuples, double *allvisfrac);
 
 extern int32 get_relation_data_width(Oid relid, int32 *attr_widths);
 
 
 (10 rows)
 
 SELECT sum(unique1) over
-   (rows (SELECT unique1 FROM tenk1 ORDER BY unique1 LIMIT 1) + 1 PRECEDING),
+   (order by unique1
+    rows (SELECT unique1 FROM tenk1 ORDER BY unique1 LIMIT 1) + 1 PRECEDING),
    unique1
 FROM tenk1 WHERE unique1 < 10;
  sum | unique1 
 -----+---------
-   4 |       4
-   6 |       2
-   3 |       1
-   7 |       6
-  15 |       9
-  17 |       8
-  13 |       5
-   8 |       3
-  10 |       7
-   7 |       0
+   0 |       0
+   1 |       1
+   3 |       2
+   5 |       3
+   7 |       4
+   9 |       5
+  11 |       6
+  13 |       7
+  15 |       8
+  17 |       9
 (10 rows)
 
 CREATE TEMP VIEW v_window AS
 
 WINDOW w AS (order by four range between current row and unbounded following);
 
 SELECT sum(unique1) over
-   (rows (SELECT unique1 FROM tenk1 ORDER BY unique1 LIMIT 1) + 1 PRECEDING),
+   (order by unique1
+    rows (SELECT unique1 FROM tenk1 ORDER BY unique1 LIMIT 1) + 1 PRECEDING),
    unique1
 FROM tenk1 WHERE unique1 < 10;