#include "catalog/pg_collation.h"
#include "catalog/pg_statistic_ext.h"
#include "nodes/relation.h"
+#include "postmaster/autovacuum.h"
#include "statistics/extended_stats_internal.h"
#include "statistics/statistics.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
+#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/syscache.h"
typedef struct StatExtEntry
{
Oid statOid; /* OID of pg_statistic_ext entry */
+ char *schema; /* statistics schema */
+ char *name; /* statistics name */
Bitmapset *columns; /* attribute numbers covered by the statistics */
List *types; /* 'char' list of enabled statistic kinds */
} StatExtEntry;
static List *fetch_statentries_for_relation(Relation pg_statext, Oid relid);
static VacAttrStats **lookup_var_attr_stats(Relation rel, Bitmapset *attrs,
- int natts, VacAttrStats **vacattrstats);
+ int nvacatts, VacAttrStats **vacatts);
static void statext_store(Relation pg_stext, Oid relid,
MVNDistinct *ndistinct, MVDependencies *dependencies,
VacAttrStats **stats);
Relation pg_stext;
ListCell *lc;
List *stats;
+ MemoryContext cxt;
+ MemoryContext oldcxt;
+
+ cxt = AllocSetContextCreate(CurrentMemoryContext, "stats ext",
+ ALLOCSET_DEFAULT_SIZES);
+ oldcxt = MemoryContextSwitchTo(cxt);
pg_stext = heap_open(StatisticExtRelationId, RowExclusiveLock);
stats = fetch_statentries_for_relation(pg_stext, RelationGetRelid(onerel));
VacAttrStats **stats;
ListCell *lc2;
- /* filter only the interesting vacattrstats records */
+ /*
+ * Check if we can build these stats based on the column analyzed.
+ * If not, report this fact (except in autovacuum) and move on.
+ */
stats = lookup_var_attr_stats(onerel, stat->columns,
natts, vacattrstats);
+ if (!stats && !IsAutoVacuumWorkerProcess())
+ {
+ ereport(WARNING,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("extended statistics \"%s.%s\" could not be collected for relation %s.%s",
+ stat->schema, stat->name,
+ get_namespace_name(onerel->rd_rel->relnamespace),
+ RelationGetRelationName(onerel)),
+ errtable(onerel)));
+ continue;
+ }
/* check allowed number of dimensions */
Assert(bms_num_members(stat->columns) >= 2 &&
}
heap_close(pg_stext, RowExclusiveLock);
+
+ MemoryContextSwitchTo(oldcxt);
+ MemoryContextDelete(cxt);
}
/*
entry = palloc0(sizeof(StatExtEntry));
entry->statOid = HeapTupleGetOid(htup);
staForm = (Form_pg_statistic_ext) GETSTRUCT(htup);
+ entry->schema = get_namespace_name(staForm->stanamespace);
+ entry->name = pstrdup(NameStr(staForm->staname));
for (i = 0; i < staForm->stakeys.dim1; i++)
{
entry->columns = bms_add_member(entry->columns,
}
/*
- * Using 'vacattrstats' of size 'natts' as input data, return a newly built
- * VacAttrStats array which includes only the items corresponding to attributes
- * indicated by 'attrs'.
+ * Using 'vacatts' of size 'nvacatts' as input data, return a newly built
+ * VacAttrStats array which includes only the items corresponding to
+ * attributes indicated by 'stakeys'. If we don't have all of the per column
+ * stats available to compute the extended stats, then we return NULL to indicate
+ * to the caller that the stats should not be built.
*/
static VacAttrStats **
-lookup_var_attr_stats(Relation rel, Bitmapset *attrs, int natts,
- VacAttrStats **vacattrstats)
+lookup_var_attr_stats(Relation rel, Bitmapset *attrs,
+ int nvacatts, VacAttrStats **vacatts)
{
int i = 0;
int x = -1;
VacAttrStats **stats;
- Bitmapset *matched = NULL;
stats = (VacAttrStats **)
palloc(bms_num_members(attrs) * sizeof(VacAttrStats *));
int j;
stats[i] = NULL;
- for (j = 0; j < natts; j++)
+ for (j = 0; j < nvacatts; j++)
{
- if (x == vacattrstats[j]->tupattnum)
+ if (x == vacatts[j]->tupattnum)
{
- stats[i] = vacattrstats[j];
+ stats[i] = vacatts[j];
break;
}
}
if (!stats[i])
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("extended statistics could not be collected for column \"%s\" of relation %s.%s",
- NameStr(RelationGetDescr(rel)->attrs[x - 1]->attname),
- get_namespace_name(rel->rd_rel->relnamespace),
- RelationGetRelationName(rel)),
- errhint("Consider ALTER TABLE \"%s\".\"%s\" ALTER \"%s\" SET STATISTICS -1",
- get_namespace_name(rel->rd_rel->relnamespace),
- RelationGetRelationName(rel),
- NameStr(RelationGetDescr(rel)->attrs[x - 1]->attname))));
+ {
+ /*
+ * Looks like stats were not gathered for one of the columns
+ * required. We'll be unable to build the extended stats without
+ * this column.
+ */
+ pfree(stats);
+ return NULL;
+ }
- /*
- * Check that we found a non-dropped column and that the attnum
- * matches.
- */
+ /*
+ * Sanity check that the column is not dropped - stats should have
+ * been removed in this case.
+ */
Assert(!stats[i]->attr->attisdropped);
- matched = bms_add_member(matched, stats[i]->tupattnum);
i++;
}
- if (bms_subset_compare(matched, attrs) != BMS_EQUAL)
- elog(ERROR, "could not find all attributes in attribute stats array");
- bms_free(matched);
return stats;
}