]> granicus.if.org Git - postgresql/commitdiff
Add the ability to store inheritance-tree statistics in pg_statistic,
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 29 Dec 2009 20:11:45 +0000 (20:11 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 29 Dec 2009 20:11:45 +0000 (20:11 +0000)
and teach ANALYZE to compute such stats for tables that have subclasses.
Per my proposal of yesterday.

autovacuum still needs to be taught about running ANALYZE on parent tables
when their subclasses change, but the feature is useful even without that.

18 files changed:
doc/src/sgml/catalogs.sgml
src/backend/catalog/heap.c
src/backend/catalog/system_views.sql
src/backend/commands/analyze.c
src/backend/commands/vacuum.c
src/backend/executor/nodeHash.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/outfuncs.c
src/backend/optimizer/plan/createplan.c
src/backend/utils/adt/selfuncs.c
src/backend/utils/cache/lsyscache.c
src/backend/utils/cache/syscache.c
src/include/catalog/catversion.h
src/include/catalog/indexing.h
src/include/catalog/pg_statistic.h
src/include/nodes/plannodes.h
src/include/utils/syscache.h
src/test/regress/expected/rules.out

index 82d3658a50b21aa3f1e736e543284a41473a6ac0..0acd79361bd3688d5d24d6586b34970ce0d64ea6 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.214 2009/12/17 14:36:15 rhaas Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.215 2009/12/29 20:11:42 tgl Exp $ -->
 <!--
  Documentation of the system catalogs, directed toward PostgreSQL developers
  -->
    The catalog <structname>pg_statistic</structname> stores
    statistical data about the contents of the database.  Entries are
    created by <xref linkend="sql-analyze" endterm="sql-analyze-title">
-   and subsequently used by the query planner.  There is one entry for
-   each table column that has been analyzed.  Note that all the
+   and subsequently used by the query planner.  Note that all the
    statistical data is inherently approximate, even assuming that it
    is up-to-date.
   </para>
 
+  <para>
+   Normally there is one entry, with <structfield>stainherit</> =
+   <literal>false</>, for each table column that has been analyzed.
+   If the table has inheritance children, a second entry with
+   <structfield>stainherit</> = <literal>true</> is also created.  This row
+   represents the column's statistics over the inheritance tree, i.e.,
+   statistics for the data you'd see with
+   <literal>SELECT <replaceable>column</> FROM <replaceable>table</>*</literal>,
+   whereas the <structfield>stainherit</> = <literal>false</> row represents
+   the results of
+   <literal>SELECT <replaceable>column</> FROM ONLY <replaceable>table</></literal>.
+  </para>
+
   <para>
    <structname>pg_statistic</structname> also stores statistical data about
    the values of index expressions.  These are described as if they were
    actual data columns; in particular, <structfield>starelid</structfield>
    references the index.  No entry is made for an ordinary non-expression
    index column, however, since it would be redundant with the entry
-   for the underlying table column.
+   for the underlying table column.  Currently, entries for index expressions
+   always have <structfield>stainherit</> = <literal>false</>.
   </para>
 
   <para>
       <entry>The number of the described column</entry>
      </row>
 
+     <row>
+      <entry><structfield>stainherit</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>If true, the stats include inheritance child columns, not just the
+       values in the specified relation</entry>
+     </row>
+
      <row>
       <entry><structfield>stanullfrac</structfield></entry>
       <entry><type>float4</type></entry>
       <entry>Name of the column described by this row</entry>
      </row>
 
+     <row>
+      <entry><structfield>inherited</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>If true, this row includes inheritance child columns, not just the
+       values in the specified table</entry>
+     </row>
+
      <row>
       <entry><structfield>null_frac</structfield></entry>
       <entry><type>real</type></entry>
index 0f33c525b611dac18adc3ea3947e7f112ea528e2..8ef00f9287bab8c405a2d3a19d2bfa08e6bdd7e4 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.362 2009/12/24 22:09:23 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.363 2009/12/29 20:11:43 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -2314,7 +2314,7 @@ cookConstraint(ParseState *pstate,
 /*
  * RemoveStatistics --- remove entries in pg_statistic for a rel or column
  *
- * If attnum is zero, remove all entries for rel; else remove only the one
+ * If attnum is zero, remove all entries for rel; else remove only the one(s)
  * for that column.
  */
 void
@@ -2344,9 +2344,10 @@ RemoveStatistics(Oid relid, AttrNumber attnum)
                nkeys = 2;
        }
 
-       scan = systable_beginscan(pgstatistic, StatisticRelidAttnumIndexId, true,
+       scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true,
                                                          SnapshotNow, nkeys, key);
 
+       /* we must loop even when attnum != 0, in case of inherited stats */
        while (HeapTupleIsValid(tuple = systable_getnext(scan)))
                simple_heap_delete(pgstatistic, &tuple->t_self);
 
index 05608bdbee501ab4057f736c7f828466d9727433..cb5ed390e3ad7685eef778e7f42861e45fab28ac 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1996-2009, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.63 2009/11/29 18:14:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.64 2009/12/29 20:11:44 tgl Exp $
  */
 
 CREATE VIEW pg_roles AS 
@@ -109,6 +109,7 @@ CREATE VIEW pg_stats AS
         nspname AS schemaname, 
         relname AS tablename, 
         attname AS attname, 
+        stainherit AS inherited, 
         stanullfrac AS null_frac, 
         stawidth AS avg_width, 
         stadistinct AS n_distinct, 
index 6d13eeb5ec1f65bb1d2046e9656bb487dd6f0dbd..0739db99f5062a0610e64235cce55c9833255886 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.143 2009/12/09 21:57:50 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.144 2009/12/29 20:11:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "access/heapam.h"
 #include "access/transam.h"
+#include "access/tupconvert.h"
 #include "access/tuptoaster.h"
 #include "access/xact.h"
 #include "catalog/index.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
+#include "catalog/pg_inherits_fn.h"
 #include "catalog/pg_namespace.h"
 #include "commands/dbcommands.h"
 #include "commands/vacuum.h"
@@ -55,6 +57,7 @@ typedef struct
        BlockNumber t;                          /* current block number */
        int                     m;                              /* blocks selected so far */
 } BlockSamplerData;
+
 typedef BlockSamplerData *BlockSampler;
 
 /* Per-index data for ANALYZE */
