diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 82d3658a50b..0acd79361bd 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,4 +1,4 @@ - + @@ -4506,19 +4506,32 @@ The catalog pg_statistic stores statistical data about the contents of the database. Entries are created by - 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. + + Normally there is one entry, with stainherit = + false, for each table column that has been analyzed. + If the table has inheritance children, a second entry with + stainherit = 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 + SELECT column FROM table*, + whereas the stainherit = false row represents + the results of + SELECT column FROM ONLY table. + + pg_statistic also stores statistical data about the values of index expressions. These are described as if they were actual data columns; in particular, starelid 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 stainherit = false. @@ -4572,6 +4585,14 @@ The number of the described column + + stainherit + bool + + If true, the stats include inheritance child columns, not just the + values in the specified relation + + stanullfrac float4 @@ -7114,6 +7135,14 @@ Name of the column described by this row + + inherited + bool + + If true, this row includes inheritance child columns, not just the + values in the specified table + + null_frac real diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 0f33c525b61..8ef00f9287b 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -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); diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 05608bdbee5..cb5ed390e3a 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -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, diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 6d13eeb5ec1..0739db99f50 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -18,11 +18,13 @@ #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)) { diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index b9d1fac0882..0049b7c9731 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -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); } /* diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index 16b84d0f5ad..a58e9170272 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -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; diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 2722a93e074..afbc3edaf62 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -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); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 419c005b508..b35b0beaf19 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -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); } diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 41238b7c0e6..43b0c123ca2 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -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; diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 20d4180e9b9..8bc26cb6e97 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -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; } } diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 0b50309bf36..fc1c21bc4a9 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -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) diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index efed498f120..59e9ee60269 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -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 diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 6ac2c6713d8..0c4ce005295 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -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 diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index 3bf606c0985..a5d93ed4455 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -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 diff --git a/src/include/catalog/pg_statistic.h b/src/include/catalog/pg_statistic.h index 0e831ef2982..8063f74190d 100644 --- a/src/include/catalog/pg_statistic.h +++ b/src/include/catalog/pg_statistic.h @@ -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, diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index e9c994e4f27..68c95d5cf8a 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -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 */ diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index f0647e34194..d2d02236c78 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -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, diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 9420e568acd..87f87e9afcf 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -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);