23
23
#include "catalog/pg_collation.h"
24
24
#include "catalog/pg_statistic_ext.h"
25
25
#include "nodes/relation.h"
26
+ #include "postmaster/autovacuum.h"
26
27
#include "statistics/extended_stats_internal.h"
27
28
#include "statistics/statistics.h"
28
29
#include "utils/builtins.h"
29
30
#include "utils/fmgroids.h"
30
31
#include "utils/lsyscache.h"
32
+ #include "utils/memutils.h"
31
33
#include "utils/rel.h"
32
34
#include "utils/syscache.h"
33
35
38
40
typedef struct StatExtEntry
39
41
{
40
42
Oid statOid ; /* OID of pg_statistic_ext entry */
43
+ char * schema ; /* statistics schema */
44
+ char * name ; /* statistics name */
41
45
Bitmapset * columns ; /* attribute numbers covered by the statistics */
42
46
List * types ; /* 'char' list of enabled statistic kinds */
43
47
} StatExtEntry ;
44
48
45
49
46
50
static List * fetch_statentries_for_relation (Relation pg_statext , Oid relid );
47
51
static VacAttrStats * * lookup_var_attr_stats (Relation rel , Bitmapset * attrs ,
48
- int natts , VacAttrStats * * vacattrstats );
52
+ int nvacatts , VacAttrStats * * vacatts );
49
53
static void statext_store (Relation pg_stext , Oid relid ,
50
54
MVNDistinct * ndistinct , MVDependencies * dependencies ,
51
55
VacAttrStats * * stats );
@@ -66,6 +70,12 @@ BuildRelationExtStatistics(Relation onerel, double totalrows,
66
70
Relation pg_stext ;
67
71
ListCell * lc ;
68
72
List * stats ;
73
+ MemoryContext cxt ;
74
+ MemoryContext oldcxt ;
75
+
76
+ cxt = AllocSetContextCreate (CurrentMemoryContext , "stats ext" ,
77
+ ALLOCSET_DEFAULT_SIZES );
78
+ oldcxt = MemoryContextSwitchTo (cxt );
69
79
70
80
pg_stext = heap_open (StatisticExtRelationId , RowExclusiveLock );
71
81
stats = fetch_statentries_for_relation (pg_stext , RelationGetRelid (onerel ));
@@ -78,9 +88,23 @@ BuildRelationExtStatistics(Relation onerel, double totalrows,
78
88
VacAttrStats * * stats ;
79
89
ListCell * lc2 ;
80
90
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
+ */
82
95
stats = lookup_var_attr_stats (onerel , stat -> columns ,
83
96
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
+ }
84
108
85
109
/* check allowed number of dimensions */
86
110
Assert (bms_num_members (stat -> columns ) >= 2 &&
@@ -104,6 +128,9 @@ BuildRelationExtStatistics(Relation onerel, double totalrows,
104
128
}
105
129
106
130
heap_close (pg_stext , RowExclusiveLock );
131
+
132
+ MemoryContextSwitchTo (oldcxt );
133
+ MemoryContextDelete (cxt );
107
134
}
108
135
109
136
/*
@@ -168,6 +195,8 @@ fetch_statentries_for_relation(Relation pg_statext, Oid relid)
168
195
entry = palloc0 (sizeof (StatExtEntry ));
169
196
entry -> statOid = HeapTupleGetOid (htup );
170
197
staForm = (Form_pg_statistic_ext ) GETSTRUCT (htup );
198
+ entry -> schema = get_namespace_name (staForm -> stanamespace );
199
+ entry -> name = pstrdup (NameStr (staForm -> staname ));
171
200
for (i = 0 ; i < staForm -> stakeys .dim1 ; i ++ )
172
201
{
173
202
entry -> columns = bms_add_member (entry -> columns ,
@@ -200,18 +229,19 @@ fetch_statentries_for_relation(Relation pg_statext, Oid relid)
200
229
}
201
230
202
231
/*
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.
206
237
*/
207
238
static 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 )
210
241
{
211
242
int i = 0 ;
212
243
int x = -1 ;
213
244
VacAttrStats * * stats ;
214
- Bitmapset * matched = NULL ;
215
245
216
246
stats = (VacAttrStats * * )
217
247
palloc (bms_num_members (attrs ) * sizeof (VacAttrStats * ));
@@ -222,39 +252,34 @@ lookup_var_attr_stats(Relation rel, Bitmapset *attrs, int natts,
222
252
int j ;
223
253
224
254
stats [i ] = NULL ;
225
- for (j = 0 ; j < natts ; j ++ )
255
+ for (j = 0 ; j < nvacatts ; j ++ )
226
256
{
227
- if (x == vacattrstats [j ]-> tupattnum )
257
+ if (x == vacatts [j ]-> tupattnum )
228
258
{
229
- stats [i ] = vacattrstats [j ];
259
+ stats [i ] = vacatts [j ];
230
260
break ;
231
261
}
232
262
}
233
263
234
264
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
+ }
245
274
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
+ */
250
279
Assert (!stats [i ]-> attr -> attisdropped );
251
- matched = bms_add_member (matched , stats [i ]-> tupattnum );
252
280
253
281
i ++ ;
254
282
}
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 );
258
283
259
284
return stats ;
260
285
}
0 commit comments