@@ -78,6 +81,8 @@ static MemoryContext anl_context = NULL;
 static BufferAccessStrategy vac_strategy;
 
 
+static void do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
+                          bool update_reltuples, bool inh);
 static void BlockSampler_Init(BlockSampler bs, BlockNumber nblocks,
                                  int samplesize);
 static bool BlockSampler_HasMore(BlockSampler bs);
@@ -93,7 +98,11 @@ static double random_fract(void);
 static double init_selection_state(int n);
 static double get_next_S(double t, int n, double *stateptr);
 static int     compare_rows(const void *a, const void *b);
-static void update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats);
+static int     acquire_inherited_sample_rows(Relation onerel,
+                                                         HeapTuple *rows, int targrows,
+                                                         double *totalrows, double *totaldeadrows);
+static void update_attstats(Oid relid, bool inh,
+                                                       int natts, VacAttrStats **vacattrstats);
 static Datum std_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull);
 static Datum ind_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull);
 
@@ -116,27 +125,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
                        BufferAccessStrategy bstrategy, bool update_reltuples)
 {
        Relation        onerel;
-       int                     attr_cnt,
-                               tcnt,
-                               i,
-                               ind;
-       Relation   *Irel;
-       int                     nindexes;
-       bool            hasindex;
-       bool            analyzableindex;
-       VacAttrStats **vacattrstats;
-       AnlIndexData *indexdata;
-       int                     targrows,
-                               numrows;
-       double          totalrows,
-                               totaldeadrows;
-       HeapTuple  *rows;
-       PGRUsage        ru0;
-       TimestampTz starttime = 0;
-       Oid                     save_userid;
-       int                     save_sec_context;
-       int                     save_nestlevel;
 
+       /* Set up static variables */
        if (vacstmt->options & VACOPT_VERBOSE)
                elevel = INFO;
        else
@@ -145,15 +135,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
        vac_strategy = bstrategy;
 
        /*
-        * Use the current context for storing analysis info.  vacuum.c ensures
-        * that this context will be cleared when I return, thus releasing the
-        * memory allocated here.
-        */
-       anl_context = CurrentMemoryContext;
-
-       /*
-        * Check for user-requested abort.      Note we want this to be inside a
-        * transaction, so xact.c doesn't issue useless WARNING.
+        * Check for user-requested abort.
         */
        CHECK_FOR_INTERRUPTS();
 
@@ -230,10 +212,91 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
                return;
        }
 
-       ereport(elevel,
-                       (errmsg("analyzing \"%s.%s\"",
-                                       get_namespace_name(RelationGetNamespace(onerel)),
-                                       RelationGetRelationName(onerel))));
+       /*
+        * OK, let's do it.  First let other backends know I'm in ANALYZE.
+        */
+       LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+       MyProc->vacuumFlags |= PROC_IN_ANALYZE;
+       LWLockRelease(ProcArrayLock);
+
+       /*
+        * Do the normal non-recursive ANALYZE.
+        */
+       do_analyze_rel(onerel, vacstmt, update_reltuples, false);
+
+       /*
+        * If there are child tables, do recursive ANALYZE.
+        */
+       if (onerel->rd_rel->relhassubclass)
+               do_analyze_rel(onerel, vacstmt, false, true);
+
+       /*
+        * Close source relation now, but keep lock so that no one deletes it
+        * before we commit.  (If someone did, they'd fail to clean up the entries
+        * we made in pg_statistic.  Also, releasing the lock before commit would
+        * expose us to concurrent-update failures in update_attstats.)
+        */
+       relation_close(onerel, NoLock);
+
+       /*
+        * Reset my PGPROC flag.  Note: we need this here, and not in vacuum_rel,
+        * because the vacuum flag is cleared by the end-of-xact code.
+        */
+       LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+       MyProc->vacuumFlags &= ~PROC_IN_ANALYZE;
+       LWLockRelease(ProcArrayLock);
+}
+
+/*
+ *     do_analyze_rel() -- analyze one relation, recursively or not
+ */
+static void
+do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
+                          bool update_reltuples, bool inh)
+{
+       int                     attr_cnt,
+                               tcnt,
+                               i,
+                               ind;
+       Relation   *Irel;
+       int                     nindexes;
+       bool            hasindex;
+       bool            analyzableindex;
+       VacAttrStats **vacattrstats;
+       AnlIndexData *indexdata;
+       int                     targrows,
+                               numrows;
+       double          totalrows,
+                               totaldeadrows;
+       HeapTuple  *rows;
+       PGRUsage        ru0;
+       TimestampTz starttime = 0;
+       MemoryContext caller_context;
+       Oid                     save_userid;
+       int                     save_sec_context;
+       int                     save_nestlevel;
+
+       if (inh)
+               ereport(elevel,
+                               (errmsg("analyzing \"%s.%s\" inheritance tree",
+                                               get_namespace_name(RelationGetNamespace(onerel)),
+                                               RelationGetRelationName(onerel))));
+       else
+               ereport(elevel,
+                               (errmsg("analyzing \"%s.%s\"",
+                                               get_namespace_name(RelationGetNamespace(onerel)),
+                                               RelationGetRelationName(onerel))));
+
+       /*
+        * Set up a working context so that we can easily free whatever junk
+        * gets created.
+        */
+       anl_context = AllocSetContextCreate(CurrentMemoryContext,
+                                                                               "Analyze",
+                                                                               ALLOCSET_DEFAULT_MINSIZE,
+                                                                               ALLOCSET_DEFAULT_INITSIZE,
+                                                                               ALLOCSET_DEFAULT_MAXSIZE);
+       caller_context = MemoryContextSwitchTo(anl_context);
 
        /*
         * Switch to the table owner's userid, so that any index functions are run
@@ -245,11 +308,6 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
                                                   save_sec_context | SECURITY_RESTRICTED_OPERATION);
        save_nestlevel = NewGUCNestLevel();
 
-       /* let others know what I'm doing */
-       LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
-       MyProc->vacuumFlags |= PROC_IN_ANALYZE;
-       LWLockRelease(ProcArrayLock);
-
        /* measure elapsed time iff autovacuum logging requires it */
        if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
        {
@@ -304,9 +362,17 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
        /*
         * Open all indexes of the relation, and see if there are any analyzable
         * columns in the indexes.      We do not analyze index columns if there was
-        * an explicit column list in the ANALYZE command, however.
+        * an explicit column list in the ANALYZE command, however.  If we are
+        * doing a recursive scan, we don't want to touch the parent's indexes
+        * at all.
         */
-       vac_open_indexes(onerel, AccessShareLock, &nindexes, &Irel);
+       if (!inh)
+               vac_open_indexes(onerel, AccessShareLock, &nindexes, &Irel);
+       else
+       {
+               Irel = NULL;
+               nindexes = 0;
+       }
        hasindex = (nindexes > 0);
        indexdata = NULL;
        analyzableindex = false;
@@ -399,8 +465,12 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
         * Acquire the sample rows
         */
        rows = (HeapTuple *) palloc(targrows * sizeof(HeapTuple));
-       numrows = acquire_sample_rows(onerel, rows, targrows,
-                                                                 &totalrows, &totaldeadrows);
+       if (inh)
+               numrows = acquire_inherited_sample_rows(onerel, rows, targrows,
+                                                                                               &totalrows, &totaldeadrows);
+       else
+               numrows = acquire_sample_rows(onerel, rows, targrows,
+                                                                         &totalrows, &totaldeadrows);
 
        /*
         * Compute the statistics.      Temporary results during the calculations for
@@ -452,13 +522,14 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
                 * previous statistics for the target columns.  (If there are stats in
                 * pg_statistic for columns we didn't process, we leave them alone.)
                 */
-               update_attstats(relid, attr_cnt, vacattrstats);
+               update_attstats(RelationGetRelid(onerel), inh,
+                                               attr_cnt, vacattrstats);
 
                for (ind = 0; ind < nindexes; ind++)
                {
                        AnlIndexData *thisdata = &indexdata[ind];
 
-                       update_attstats(RelationGetRelid(Irel[ind]),
+                       update_attstats(RelationGetRelid(Irel[ind]), false,
                                                        thisdata->attr_cnt, thisdata->vacattrstats);
                }
        }
@@ -537,27 +608,16 @@ cleanup:
                                                        pg_rusage_show(&ru0))));
        }
 
