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{
4042 Oid statOid ; /* OID of pg_statistic_ext entry */
43+ char * schema ; /* statistics schema */
44+ char * name ; /* statistics name */
4145 Bitmapset * columns ; /* attribute numbers covered by the statistics */
4246 List * 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 ,
5054 MVNDistinct * ndistinct , MVDependencies * dependencies ,
5155 VacAttrStats * * stats );
@@ -66,6 +70,12 @@ BuildRelationExtStatistics(Relation onerel, double totalrows,
6670 Relation pg_stext ;
6771 ListCell * lc ;
6872 List * stats ;
73+ MemoryContext cxt ;
74+ MemoryContext oldcxt ;
75+
76+ cxt = AllocSetContextCreate (CurrentMemoryContext , "stats ext" ,
77+ ALLOCSET_DEFAULT_SIZES );
78+ oldcxt = MemoryContextSwitchTo (cxt );
6979
7080 pg_stext = heap_open (StatisticExtRelationId , RowExclusiveLock );
7181 stats = fetch_statentries_for_relation (pg_stext , RelationGetRelid (onerel ));
@@ -78,9 +88,23 @@ BuildRelationExtStatistics(Relation onerel, double totalrows,
7888 VacAttrStats * * stats ;
7989 ListCell * 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+ */
8295 stats = lookup_var_attr_stats (onerel , stat -> columns ,
8396 natts , 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 */
86110 Assert (bms_num_members (stat -> columns ) >= 2 &&
@@ -104,6 +128,9 @@ BuildRelationExtStatistics(Relation onerel, double totalrows,
104128 }
105129
106130 heap_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)
168195 entry = palloc0 (sizeof (StatExtEntry ));
169196 entry -> statOid = HeapTupleGetOid (htup );
170197 staForm = (Form_pg_statistic_ext ) GETSTRUCT (htup );
198+ entry -> schema = get_namespace_name (staForm -> stanamespace );
199+ entry -> name = pstrdup (NameStr (staForm -> staname ));
171200 for (i = 0 ; i < staForm -> stakeys .dim1 ; i ++ )
172201 {
173202 entry -> 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{
211242 int i = 0 ;
212243 int x = -1 ;
213244 VacAttrStats * * stats ;
214- Bitmapset * matched = NULL ;
215245
216246 stats = (VacAttrStats * * )
217247 palloc (bms_num_members (attrs ) * sizeof (VacAttrStats * ));
@@ -222,39 +252,34 @@ lookup_var_attr_stats(Relation rel, Bitmapset *attrs, int natts,
222252 int j ;
223253
224254 stats [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 ];
230260 break ;
231261 }
232262 }
233263
234264 if (!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 that we found a non- dropped column and that the attnum
248- * matches .
249- */
275+ /*
276+ * Sanity check that the column is not dropped - stats should have
277+ * been removed in this case .
278+ */
250279 Assert (!stats [i ]-> attr -> attisdropped );
251- matched = bms_add_member (matched , stats [i ]-> tupattnum );
252280
253281 i ++ ;
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
259284 return stats ;
260285}
0 commit comments