2323#include "catalog/pg_collation.h"
2424#include "catalog/pg_statistic_ext.h"
2525#include "nodes/relation.h"
26+ #include "postmaster/autovacuum.h"
2627#include "statistics/extended_stats_internal.h"
2728#include "statistics/statistics.h"
2829#include "utils/builtins.h"
2930#include "utils/fmgroids.h"
3031#include "utils/lsyscache.h"
32+ #include "utils/memutils.h"
3133#include "utils/rel.h"
3234#include "utils/syscache.h"
3335
3840typedef struct StatExtEntry
3941{
4042Oid statOid ;/* OID of pg_statistic_ext entry */
43+ char * schema ;/* statistics schema */
44+ char * name ;/* statistics name */
4145Bitmapset * columns ;/* attribute numbers covered by the statistics */
4246List * types ;/* 'char' list of enabled statistic kinds */
4347}StatExtEntry ;
4448
4549
4650static List * fetch_statentries_for_relation (Relation pg_statext ,Oid relid );
4751static VacAttrStats * * lookup_var_attr_stats (Relation rel ,Bitmapset * attrs ,
48- int natts ,VacAttrStats * * vacattrstats );
52+ int nvacatts ,VacAttrStats * * vacatts );
4953static void statext_store (Relation pg_stext ,Oid relid ,
5054MVNDistinct * ndistinct ,MVDependencies * dependencies ,
5155VacAttrStats * * stats );
@@ -66,6 +70,12 @@ BuildRelationExtStatistics(Relation onerel, double totalrows,
6670Relation pg_stext ;
6771ListCell * lc ;
6872List * stats ;
73+ MemoryContext cxt ;
74+ MemoryContext oldcxt ;
75+
76+ cxt = AllocSetContextCreate (CurrentMemoryContext ,"stats ext" ,
77+ ALLOCSET_DEFAULT_SIZES );
78+ oldcxt = MemoryContextSwitchTo (cxt );
6979
7080pg_stext = heap_open (StatisticExtRelationId ,RowExclusiveLock );
7181stats = fetch_statentries_for_relation (pg_stext ,RelationGetRelid (onerel ));
@@ -78,9 +88,23 @@ BuildRelationExtStatistics(Relation onerel, double totalrows,
7888VacAttrStats * * stats ;
7989ListCell * lc2 ;
8090
81- /* filter only the interesting vacattrstats records */
91+ /*
92+ * Check if we can build these stats based on the column analyzed.
93+ * If not, report this fact (except in autovacuum) and move on.
94+ */
8295stats = lookup_var_attr_stats (onerel ,stat -> columns ,
8396natts ,vacattrstats );
97+ if (!stats && !IsAutoVacuumWorkerProcess ())
98+ {
99+ ereport (WARNING ,
100+ (errcode (ERRCODE_INVALID_OBJECT_DEFINITION ),
101+ errmsg ("extended statistics \"%s.%s\" could not be collected for relation %s.%s" ,
102+ stat -> schema ,stat -> name ,
103+ get_namespace_name (onerel -> rd_rel -> relnamespace ),
104+ RelationGetRelationName (onerel )),
105+ errtable (onerel )));
106+ continue ;
107+ }
84108
85109/* check allowed number of dimensions */
86110Assert (bms_num_members (stat -> columns ) >=2 &&
@@ -104,6 +128,9 @@ BuildRelationExtStatistics(Relation onerel, double totalrows,
104128}
105129
106130heap_close (pg_stext ,RowExclusiveLock );
131+
132+ MemoryContextSwitchTo (oldcxt );
133+ MemoryContextDelete (cxt );
107134}
108135
109136/*
@@ -168,6 +195,8 @@ fetch_statentries_for_relation(Relation pg_statext, Oid relid)
168195entry = palloc0 (sizeof (StatExtEntry ));
169196entry -> statOid = HeapTupleGetOid (htup );
170197staForm = (Form_pg_statistic_ext )GETSTRUCT (htup );
198+ entry -> schema = get_namespace_name (staForm -> stanamespace );
199+ entry -> name = pstrdup (NameStr (staForm -> staname ));
171200for (i = 0 ;i < staForm -> stakeys .dim1 ;i ++ )
172201{
173202entry -> columns = bms_add_member (entry -> columns ,
@@ -200,18 +229,19 @@ fetch_statentries_for_relation(Relation pg_statext, Oid relid)
200229}
201230
202231/*
203- * Using 'vacattrstats' of size 'natts' as input data, return a newly built
204- * VacAttrStats array which includes only the items corresponding to attributes
205- * indicated by 'attrs'.
232+ * Using 'vacatts' of size 'nvacatts' as input data, return a newly built
233+ * VacAttrStats array which includes only the items corresponding to
234+ * attributes indicated by 'stakeys'. If we don't have all of the per column
235+ * stats available to compute the extended stats, then we return NULL to indicate
236+ * to the caller that the stats should not be built.
206237 */
207238static VacAttrStats * *
208- lookup_var_attr_stats (Relation rel ,Bitmapset * attrs ,int natts ,
209- VacAttrStats * * vacattrstats )
239+ lookup_var_attr_stats (Relation rel ,Bitmapset * attrs ,
240+ int nvacatts , VacAttrStats * * vacatts )
210241{
211242int i = 0 ;
212243int x = -1 ;
213244VacAttrStats * * stats ;
214- Bitmapset * matched = NULL ;
215245
216246stats = (VacAttrStats * * )
217247palloc (bms_num_members (attrs )* sizeof (VacAttrStats * ));
@@ -222,39 +252,34 @@ lookup_var_attr_stats(Relation rel, Bitmapset *attrs, int natts,
222252int j ;
223253
224254stats [i ]= NULL ;
225- for (j = 0 ;j < natts ;j ++ )
255+ for (j = 0 ;j < nvacatts ;j ++ )
226256{
227- if (x == vacattrstats [j ]-> tupattnum )
257+ if (x == vacatts [j ]-> tupattnum )
228258{
229- stats [i ]= vacattrstats [j ];
259+ stats [i ]= vacatts [j ];
230260break ;
231261}
232262}
233263
234264if (!stats [i ])
235- ereport (ERROR ,
236- (errcode (ERRCODE_INVALID_OBJECT_DEFINITION ),
237- errmsg ("extended statistics could not be collected for column \"%s\" of relation %s.%s" ,
238- NameStr (RelationGetDescr (rel )-> attrs [x - 1 ]-> attname ),
239- get_namespace_name (rel -> rd_rel -> relnamespace ),
240- RelationGetRelationName (rel )),
241- errhint ("Consider ALTER TABLE \"%s\".\"%s\" ALTER \"%s\" SET STATISTICS -1" ,
242- get_namespace_name (rel -> rd_rel -> relnamespace ),
243- RelationGetRelationName (rel ),
244- NameStr (RelationGetDescr (rel )-> attrs [x - 1 ]-> attname ))));
265+ {
266+ /*
267+ * Looks like stats were not gathered for one of the columns
268+ * required. We'll be unable to build the extended stats without
269+ * this column.
270+ */
271+ pfree (stats );
272+ return NULL ;
273+ }
245274
246- /*
247- * Check thatwe found a non- droppedcolumn and that the attnum
248- * matches .
249- */
275+ /*
276+ * Sanity check thatthe column is not dropped- stats should have
277+ * been removed in this case .
278+ */
250279Assert (!stats [i ]-> attr -> attisdropped );
251- matched = bms_add_member (matched ,stats [i ]-> tupattnum );
252280
253281i ++ ;
254282}
255- if (bms_subset_compare (matched ,attrs )!= BMS_EQUAL )
256- elog (ERROR ,"could not find all attributes in attribute stats array" );
257- bms_free (matched );
258283
259284return stats ;
260285}