-       /*
-        * Close source relation now, but keep lock so that no one deletes it
-        * before we commit.  (If someone did, they'd fail to clean up the entries
-        * we made in pg_statistic.  Also, releasing the lock before commit would
-        * expose us to concurrent-update failures in update_attstats.)
-        */
-       relation_close(onerel, NoLock);
-
-       /*
-        * Reset my PGPROC flag.  Note: we need this here, and not in vacuum_rel,
-        * because the vacuum flag is cleared by the end-of-xact code.
-        */
-       LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
-       MyProc->vacuumFlags &= ~PROC_IN_ANALYZE;
-       LWLockRelease(ProcArrayLock);
-
        /* Roll back any GUC changes executed by index functions */
        AtEOXact_GUC(false, save_nestlevel);
 
        /* Restore userid and security context */
        SetUserIdAndSecContext(save_userid, save_sec_context);
+
+       /* Restore current context and release memory */
+       MemoryContextSwitchTo(caller_context);
+       MemoryContextDelete(anl_context);
+       anl_context = NULL;
 }
 
 /*
@@ -877,6 +937,15 @@ BlockSampler_Next(BlockSampler bs)
 /*
  * acquire_sample_rows -- acquire a random sample of rows from the table
  *
+ * Selected rows are returned in the caller-allocated array rows[], which
+ * must have at least targrows entries.
+ * The actual number of rows selected is returned as the function result.
+ * We also estimate the total numbers of live and dead rows in the table,
+ * and return them into *totalrows and *totaldeadrows, respectively.
+ *
+ * The returned list of tuples is in order by physical position in the table.
+ * (We will rely on this later to derive correlation estimates.)
+ *
  * As of May 2004 we use a new two-stage method:  Stage one selects up
  * to targrows random blocks (or all blocks, if there aren't so many).
  * Stage two scans these blocks and uses the Vitter algorithm to create
@@ -892,17 +961,11 @@ BlockSampler_Next(BlockSampler bs)
  * the number of different blocks represented by the sample tends to be
  * too small.  We can live with that for now.  Improvements are welcome.
  *
- * We also estimate the total numbers of live and dead rows in the table,
- * and return them into *totalrows and *totaldeadrows, respectively.
- *
  * An important property of this sampling method is that because we do
  * look at a statistically unbiased set of blocks, we should get
  * unbiased estimates of the average numbers of live and dead rows per
  * block.  The previous sampling method put too much credence in the row
  * density near the start of the table.
- *
- * The returned list of tuples is in order by physical position in the table.
- * (We will rely on this later to derive correlation estimates.)
  */
 static int
 acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
@@ -918,7 +981,7 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
        BlockSamplerData bs;
        double          rstate;
 
-       Assert(targrows > 1);
+       Assert(targrows > 0);
 
        totalblocks = RelationGetNumberOfBlocks(onerel);
 
@@ -1276,6 +1339,155 @@ compare_rows(const void *a, const void *b)
 }
 
 
+/*
+ * acquire_inherited_sample_rows -- acquire sample rows from inheritance tree
+ *
+ * This has the same API as acquire_sample_rows, except that rows are
+ * collected from all inheritance children as well as the specified table.
+ * We fail and return zero if there are no inheritance children.
+ */
+static int
+acquire_inherited_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
+                                                         double *totalrows, double *totaldeadrows)
+{
+       List       *tableOIDs;
+       Relation   *rels;
+       double     *relblocks;
+       double          totalblocks;
+       int                     numrows,
+                               nrels,
+                               i;
+       ListCell   *lc;
+
+       /*
+        * Find all members of inheritance set.  We only need AccessShareLock on
+        * the children.
+        */
+       tableOIDs = find_all_inheritors(RelationGetRelid(onerel), AccessShareLock);
+
+       /*
+        * Check that there's at least one descendant, else fail.  This could
+        * happen despite analyze_rel's relhassubclass check, if table once had a
+        * child but no longer does.
+        */
+       if (list_length(tableOIDs) < 2)
+       {
+               /*
+                * XXX It would be desirable to clear relhassubclass here, but we
+                * don't have adequate lock to do that safely.
+                */
+               return 0;
+       }
+
+       /*
+        * Count the blocks in all the relations.  The result could overflow
+        * BlockNumber, so we use double arithmetic.
+        */
+       rels = (Relation *) palloc(list_length(tableOIDs) * sizeof(Relation));
+       relblocks = (double *) palloc(list_length(tableOIDs) * sizeof(double));
+       totalblocks = 0;
+       nrels = 0;
+       foreach(lc, tableOIDs)
+       {
+               Oid                     childOID = lfirst_oid(lc);
+               Relation        childrel;
+
+               /* We already got the needed lock */
+               childrel = heap_open(childOID, NoLock);
+
+               /* Ignore if temp table of another backend */
+               if (RELATION_IS_OTHER_TEMP(childrel))
+               {
+                       /* ... but release the lock on it */
+                       Assert(childrel != onerel);
+                       heap_close(childrel, AccessShareLock);
+                       continue;
+               }
+
+               rels[nrels] = childrel;
+               relblocks[nrels] = (double) RelationGetNumberOfBlocks(childrel);
+               totalblocks += relblocks[nrels];
+               nrels++;
+       }
+
+       /*
+        * Now sample rows from each relation, proportionally to its fraction
+        * of the total block count.  (This might be less than desirable if the
+        * child rels have radically different free-space percentages, but it's
+        * not clear that it's worth working harder.)
+        */
+       numrows = 0;
+       *totalrows = 0;
+       *totaldeadrows = 0;
+       for (i = 0; i < nrels; i++)
+       {
+               Relation        childrel = rels[i];
+               double          childblocks = relblocks[i];
+
+               if (childblocks > 0)
+               {
+                       int             childtargrows;
+
+                       childtargrows = (int) rint(targrows * childblocks / totalblocks);
+                       /* Make sure we don't overrun due to roundoff error */
+                       childtargrows = Min(childtargrows, targrows - numrows);
+                       if (childtargrows > 0)
+                       {
+                               int                     childrows;
+                               double          trows,
+                                                       tdrows;
+
+                               /* Fetch a random sample of the child's rows */
+                               childrows = acquire_sample_rows(childrel,
+                                                                                               rows + numrows,
+                                                                                               childtargrows,
+                                                                                               &trows,
+                                                                                               &tdrows);
+
+                               /* We may need to convert from child's rowtype to parent's */
+                               if (childrows > 0 &&
+                                       !equalTupleDescs(RelationGetDescr(childrel),
+                                                                        RelationGetDescr(onerel)))
+                               {
+                                       TupleConversionMap *map;
+
+                                       map = convert_tuples_by_name(RelationGetDescr(childrel),
+                                                                                                RelationGetDescr(onerel),
+                                                                                                gettext_noop("could not convert row type"));
+                                       if (map != NULL)
+                                       {
+                                               int             j;
+
+                                               for (j = 0; j < childrows; j++)
+                                               {
+                                                       HeapTuple       newtup;
+
+                                                       newtup = do_convert_tuple(rows[numrows + j], map);
+                                                       heap_freetuple(rows[numrows + j]);
+                                                       rows[numrows + j] = newtup;
+                                               }
+                                               free_conversion_map(map);
+                                       }
+                               }
+
+                               /* And add to counts */
+                               numrows += childrows;
+                               *totalrows += trows;
+                               *totaldeadrows += tdrows;
+                       }
+               }
+
+               /*
+                * Note: we cannot release the child-table locks, since we may have
+                * pointers to their TOAST tables in the sampled rows.
+                */
+               heap_close(childrel, NoLock);
+       }
+
+       return numrows;
+}
+
+
 /*
  *     update_attstats() -- update attribute statistics for one relation
  *
@@ -1299,7 +1511,7 @@ compare_rows(const void *a, const void *b)
  *             by taking a self-exclusive lock on the relation in analyze_rel().
  */
 static void
-update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
+update_attstats(Oid relid, bool inh, int natts, VacAttrStats **vacattrstats)
 {
        Relation        sd;
        int                     attno;
@@ -1337,6 +1549,7 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
                i = 0;
                values[i++] = ObjectIdGetDatum(relid);  /* starelid */
                values[i++] = Int16GetDatum(stats->attr->attnum);               /* staattnum */
+               values[i++] = BoolGetDatum(inh);                /* stainherit */
                values[i++] = Float4GetDatum(stats->stanullfrac);               /* stanullfrac */
                values[i++] = Int32GetDatum(stats->stawidth);   /* stawidth */
                values[i++] = Float4GetDatum(stats->stadistinct);               /* stadistinct */
@@ -1393,10 +1606,11 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
                }
 
                /* Is there already a pg_statistic tuple for this attribute? */
-               oldtup = SearchSysCache(STATRELATT,
+               oldtup = SearchSysCache(STATRELATTINH,
                                                                ObjectIdGetDatum(relid),
                                                                Int16GetDatum(stats->attr->attnum),
-                                                               0, 0);
+                                                               BoolGetDatum(inh),
+                                                               0);
 
                if (HeapTupleIsValid(oldtup))
                {
index b9d1fac088207fb3d729b6c940a7733d0cfdd925..0049b7c9731f77b0a952f34792492c6f2d28c809 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.399 2009/12/19 01:32:34 sriggs Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.400 2009/12/29 20:11:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -292,7 +292,6 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
           BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel)
 {
        const char *stmttype;
-       volatile MemoryContext anl_context = NULL;
        volatile bool all_rels,
                                in_outer_xact,
                                use_own_xacts;
@@ -403,17 +402,6 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
                        use_own_xacts = false;
        }
 
-       /*
-        * If we are running ANALYZE without per-table transactions, we'll need a
-        * memory context with table lifetime.
-        */
-       if (!use_own_xacts)
-               anl_context = AllocSetContextCreate(PortalContext,
-                                                                                       "Analyze",
-                                                                                       ALLOCSET_DEFAULT_MINSIZE,
-                                                                                       ALLOCSET_DEFAULT_INITSIZE,
-                                                                                       ALLOCSET_DEFAULT_MAXSIZE);
-
        /*
         * vacuum_rel expects to be entered with no transaction active; it will
         * start and commit its own transaction.  But we are called by an SQL
@@ -454,14 +442,9 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
 
                        if (vacstmt->options & VACOPT_ANALYZE)
                        {
-                               MemoryContext old_context = NULL;
-
                                /*
                                 * If using separate xacts, start one for analyze. Otherwise,
-                                * we can use the outer transaction, but we still need to call
-                                * analyze_rel in a memory context that will be cleaned up on
-                                * return (else we leak memory while processing multiple
-                                * tables).
+                                * we can use the outer transaction.
                                 */
                                if (use_own_xacts)
                                {
@@ -469,8 +452,6 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
                                        /* functions in indexes may want a snapshot set */
                                        PushActiveSnapshot(GetTransactionSnapshot());
                                }
-                               else
-                                       old_context = MemoryContextSwitchTo(anl_context);
 
                                analyze_rel(relid, vacstmt, vac_strategy, !scanned_all);
 
@@ -479,11 +460,6 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
                                        PopActiveSnapshot();
                                        CommitTransactionCommand();
                                }
-                               else
-                               {
-                                       MemoryContextSwitchTo(old_context);
-                                       MemoryContextResetAndDeleteChildren(anl_context);
-                               }
                        }
                }
        }
@@ -528,9 +504,6 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
         */
        MemoryContextDelete(vac_context);
        vac_context = NULL;
-
-       if (anl_context)
-               MemoryContextDelete(anl_context);
 }
 
 /*
index 16b84d0f5ad3392ddd3f6738dac61a683ce45fb1..a58e91702721eaeea02d194b67f4dc843a7c252a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeHash.c,v 1.123 2009/10/30 20:58:45 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeHash.c,v 1.124 2009/12/29 20:11:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -996,10 +996,11 @@ ExecHashBuildSkewHash(HashJoinTable hashtable, Hash *node, int mcvsToUse)
        /*
         * Try to find the MCV statistics for the outer relation's join key.
         */
-       statsTuple = SearchSysCache(STATRELATT,
+       statsTuple = SearchSysCache(STATRELATTINH,
                                                                ObjectIdGetDatum(node->skewTable),
                                                                Int16GetDatum(node->skewColumn),
-                                                               0, 0);
+                                                               BoolGetDatum(node->skewInherit),
+                                                               0);
        if (!HeapTupleIsValid(statsTuple))
                return;
 
index 2722a93e074efb3e7b0c29c06b373df8a6159e8a..afbc3edaf62c89c62b8724ac4efa7acd94b35e57 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.455 2009/12/23 02:35:20 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.456 2009/12/29 20:11:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -763,6 +763,7 @@ _copyHash(Hash *from)
         */
        COPY_SCALAR_FIELD(skewTable);
        COPY_SCALAR_FIELD(skewColumn);
+       COPY_SCALAR_FIELD(skewInherit);
        COPY_SCALAR_FIELD(skewColType);
        COPY_SCALAR_FIELD(skewColTypmod);
 
index 419c005b5087c64446a89a82a541ef84e6caddda..b35b0beaf19333a44fa3d7d2196f1e2c11cfe911 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.376 2009/12/23 02:35:21 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.377 2009/12/29 20:11:45 tgl Exp $
  *
  * NOTES
  *       Every node type that can appear in stored rules' parsetrees *must*
@@ -693,6 +693,7 @@ _outHash(StringInfo str, Hash *node)
 
        WRITE_OID_FIELD(skewTable);
        WRITE_INT_FIELD(skewColumn);
+       WRITE_BOOL_FIELD(skewInherit);
        WRITE_OID_FIELD(skewColType);
        WRITE_INT_FIELD(skewColTypmod);
 }
index 41238b7c0e6e48e4045a8de662e7db2eb433501c..43b0c123ca21ad1051b207642c5c6bf6eb500490 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.267 2009/11/15 02:45:35 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.268 2009/12/29 20:11:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -115,6 +115,7 @@ static HashJoin *make_hashjoin(List *tlist,
 static Hash *make_hash(Plan *lefttree,
                  Oid skewTable,
                  AttrNumber skewColumn,
+                 bool skewInherit,
                  Oid skewColType,
                  int32 skewColTypmod);
 static MergeJoin *make_mergejoin(List *tlist,
@@ -1898,6 +1899,7 @@ create_hashjoin_plan(PlannerInfo *root,
        List       *hashclauses;
        Oid                     skewTable = InvalidOid;
        AttrNumber      skewColumn = InvalidAttrNumber;
+       bool            skewInherit = false;
        Oid                     skewColType = InvalidOid;
        int32           skewColTypmod = -1;
        HashJoin   *join_plan;
@@ -1969,6 +1971,7 @@ create_hashjoin_plan(PlannerInfo *root,
                        {
                                skewTable = rte->relid;
                                skewColumn = var->varattno;
+                               skewInherit = rte->inh;
                                skewColType = var->vartype;
                                skewColTypmod = var->vartypmod;
                        }
@@ -1981,6 +1984,7 @@ create_hashjoin_plan(PlannerInfo *root,
        hash_plan = make_hash(inner_plan,
                                                  skewTable,
                                                  skewColumn,
+                                                 skewInherit,
                                                  skewColType,
                                                  skewColTypmod);
        join_plan = make_hashjoin(tlist,
@@ -2794,6 +2798,7 @@ static Hash *
 make_hash(Plan *lefttree,
                  Oid skewTable,
                  AttrNumber skewColumn,
+                 bool skewInherit,
                  Oid skewColType,
                  int32 skewColTypmod)
 {
@@ -2814,6 +2819,7 @@ make_hash(Plan *lefttree,
 
        node->skewTable = skewTable;
        node->skewColumn = skewColumn;
+       node->skewInherit = skewInherit;
        node->skewColType = skewColType;
        node->skewColTypmod = skewColTypmod;
 
index 20d4180e9b9aaf3efbe38d63494ebf20eaf31a44..8bc26cb6e97a93d25f38a7a0b804d05b35e481ca 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.263 2009/10/21 20:38:58 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.264 2009/12/29 20:11:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -4046,20 +4046,13 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
                                !vardata->freefunc)
                                elog(ERROR, "no function provided to release variable stats with");
                }
-               else if (rte->inh)
-               {
-                       /*
-                        * XXX This means the Var represents a column of an append
-                        * relation. Later add code to look at the member relations and
-                        * try to derive some kind of combined statistics?
-                        */
-               }
                else if (rte->rtekind == RTE_RELATION)
                {
-                       vardata->statsTuple = SearchSysCache(STATRELATT,
+                       vardata->statsTuple = SearchSysCache(STATRELATTINH,
                                                                                                 ObjectIdGetDatum(rte->relid),
                                                                                                 Int16GetDatum(var->varattno),
-                                                                                                0, 0);
+                                                                                                BoolGetDatum(rte->inh),
+                                                                                                0);
                        vardata->freefunc = ReleaseSysCache;
                }
                else
@@ -4196,10 +4189,11 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
                                                else if (index->indpred == NIL)
                                                {
                                                        vardata->statsTuple =
-                                                               SearchSysCache(STATRELATT,
+                                                               SearchSysCache(STATRELATTINH,
                                                                                   ObjectIdGetDatum(index->indexoid),
                                                                                           Int16GetDatum(pos + 1),
-                                                                                          0, 0);
+                                                                                          BoolGetDatum(false),
+                                                                                          0);
                                                        vardata->freefunc = ReleaseSysCache;
                                                }
                                                if (vardata->statsTuple)
@@ -5830,10 +5824,11 @@ btcostestimate(PG_FUNCTION_ARGS)
                }
                else
                {
-                       vardata.statsTuple = SearchSysCache(STATRELATT,
+                       vardata.statsTuple = SearchSysCache(STATRELATTINH,
                                                                                                ObjectIdGetDatum(relid),
                                                                                                Int16GetDatum(colnum),
-                                                                                               0, 0);
+                                                                                               BoolGetDatum(rte->inh),
+                                                                                               0);
                        vardata.freefunc = ReleaseSysCache;
                }
        }
@@ -5856,10 +5851,11 @@ btcostestimate(PG_FUNCTION_ARGS)
                }
                else
                {
-                       vardata.statsTuple = SearchSysCache(STATRELATT,
+                       vardata.statsTuple = SearchSysCache(STATRELATTINH,
                                                                                                ObjectIdGetDatum(relid),
                                                                                                Int16GetDatum(colnum),
-                                                                                               0, 0);
+                                                                                               BoolGetDatum(false),
+                                                                                               0);
                        vardata.freefunc = ReleaseSysCache;
                }
        }
index 0b50309bf3646991380c0c17209f5c0190def034..fc1c21bc4a982a446d97fd5375de57952d3793a1 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.163 2009/08/10 05:46:50 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.164 2009/12/29 20:11:45 tgl Exp $
  *
  * NOTES
  *       Eventually, the index information should go through here, too.
@@ -2524,6 +2524,9 @@ get_typmodout(Oid typid)
  *       Given the table and attribute number of a column, get the average
  *       width of entries in the column.  Return zero if no data available.
  *
+ * Currently this is only consulted for individual tables, not for inheritance
+ * trees, so we don't need an "inh" parameter.
+ *
  * Calling a hook at this point looks somewhat strange, but is required
  * because the optimizer calls this function without any other way for
  * plug-ins to control the result.
@@ -2540,10 +2543,11 @@ get_attavgwidth(Oid relid, AttrNumber attnum)
                if (stawidth > 0)
                        return stawidth;
        }
-       tp = SearchSysCache(STATRELATT,
+       tp = SearchSysCache(STATRELATTINH,
                                                ObjectIdGetDatum(relid),
                                                Int16GetDatum(attnum),
-                                               0, 0);
+                                               BoolGetDatum(false),
+                                               0);
        if (HeapTupleIsValid(tp))
        {
                stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
@@ -2609,7 +2613,7 @@ get_attstatsslot(HeapTuple statstuple,
 
        if (values)
        {
-               val = SysCacheGetAttr(STATRELATT, statstuple,
+               val = SysCacheGetAttr(STATRELATTINH, statstuple,
                                                          Anum_pg_statistic_stavalues1 + i,
                                                          &isnull);
                if (isnull)
@@ -2658,7 +2662,7 @@ get_attstatsslot(HeapTuple statstuple,
 
        if (numbers)
        {
-               val = SysCacheGetAttr(STATRELATT, statstuple,
+               val = SysCacheGetAttr(STATRELATTINH, statstuple,
                                                          Anum_pg_statistic_stanumbers1 + i,
                                                          &isnull);
                if (isnull)
index efed498f120d065950d566b61a5a0b2fde46b9e9..59e9ee60269315653c971ebe027ebb4e2aefd1b6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.121 2009/10/05 19:24:45 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.122 2009/12/29 20:11:45 tgl Exp $
  *
  * NOTES
  *       These routines allow the parser/planner/executor to perform
@@ -597,14 +597,14 @@ static const struct cachedesc cacheinfo[] = {
                },
                1024
        },
-       {StatisticRelationId,           /* STATRELATT */
-               StatisticRelidAttnumIndexId,
+       {StatisticRelationId,           /* STATRELATTINH */
+               StatisticRelidAttnumInhIndexId,
                Anum_pg_statistic_starelid,
-               2,
+               3,
                {
                        Anum_pg_statistic_starelid,
                        Anum_pg_statistic_staattnum,
-                       0,
+                       Anum_pg_statistic_stainherit,
                        0
                },
                1024
index 6ac2c6713d8bc6abf52fee17b8fca923f4853a62..0c4ce005295f3907a457be959188c4ef7cf6d496 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.561 2009/12/27 14:50:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.562 2009/12/29 20:11:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200912271
+#define CATALOG_VERSION_NO     200912281
 
 #endif
index 3bf606c0985111bdadcee84cb94102e6201bc538..a5d93ed4455545c80f18b19581e3b19a36a6542f 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.111 2009/12/11 03:34:56 itagaki Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.112 2009/12/29 20:11:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -208,8 +208,8 @@ DECLARE_INDEX(pg_shdepend_depender_index, 1232, on pg_shdepend using btree(dbid
 DECLARE_INDEX(pg_shdepend_reference_index, 1233, on pg_shdepend using btree(refclassid oid_ops, refobjid oid_ops));
 #define SharedDependReferenceIndexId   1233
 
-DECLARE_UNIQUE_INDEX(pg_statistic_relid_att_index, 2696, on pg_statistic using btree(starelid oid_ops, staattnum int2_ops));
-#define StatisticRelidAttnumIndexId  2696
+DECLARE_UNIQUE_INDEX(pg_statistic_relid_att_inh_index, 2696, on pg_statistic using btree(starelid oid_ops, staattnum int2_ops, stainherit bool_ops));
+#define StatisticRelidAttnumInhIndexId  2696
 
 DECLARE_UNIQUE_INDEX(pg_tablespace_oid_index, 2697, on pg_tablespace using btree(oid oid_ops));
 #define TablespaceOidIndexId  2697
index 0e831ef29829f7e552bb94b2015498aab0c42ff3..8063f74190d2d1d1402fed7b5d3c89e70869dab1 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_statistic.h,v 1.39 2009/06/11 14:49:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_statistic.h,v 1.40 2009/12/29 20:11:45 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -43,6 +43,7 @@ CATALOG(pg_statistic,2619) BKI_WITHOUT_OIDS
        /* These fields form the unique key for the entry: */
        Oid                     starelid;               /* relation containing attribute */
        int2            staattnum;              /* attribute (column) stats are for */
+       bool            stainherit;             /* true if inheritance children are included */
 
        /* the fraction of the column's entries that are NULL: */
        float4          stanullfrac;
@@ -142,28 +143,29 @@ typedef FormData_pg_statistic *Form_pg_statistic;
  *             compiler constants for pg_statistic
  * ----------------
  */
-#define Natts_pg_statistic                             21
+#define Natts_pg_statistic                             22
 #define Anum_pg_statistic_starelid             1
 #define Anum_pg_statistic_staattnum            2
-#define Anum_pg_statistic_stanullfrac  3
-#define Anum_pg_statistic_stawidth             4
-#define Anum_pg_statistic_stadistinct  5
-#define Anum_pg_statistic_stakind1             6
-#define Anum_pg_statistic_stakind2             7
-#define Anum_pg_statistic_stakind3             8
-#define Anum_pg_statistic_stakind4             9
-#define Anum_pg_statistic_staop1               10
-#define Anum_pg_statistic_staop2               11
-#define Anum_pg_statistic_staop3               12
-#define Anum_pg_statistic_staop4               13
-#define Anum_pg_statistic_stanumbers1  14
-#define Anum_pg_statistic_stanumbers2  15
-#define Anum_pg_statistic_stanumbers3  16
-#define Anum_pg_statistic_stanumbers4  17
-#define Anum_pg_statistic_stavalues1   18
-#define Anum_pg_statistic_stavalues2   19
-#define Anum_pg_statistic_stavalues3   20
-#define Anum_pg_statistic_stavalues4   21
+#define Anum_pg_statistic_stainherit   3
+#define Anum_pg_statistic_stanullfrac  4
+#define Anum_pg_statistic_stawidth             5
+#define Anum_pg_statistic_stadistinct  6
+#define Anum_pg_statistic_stakind1             7
+#define Anum_pg_statistic_stakind2             8
+#define Anum_pg_statistic_stakind3             9
+#define Anum_pg_statistic_stakind4             10
+#define Anum_pg_statistic_staop1               11
+#define Anum_pg_statistic_staop2               12
+#define Anum_pg_statistic_staop3               13
+#define Anum_pg_statistic_staop4               14
+#define Anum_pg_statistic_stanumbers1  15
+#define Anum_pg_statistic_stanumbers2  16
+#define Anum_pg_statistic_stanumbers3  17
+#define Anum_pg_statistic_stanumbers4  18
+#define Anum_pg_statistic_stavalues1   19
+#define Anum_pg_statistic_stavalues2   20
+#define Anum_pg_statistic_stavalues3   21
+#define Anum_pg_statistic_stavalues4   22
 
 /*
  * Currently, three statistical slot "kinds" are defined: most common values,
index e9c994e4f279a7fedeb4e79cd057a8626eb28332..68c95d5cf8ae0b6619933d70bc5d57e2510988d7 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.113 2009/10/26 02:26:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.114 2009/12/29 20:11:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -570,9 +570,9 @@ typedef struct Unique
  *             hash build node
  *
  * If the executor is supposed to try to apply skew join optimization, then
- * skewTable/skewColumn identify the outer relation's join key column, from
- * which the relevant MCV statistics can be fetched.  Also, its type
- * information is provided to save a lookup.
+ * skewTable/skewColumn/skewInherit identify the outer relation's join key
+ * column, from which the relevant MCV statistics can be fetched.  Also, its
+ * type information is provided to save a lookup.
  * ----------------
  */
 typedef struct Hash
@@ -580,6 +580,7 @@ typedef struct Hash
        Plan            plan;
        Oid                     skewTable;              /* outer join key's table OID, or InvalidOid */
        AttrNumber      skewColumn;             /* outer join key's column #, or zero */
+       bool            skewInherit;    /* is outer join rel an inheritance tree? */
        Oid                     skewColType;    /* datatype of the outer key column */
        int32           skewColTypmod;  /* typmod of the outer key column */
        /* all other info is in the parent HashJoin node */
index f0647e3419407dab07df274f4b7dcb5d419249dd..d2d02236c788b82ade678c56cfa7b5ac22cb1660 100644 (file)
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.75 2009/10/05 19:24:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.76 2009/12/29 20:11:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -70,7 +70,7 @@ enum SysCacheIdentifier
        RELNAMENSP,
        RELOID,
        RULERELNAME,
-       STATRELATT,
+       STATRELATTINH,
        TSCONFIGMAP,
        TSCONFIGNAMENSP,
        TSCONFIGOID,
index 9420e568acd60d4cde14d2d3f077bd5885e62aa9..87f87e9afcf0c218d15b8bf13fa85cc3766712c0 100644 (file)
@@ -1276,8 +1276,8 @@ drop table cchild;
 -- Check that ruleutils are working
 --
 SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
-         viewname         |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              definition                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+         viewname         |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            definition                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  iexit                    | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
  pg_cursors               | SELECT c.name, c.statement, c.is_holdable, c.is_binary, c.is_scrollable, c.creation_time FROM pg_cursor() c(name, statement, is_holdable, is_binary, is_scrollable, creation_time);
  pg_group                 | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin);
@@ -1308,7 +1308,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
  pg_statio_user_indexes   | SELECT pg_statio_all_indexes.relid, pg_statio_all_indexes.indexrelid, pg_statio_all_indexes.schemaname, pg_statio_all_indexes.relname, pg_statio_all_indexes.indexrelname, pg_statio_all_indexes.idx_blks_read, pg_statio_all_indexes.idx_blks_hit FROM pg_statio_all_indexes WHERE ((pg_statio_all_indexes.schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (pg_statio_all_indexes.schemaname !~ '^pg_toast'::text));
  pg_statio_user_sequences | SELECT pg_statio_all_sequences.relid, pg_statio_all_sequences.schemaname, pg_statio_all_sequences.relname, pg_statio_all_sequences.blks_read, pg_statio_all_sequences.blks_hit FROM pg_statio_all_sequences WHERE ((pg_statio_all_sequences.schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (pg_statio_all_sequences.schemaname !~ '^pg_toast'::text));
  pg_statio_user_tables    | SELECT pg_statio_all_tables.relid, pg_statio_all_tables.schemaname, pg_statio_all_tables.relname, pg_statio_all_tables.heap_blks_read, pg_statio_all_tables.heap_blks_hit, pg_statio_all_tables.idx_blks_read, pg_statio_all_tables.idx_blks_hit, pg_statio_all_tables.toast_blks_read, pg_statio_all_tables.toast_blks_hit, pg_statio_all_tables.tidx_blks_read, pg_statio_all_tables.tidx_blks_hit FROM pg_statio_all_tables WHERE ((pg_statio_all_tables.schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (pg_statio_all_tables.schemaname !~ '^pg_toast'::text));
- pg_stats                 | SELECT n.nspname AS schemaname, c.relname AS tablename, a.attname, s.stanullfrac AS null_frac, s.stawidth AS avg_width, s.stadistinct AS n_distinct, CASE WHEN (s.stakind1 = ANY (ARRAY[1, 4])) THEN s.stavalues1 WHEN (s.stakind2 = ANY (ARRAY[1, 4])) THEN s.stavalues2 WHEN (s.stakind3 = ANY (ARRAY[1, 4])) THEN s.stavalues3 WHEN (s.stakind4 = ANY (ARRAY[1, 4])) THEN s.stavalues4 ELSE NULL::anyarray END AS most_common_vals, CASE WHEN (s.stakind1 = ANY (ARRAY[1, 4])) THEN s.stanumbers1 WHEN (s.stakind2 = ANY (ARRAY[1, 4])) THEN s.stanumbers2 WHEN (s.stakind3 = ANY (ARRAY[1, 4])) THEN s.stanumbers3 WHEN (s.stakind4 = ANY (ARRAY[1, 4])) THEN s.stanumbers4 ELSE NULL::real[] END AS most_common_freqs, CASE WHEN (s.stakind1 = 2) THEN s.stavalues1 WHEN (s.stakind2 = 2) THEN s.stavalues2 WHEN (s.stakind3 = 2) THEN s.stavalues3 WHEN (s.stakind4 = 2) THEN s.stavalues4 ELSE NULL::anyarray END AS histogram_bounds, CASE WHEN (s.stakind1 = 3) THEN s.stanumbers1[1] WHEN (s.stakind2 = 3) THEN s.stanumbers2[1] WHEN (s.stakind3 = 3) THEN s.stanumbers3[1] WHEN (s.stakind4 = 3) THEN s.stanumbers4[1] ELSE NULL::real END AS correlation FROM (((pg_statistic s JOIN pg_class c ON ((c.oid = s.starelid))) JOIN pg_attribute a ON (((c.oid = a.attrelid) AND (a.attnum = s.staattnum)))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE ((NOT a.attisdropped) AND has_column_privilege(c.oid, a.attnum, 'select'::text));
+ pg_stats                 | SELECT n.nspname AS schemaname, c.relname AS tablename, a.attname, s.stainherit AS inherited, s.stanullfrac AS null_frac, s.stawidth AS avg_width, s.stadistinct AS n_distinct, CASE WHEN (s.stakind1 = ANY (ARRAY[1, 4])) THEN s.stavalues1 WHEN (s.stakind2 = ANY (ARRAY[1, 4])) THEN s.stavalues2 WHEN (s.stakind3 = ANY (ARRAY[1, 4])) THEN s.stavalues3 WHEN (s.stakind4 = ANY (ARRAY[1, 4])) THEN s.stavalues4 ELSE NULL::anyarray END AS most_common_vals, CASE WHEN (s.stakind1 = ANY (ARRAY[1, 4])) THEN s.stanumbers1 WHEN (s.stakind2 = ANY (ARRAY[1, 4])) THEN s.stanumbers2 WHEN (s.stakind3 = ANY (ARRAY[1, 4])) THEN s.stanumbers3 WHEN (s.stakind4 = ANY (ARRAY[1, 4])) THEN s.stanumbers4 ELSE NULL::real[] END AS most_common_freqs, CASE WHEN (s.stakind1 = 2) THEN s.stavalues1 WHEN (s.stakind2 = 2) THEN s.stavalues2 WHEN (s.stakind3 = 2) THEN s.stavalues3 WHEN (s.stakind4 = 2) THEN s.stavalues4 ELSE NULL::anyarray END AS histogram_bounds, CASE WHEN (s.stakind1 = 3) THEN s.stanumbers1[1] WHEN (s.stakind2 = 3) THEN s.stanumbers2[1] WHEN (s.stakind3 = 3) THEN s.stanumbers3[1] WHEN (s.stakind4 = 3) THEN s.stanumbers4[1] ELSE NULL::real END AS correlation FROM (((pg_statistic s JOIN pg_class c ON ((c.oid = s.starelid))) JOIN pg_attribute a ON (((c.oid = a.attrelid) AND (a.attnum = s.staattnum)))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE ((NOT a.attisdropped) AND has_column_privilege(c.oid, a.attnum, 'select'::text));
  pg_tables                | SELECT n.nspname AS schemaname, c.relname AS tablename, pg_get_userbyid(c.relowner) AS tableowner, t.spcname AS tablespace, c.relhasindex AS hasindexes, c.relhasrules AS hasrules, c.relhastriggers AS hastriggers FROM ((pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = c.reltablespace))) WHERE (c.relkind = 'r'::"char");
  pg_timezone_abbrevs      | SELECT pg_timezone_abbrevs.abbrev, pg_timezone_abbrevs.utc_offset, pg_timezone_abbrevs.is_dst FROM pg_timezone_abbrevs() pg_timezone_abbrevs(abbrev, utc_offset, is_dst);
  pg_timezone_names        | SELECT pg_timezone_names.name, pg_timezone_names.abbrev, pg_timezone_names.utc_offset, pg_timezone_names.is_dst FROM pg_timezone_names() pg_timezone_names(name, abbrev, utc_offset, is_dst);