PostgreSQL Source Code git master
Macros | Enumerations | Functions | Variables
attribute_stats.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/indexing.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_operator.h"
#include "nodes/nodeFuncs.h"
#include "statistics/statistics.h"
#include "statistics/stat_utils.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
Include dependency graph for attribute_stats.c:

Go to the source code of this file.

Macros

#define  DEFAULT_NULL_FRAC   Float4GetDatum(0.0)
 
#define  DEFAULT_AVG_WIDTH   Int32GetDatum(0) /* unknown */
 
#define  DEFAULT_N_DISTINCT   Float4GetDatum(0.0) /* unknown */
 

Enumerations

 
 

Functions

 
static Nodeget_attr_expr (Relation rel, int attnum)
 
static void  get_attr_stat_type (Oid reloid, AttrNumber attnum, Oid *atttypid, int32 *atttypmod, char *atttyptype, Oid *atttypcoll, Oid *eq_opr, Oid *lt_opr)
 
static bool  get_elem_stat_type (Oid atttypid, char atttyptype, Oid *elemtypid, Oid *elem_eq_opr)
 
static Datum  text_to_stavalues (const char *staname, FmgrInfo *array_in, Datum d, Oid typid, int32 typmod, bool *ok)
 
static void  set_stats_slot (Datum *values, bool *nulls, bool *replaces, int16 stakind, Oid staop, Oid stacoll, Datum stanumbers, bool stanumbers_isnull, Datum stavalues, bool stavalues_isnull)
 
static void  upsert_pg_statistic (Relation starel, HeapTuple oldtup, Datum *values, bool *nulls, bool *replaces)
 
static bool  delete_pg_statistic (Oid reloid, AttrNumber attnum, bool stainherit)
 
static void  init_empty_stats_tuple (Oid reloid, int16 attnum, bool inherited, Datum *values, bool *nulls, bool *replaces)
 
 
 

Variables

static struct StatsArgInfo  attarginfo []
 
static struct StatsArgInfo  cleararginfo []
 

Macro Definition Documentation

DEFAULT_AVG_WIDTH

#define DEFAULT_AVG_WIDTH   Int32GetDatum(0) /* unknown */

Definition at line 34 of file attribute_stats.c.

DEFAULT_N_DISTINCT

#define DEFAULT_N_DISTINCT   Float4GetDatum(0.0) /* unknown */

Definition at line 35 of file attribute_stats.c.

DEFAULT_NULL_FRAC

#define DEFAULT_NULL_FRAC   Float4GetDatum(0.0)

Definition at line 33 of file attribute_stats.c.

Enumeration Type Documentation

attribute_stats_argnum

Enumerator
ATTRELSCHEMA_ARG 
ATTRELNAME_ARG 
ATTNAME_ARG 
ATTNUM_ARG 
INHERITED_ARG 
NULL_FRAC_ARG 
AVG_WIDTH_ARG 
N_DISTINCT_ARG 
MOST_COMMON_VALS_ARG 
MOST_COMMON_FREQS_ARG 
HISTOGRAM_BOUNDS_ARG 
CORRELATION_ARG 
MOST_COMMON_ELEMS_ARG 
MOST_COMMON_ELEM_FREQS_ARG 
ELEM_COUNT_HISTOGRAM_ARG 
RANGE_LENGTH_HISTOGRAM_ARG 
RANGE_EMPTY_FRAC_ARG 
RANGE_BOUNDS_HISTOGRAM_ARG 
NUM_ATTRIBUTE_STATS_ARGS 

Definition at line 37 of file attribute_stats.c.

38{
58};
@ ATTNUM_ARG
@ RANGE_LENGTH_HISTOGRAM_ARG
@ RANGE_BOUNDS_HISTOGRAM_ARG
@ ATTRELSCHEMA_ARG
@ AVG_WIDTH_ARG
@ INHERITED_ARG
@ ATTRELNAME_ARG
@ MOST_COMMON_ELEMS_ARG
@ NULL_FRAC_ARG
@ NUM_ATTRIBUTE_STATS_ARGS
@ MOST_COMMON_FREQS_ARG
@ CORRELATION_ARG
@ HISTOGRAM_BOUNDS_ARG
@ MOST_COMMON_VALS_ARG
@ RANGE_EMPTY_FRAC_ARG
@ ELEM_COUNT_HISTOGRAM_ARG
@ ATTNAME_ARG
@ N_DISTINCT_ARG
@ MOST_COMMON_ELEM_FREQS_ARG

clear_attribute_stats_argnum

Enumerator
C_ATTRELSCHEMA_ARG 
C_ATTRELNAME_ARG 
C_ATTNAME_ARG 
C_INHERITED_ARG 
C_NUM_ATTRIBUTE_STATS_ARGS 

Definition at line 83 of file attribute_stats.c.

84{
90};
@ C_INHERITED_ARG
@ C_NUM_ATTRIBUTE_STATS_ARGS
@ C_ATTNAME_ARG
@ C_ATTRELNAME_ARG
@ C_ATTRELSCHEMA_ARG

Function Documentation

attribute_statistics_update()

static bool attribute_statistics_update ( FunctionCallInfo  fcinfo )
static

Definition at line 138 of file attribute_stats.c.

139{
140 char *nspname;
141 char *relname;
142 Oid reloid;
143 char *attname;
145 bool inherited;
146
147 Relation starel;
148 HeapTuple statup;
149
150 Oid atttypid = InvalidOid;
151 int32 atttypmod;
152 char atttyptype;
153 Oid atttypcoll = InvalidOid;
154 Oid eq_opr = InvalidOid;
155 Oid lt_opr = InvalidOid;
156
157 Oid elemtypid = InvalidOid;
158 Oid elem_eq_opr = InvalidOid;
159
160 FmgrInfo array_in_fn;
161
162 bool do_mcv = !PG_ARGISNULL(MOST_COMMON_FREQS_ARG) &&
164 bool do_histogram = !PG_ARGISNULL(HISTOGRAM_BOUNDS_ARG);
165 bool do_correlation = !PG_ARGISNULL(CORRELATION_ARG);
166 bool do_mcelem = !PG_ARGISNULL(MOST_COMMON_ELEMS_ARG) &&
168 bool do_dechist = !PG_ARGISNULL(ELEM_COUNT_HISTOGRAM_ARG);
169 bool do_bounds_histogram = !PG_ARGISNULL(RANGE_BOUNDS_HISTOGRAM_ARG);
170 bool do_range_length_histogram = !PG_ARGISNULL(RANGE_LENGTH_HISTOGRAM_ARG) &&
172
173 Datum values[Natts_pg_statistic] = {0};
174 bool nulls[Natts_pg_statistic] = {0};
175 bool replaces[Natts_pg_statistic] = {0};
176
177 bool result = true;
178
181
184
185 reloid = stats_lookup_relid(nspname, relname);
186
187 if (RecoveryInProgress())
189 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
190 errmsg("recovery is in progress"),
191 errhint("Statistics cannot be modified during recovery.")));
192
193 /* lock before looking up attribute */
195
196 /* user can specify either attname or attnum, but not both */
198 {
201 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
202 errmsg("cannot specify both \"%s\" and \"%s\"", "attname", "attnum")));
204 attnum = get_attnum(reloid, attname);
205 /* note that this test covers attisdropped cases too: */
208 (errcode(ERRCODE_UNDEFINED_COLUMN),
209 errmsg("column \"%s\" of relation \"%s\" does not exist",
210 attname, relname)));
211 }
212 else if (!PG_ARGISNULL(ATTNUM_ARG))
213 {
215 attname = get_attname(reloid, attnum, true);
216 /* annoyingly, get_attname doesn't check attisdropped */
217 if (attname == NULL ||
220 (errcode(ERRCODE_UNDEFINED_COLUMN),
221 errmsg("column %d of relation \"%s\" does not exist",
222 attnum, relname)));
223 }
224 else
225 {
227 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
228 errmsg("must specify either \"%s\" or \"%s\"", "attname", "attnum")));
229 attname = NULL; /* keep compiler quiet */
230 attnum = 0;
231 }
232
233 if (attnum < 0)
235 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
236 errmsg("cannot modify statistics on system column \"%s\"",
237 attname)));
238
240 inherited = PG_GETARG_BOOL(INHERITED_ARG);
241
242 /*
243 * Check argument sanity. If some arguments are unusable, emit a WARNING
244 * and set the corresponding argument to NULL in fcinfo.
245 */
246
248 {
249 do_mcv = false;
250 result = false;
251 }
252
254 {
255 do_mcelem = false;
256 result = false;
257 }
259 {
260 do_dechist = false;
261 result = false;
262 }
263
264 if (!stats_check_arg_pair(fcinfo, attarginfo,
266 {
267 do_mcv = false;
268 result = false;
269 }
270
271 if (!stats_check_arg_pair(fcinfo, attarginfo,
274 {
275 do_mcelem = false;
276 result = false;
277 }
278
279 if (!stats_check_arg_pair(fcinfo, attarginfo,
282 {
283 do_range_length_histogram = false;
284 result = false;
285 }
286
287 /* derive information from attribute */
289 &atttypid, &atttypmod,
290 &atttyptype, &atttypcoll,
291 &eq_opr, &lt_opr);
292
293 /* if needed, derive element type */
294 if (do_mcelem || do_dechist)
295 {
296 if (!get_elem_stat_type(atttypid, atttyptype,
297 &elemtypid, &elem_eq_opr))
298 {
300 (errmsg("could not determine element type of column \"%s\"", attname),
301 errdetail("Cannot set %s or %s.",
302 "STATISTIC_KIND_MCELEM", "STATISTIC_KIND_DECHIST")));
303 elemtypid = InvalidOid;
304 elem_eq_opr = InvalidOid;
305
306 do_mcelem = false;
307 do_dechist = false;
308 result = false;
309 }
310 }
311
312 /* histogram and correlation require less-than operator */
313 if ((do_histogram || do_correlation) && !OidIsValid(lt_opr))
314 {
316 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
317 errmsg("could not determine less-than operator for column \"%s\"", attname),
318 errdetail("Cannot set %s or %s.",
319 "STATISTIC_KIND_HISTOGRAM", "STATISTIC_KIND_CORRELATION")));
320
321 do_histogram = false;
322 do_correlation = false;
323 result = false;
324 }
325
326 /* only range types can have range stats */
327 if ((do_range_length_histogram || do_bounds_histogram) &&
328 !(atttyptype == TYPTYPE_RANGE || atttyptype == TYPTYPE_MULTIRANGE))
329 {
331 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
332 errmsg("column \"%s\" is not a range type", attname),
333 errdetail("Cannot set %s or %s.",
334 "STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM", "STATISTIC_KIND_BOUNDS_HISTOGRAM")));
335
336 do_bounds_histogram = false;
337 do_range_length_histogram = false;
338 result = false;
339 }
340
341 fmgr_info(F_ARRAY_IN, &array_in_fn);
342
343 starel = table_open(StatisticRelationId, RowExclusiveLock);
344
345 statup = SearchSysCache3(STATRELATTINH, ObjectIdGetDatum(reloid), Int16GetDatum(attnum), BoolGetDatum(inherited));
346
347 /* initialize from existing tuple if exists */
348 if (HeapTupleIsValid(statup))
349 heap_deform_tuple(statup, RelationGetDescr(starel), values, nulls);
350 else
351 init_empty_stats_tuple(reloid, attnum, inherited, values, nulls,
352 replaces);
353
354 /* if specified, set to argument values */
356 {
357 values[Anum_pg_statistic_stanullfrac - 1] = PG_GETARG_DATUM(NULL_FRAC_ARG);
358 replaces[Anum_pg_statistic_stanullfrac - 1] = true;
359 }
361 {
362 values[Anum_pg_statistic_stawidth - 1] = PG_GETARG_DATUM(AVG_WIDTH_ARG);
363 replaces[Anum_pg_statistic_stawidth - 1] = true;
364 }
366 {
367 values[Anum_pg_statistic_stadistinct - 1] = PG_GETARG_DATUM(N_DISTINCT_ARG);
368 replaces[Anum_pg_statistic_stadistinct - 1] = true;
369 }
370
371 /* STATISTIC_KIND_MCV */
372 if (do_mcv)
373 {
374 bool converted;
376 Datum stavalues = text_to_stavalues("most_common_vals",
377 &array_in_fn,
379 atttypid, atttypmod,
380 &converted);
381
382 if (converted)
383 {
384 set_stats_slot(values, nulls, replaces,
385 STATISTIC_KIND_MCV,
386 eq_opr, atttypcoll,
387 stanumbers, false, stavalues, false);
388 }
389 else
390 result = false;
391 }
392
393 /* STATISTIC_KIND_HISTOGRAM */
394 if (do_histogram)
395 {
396 Datum stavalues;
397 bool converted = false;
398
399 stavalues = text_to_stavalues("histogram_bounds",
400 &array_in_fn,
402 atttypid, atttypmod,
403 &converted);
404
405 if (converted)
406 {
407 set_stats_slot(values, nulls, replaces,
408 STATISTIC_KIND_HISTOGRAM,
409 lt_opr, atttypcoll,
410 0, true, stavalues, false);
411 }
412 else
413 result = false;
414 }
415
416 /* STATISTIC_KIND_CORRELATION */
417 if (do_correlation)
418 {
420 ArrayType *arry = construct_array_builtin(elems, 1, FLOAT4OID);
421 Datum stanumbers = PointerGetDatum(arry);
422
423 set_stats_slot(values, nulls, replaces,
424 STATISTIC_KIND_CORRELATION,
425 lt_opr, atttypcoll,
426 stanumbers, false, 0, true);
427 }
428
429 /* STATISTIC_KIND_MCELEM */
430 if (do_mcelem)
431 {
433 bool converted = false;
434 Datum stavalues;
435
436 stavalues = text_to_stavalues("most_common_elems",
437 &array_in_fn,
439 elemtypid, atttypmod,
440 &converted);
441
442 if (converted)
443 {
444 set_stats_slot(values, nulls, replaces,
445 STATISTIC_KIND_MCELEM,
446 elem_eq_opr, atttypcoll,
447 stanumbers, false, stavalues, false);
448 }
449 else
450 result = false;
451 }
452
453 /* STATISTIC_KIND_DECHIST */
454 if (do_dechist)
455 {
457
458 set_stats_slot(values, nulls, replaces,
459 STATISTIC_KIND_DECHIST,
460 elem_eq_opr, atttypcoll,
461 stanumbers, false, 0, true);
462 }
463
464 /*
465 * STATISTIC_KIND_BOUNDS_HISTOGRAM
466 *
467 * This stakind appears before STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM even
468 * though it is numerically greater, and all other stakinds appear in
469 * numerical order. We duplicate this quirk for consistency.
470 */
471 if (do_bounds_histogram)
472 {
473 bool converted = false;
474 Datum stavalues;
475
476 stavalues = text_to_stavalues("range_bounds_histogram",
477 &array_in_fn,
479 atttypid, atttypmod,
480 &converted);
481
482 if (converted)
483 {
484 set_stats_slot(values, nulls, replaces,
485 STATISTIC_KIND_BOUNDS_HISTOGRAM,
487 0, true, stavalues, false);
488 }
489 else
490 result = false;
491 }
492
493 /* STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM */
494 if (do_range_length_histogram)
495 {
496 /* The anyarray is always a float8[] for this stakind */
498 ArrayType *arry = construct_array_builtin(elems, 1, FLOAT4OID);
499 Datum stanumbers = PointerGetDatum(arry);
500
501 bool converted = false;
502 Datum stavalues;
503
504 stavalues = text_to_stavalues("range_length_histogram",
505 &array_in_fn,
507 FLOAT8OID, 0, &converted);
508
509 if (converted)
510 {
511 set_stats_slot(values, nulls, replaces,
512 STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM,
513 Float8LessOperator, InvalidOid,
514 stanumbers, false, stavalues, false);
515 }
516 else
517 result = false;
518 }
519
520 upsert_pg_statistic(starel, statup, values, nulls, replaces);
521
522 if (HeapTupleIsValid(statup))
523 ReleaseSysCache(statup);
525
526 return result;
527}
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3381
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
static void get_attr_stat_type(Oid reloid, AttrNumber attnum, Oid *atttypid, int32 *atttypmod, char *atttyptype, Oid *atttypcoll, Oid *eq_opr, Oid *lt_opr)
static struct StatsArgInfo attarginfo[]
static Datum text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid, int32 typmod, bool *ok)
static bool get_elem_stat_type(Oid atttypid, char atttyptype, Oid *elemtypid, Oid *elem_eq_opr)
static void init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited, Datum *values, bool *nulls, bool *replaces)
static void set_stats_slot(Datum *values, bool *nulls, bool *replaces, int16 stakind, Oid staop, Oid stacoll, Datum stanumbers, bool stanumbers_isnull, Datum stavalues, bool stavalues_isnull)
static void upsert_pg_statistic(Relation starel, HeapTuple oldtup, Datum *values, bool *nulls, bool *replaces)
static Datum values[MAXATTR]
Definition: bootstrap.c:153
#define TextDatumGetCString(d)
Definition: builtins.h:98
int32_t int32
Definition: c.h:534
#define OidIsValid(objectId)
Definition: c.h:774
int errdetail(const char *fmt,...)
Definition: elog.c:1207
int errhint(const char *fmt,...)
Definition: elog.c:1321
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define PG_GETARG_INT16(n)
Definition: fmgr.h:271
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1346
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define RowExclusiveLock
Definition: lockdefs.h:38
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:951
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:920
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
NameData relname
Definition: pg_class.h:38
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:182
static Datum BoolGetDatum(bool X)
Definition: postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
uint64_t Datum
Definition: postgres.h:70
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
#define RelationGetDescr(relation)
Definition: rel.h:540
bool stats_check_arg_array(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum)
Definition: stat_utils.c:56
void stats_check_required_arg(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum)
Definition: stat_utils.c:37
void stats_lock_check_privileges(Oid reloid)
Definition: stat_utils.c:131
Oid stats_lookup_relid(const char *nspname, const char *relname)
Definition: stat_utils.c:221
bool stats_check_arg_pair(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum1, int argnum2)
Definition: stat_utils.c:97
Definition: array.h:93
Definition: fmgr.h:57
Definition: rel.h:56
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:240
bool SearchSysCacheExistsAttName(Oid relid, const char *attname)
Definition: syscache.c:517
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
bool RecoveryInProgress(void)
Definition: xlog.c:6386

References attarginfo, attname, ATTNAME_ARG, attnum, ATTNUM_ARG, ATTRELNAME_ARG, ATTRELSCHEMA_ARG, AVG_WIDTH_ARG, BoolGetDatum(), construct_array_builtin(), CORRELATION_ARG, ELEM_COUNT_HISTOGRAM_ARG, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, fmgr_info(), get_attname(), get_attnum(), get_attr_stat_type(), get_elem_stat_type(), heap_deform_tuple(), HeapTupleIsValid, HISTOGRAM_BOUNDS_ARG, INHERITED_ARG, init_empty_stats_tuple(), Int16GetDatum(), InvalidAttrNumber, InvalidOid, MOST_COMMON_ELEM_FREQS_ARG, MOST_COMMON_ELEMS_ARG, MOST_COMMON_FREQS_ARG, MOST_COMMON_VALS_ARG, N_DISTINCT_ARG, NULL_FRAC_ARG, ObjectIdGetDatum(), OidIsValid, PG_ARGISNULL, PG_GETARG_BOOL, PG_GETARG_DATUM, PG_GETARG_INT16, PointerGetDatum(), RANGE_BOUNDS_HISTOGRAM_ARG, RANGE_EMPTY_FRAC_ARG, RANGE_LENGTH_HISTOGRAM_ARG, RecoveryInProgress(), RelationGetDescr, ReleaseSysCache(), relname, RowExclusiveLock, SearchSysCache3(), SearchSysCacheExistsAttName(), set_stats_slot(), stats_check_arg_array(), stats_check_arg_pair(), stats_check_required_arg(), stats_lock_check_privileges(), stats_lookup_relid(), table_close(), table_open(), text_to_stavalues(), TextDatumGetCString, upsert_pg_statistic(), values, and WARNING.

Referenced by pg_restore_attribute_stats().

delete_pg_statistic()

static bool delete_pg_statistic ( Oid  reloid,
AttrNumber  attnum,
bool  stainherit 
)
static

Definition at line 844 of file attribute_stats.c.

845{
846 Relation sd = table_open(StatisticRelationId, RowExclusiveLock);
847 HeapTuple oldtup;
848 bool result = false;
849
850 /* Is there already a pg_statistic tuple for this attribute? */
851 oldtup = SearchSysCache3(STATRELATTINH,
852 ObjectIdGetDatum(reloid),
854 BoolGetDatum(stainherit));
855
856 if (HeapTupleIsValid(oldtup))
857 {
858 CatalogTupleDelete(sd, &oldtup->t_self);
859 ReleaseSysCache(oldtup);
860 result = true;
861 }
862
864
866
867 return result;
868}
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
ItemPointerData t_self
Definition: htup.h:65
void CommandCounterIncrement(void)
Definition: xact.c:1100

References attnum, BoolGetDatum(), CatalogTupleDelete(), CommandCounterIncrement(), HeapTupleIsValid, Int16GetDatum(), ObjectIdGetDatum(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache3(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by pg_clear_attribute_stats().

get_attr_expr()

static Node * get_attr_expr ( Relation  rel,
int  attnum 
)
static

Definition at line 536 of file attribute_stats.c.

537{
538 List *index_exprs;
539 ListCell *indexpr_item;
540
541 /* relation is not an index */
542 if (rel->rd_rel->relkind != RELKIND_INDEX &&
543 rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
544 return NULL;
545
546 index_exprs = RelationGetIndexExpressions(rel);
547
548 /* index has no expressions to give */
549 if (index_exprs == NIL)
550 return NULL;
551
552 /*
553 * The index attnum points directly to a relation attnum, then it's not an
554 * expression attribute.
555 */
556 if (rel->rd_index->indkey.values[attnum - 1] != 0)
557 return NULL;
558
559 indexpr_item = list_head(rel->rd_indexprs);
560
561 for (int i = 0; i < attnum - 1; i++)
562 if (rel->rd_index->indkey.values[i] == 0)
563 indexpr_item = lnext(rel->rd_indexprs, indexpr_item);
564
565 if (indexpr_item == NULL) /* shouldn't happen */
566 elog(ERROR, "too few entries in indexprs list");
567
568 return (Node *) lfirst(indexpr_item);
569}
#define elog(elevel,...)
Definition: elog.h:226
i
int i
Definition: isn.c:77
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:5097
Definition: pg_list.h:54
Definition: nodes.h:135
List * rd_indexprs
Definition: rel.h:212
Form_pg_index rd_index
Definition: rel.h:192
Form_pg_class rd_rel
Definition: rel.h:111
Definition: pg_list.h:46

References attnum, elog, ERROR, i, lfirst, list_head(), lnext(), NIL, RelationData::rd_index, RelationData::rd_indexprs, RelationData::rd_rel, and RelationGetIndexExpressions().

Referenced by get_attr_stat_type().

get_attr_stat_type()

static void get_attr_stat_type ( Oid  reloid,
AttrNumber  attnum,
Oidatttypid,
int32atttypmod,
char *  atttyptype,
Oidatttypcoll,
Oideq_opr,
Oidlt_opr 
)
static

Definition at line 575 of file attribute_stats.c.

579{
582 HeapTuple atup;
583 Node *expr;
584 TypeCacheEntry *typcache;
585
586 atup = SearchSysCache2(ATTNUM, ObjectIdGetDatum(reloid),
588
589 /* Attribute not found */
590 if (!HeapTupleIsValid(atup))
592 (errcode(ERRCODE_UNDEFINED_COLUMN),
593 errmsg("column %d of relation \"%s\" does not exist",
595
596 attr = (Form_pg_attribute) GETSTRUCT(atup);
597
598 if (attr->attisdropped)
600 (errcode(ERRCODE_UNDEFINED_COLUMN),
601 errmsg("column %d of relation \"%s\" does not exist",
603
604 expr = get_attr_expr(rel, attr->attnum);
605
606 /*
607 * When analyzing an expression index, believe the expression tree's type
608 * not the column datatype --- the latter might be the opckeytype storage
609 * type of the opclass, which is not interesting for our purposes. This
610 * mimics the behavior of examine_attribute().
611 */
612 if (expr == NULL)
613 {
614 *atttypid = attr->atttypid;
615 *atttypmod = attr->atttypmod;
616 *atttypcoll = attr->attcollation;
617 }
618 else
619 {
620 *atttypid = exprType(expr);
621 *atttypmod = exprTypmod(expr);
622
623 if (OidIsValid(attr->attcollation))
624 *atttypcoll = attr->attcollation;
625 else
626 *atttypcoll = exprCollation(expr);
627 }
628 ReleaseSysCache(atup);
629
630 /*
631 * If it's a multirange, step down to the range type, as is done by
632 * multirange_typanalyze().
633 */
634 if (type_is_multirange(*atttypid))
635 *atttypid = get_multirange_range(*atttypid);
636
637 /* finds the right operators even if atttypid is a domain */
638 typcache = lookup_type_cache(*atttypid, TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR);
639 *atttyptype = typcache->typtype;
640 *eq_opr = typcache->eq_opr;
641 *lt_opr = typcache->lt_opr;
642
643 /*
644 * Special case: collation for tsvector is DEFAULT_COLLATION_OID. See
645 * compute_tsvector_stats().
646 */
647 if (*atttypid == TSVECTOROID)
648 *atttypcoll = DEFAULT_COLLATION_OID;
649
651}
static Node * get_attr_expr(Relation rel, int attnum)
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
#define NoLock
Definition: lockdefs.h:34
#define AccessShareLock
Definition: lockdefs.h:36
Oid get_multirange_range(Oid multirangeOid)
Definition: lsyscache.c:3650
bool type_is_multirange(Oid typid)
Definition: lsyscache.c:2865
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:301
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:821
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
#define RelationGetRelationName(relation)
Definition: rel.h:548
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
Oid lt_opr
Definition: typcache.h:63
char typtype
Definition: typcache.h:43
Oid eq_opr
Definition: typcache.h:62
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:230
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_EQ_OPR
Definition: typcache.h:138
#define TYPECACHE_LT_OPR
Definition: typcache.h:139

References AccessShareLock, attnum, TypeCacheEntry::eq_opr, ereport, errcode(), errmsg(), ERROR, exprCollation(), exprType(), exprTypmod(), get_attr_expr(), get_multirange_range(), GETSTRUCT(), HeapTupleIsValid, Int16GetDatum(), lookup_type_cache(), TypeCacheEntry::lt_opr, NoLock, ObjectIdGetDatum(), OidIsValid, relation_close(), relation_open(), RelationGetRelationName, ReleaseSysCache(), SearchSysCache2(), type_is_multirange(), TYPECACHE_EQ_OPR, TYPECACHE_LT_OPR, and TypeCacheEntry::typtype.

Referenced by attribute_statistics_update().

get_elem_stat_type()

static bool get_elem_stat_type ( Oid  atttypid,
char  atttyptype,
Oidelemtypid,
Oidelem_eq_opr 
)
static

Definition at line 657 of file attribute_stats.c.

659{
660 TypeCacheEntry *elemtypcache;
661
662 if (atttypid == TSVECTOROID)
663 {
664 /*
665 * Special case: element type for tsvector is text. See
666 * compute_tsvector_stats().
667 */
668 *elemtypid = TEXTOID;
669 }
670 else
671 {
672 /* find underlying element type through any domain */
673 *elemtypid = get_base_element_type(atttypid);
674 }
675
676 if (!OidIsValid(*elemtypid))
677 return false;
678
679 /* finds the right operator even if elemtypid is a domain */
680 elemtypcache = lookup_type_cache(*elemtypid, TYPECACHE_EQ_OPR);
681 if (!OidIsValid(elemtypcache->eq_opr))
682 return false;
683
684 *elem_eq_opr = elemtypcache->eq_opr;
685
686 return true;
687}
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2999

References TypeCacheEntry::eq_opr, get_base_element_type(), lookup_type_cache(), OidIsValid, and TYPECACHE_EQ_OPR.

Referenced by attribute_statistics_update().

init_empty_stats_tuple()

static void init_empty_stats_tuple ( Oid  reloid,
int16  attnum,
bool  inherited,
Datumvalues,
bool *  nulls,
bool *  replaces 
)
static

Definition at line 874 of file attribute_stats.c.

876{
877 memset(nulls, true, sizeof(bool) * Natts_pg_statistic);
878 memset(replaces, true, sizeof(bool) * Natts_pg_statistic);
879
880 /* must initialize non-NULL attributes */
881
882 values[Anum_pg_statistic_starelid - 1] = ObjectIdGetDatum(reloid);
883 nulls[Anum_pg_statistic_starelid - 1] = false;
884 values[Anum_pg_statistic_staattnum - 1] = Int16GetDatum(attnum);
885 nulls[Anum_pg_statistic_staattnum - 1] = false;
886 values[Anum_pg_statistic_stainherit - 1] = BoolGetDatum(inherited);
887 nulls[Anum_pg_statistic_stainherit - 1] = false;
888
889 values[Anum_pg_statistic_stanullfrac - 1] = DEFAULT_NULL_FRAC;
890 nulls[Anum_pg_statistic_stanullfrac - 1] = false;
891 values[Anum_pg_statistic_stawidth - 1] = DEFAULT_AVG_WIDTH;
892 nulls[Anum_pg_statistic_stawidth - 1] = false;
893 values[Anum_pg_statistic_stadistinct - 1] = DEFAULT_N_DISTINCT;
894 nulls[Anum_pg_statistic_stadistinct - 1] = false;
895
896 /* initialize stakind, staop, and stacoll slots */
897 for (int slotnum = 0; slotnum < STATISTIC_NUM_SLOTS; slotnum++)
898 {
899 values[Anum_pg_statistic_stakind1 + slotnum - 1] = (Datum) 0;
900 nulls[Anum_pg_statistic_stakind1 + slotnum - 1] = false;
901 values[Anum_pg_statistic_staop1 + slotnum - 1] = ObjectIdGetDatum(InvalidOid);
902 nulls[Anum_pg_statistic_staop1 + slotnum - 1] = false;
903 values[Anum_pg_statistic_stacoll1 + slotnum - 1] = ObjectIdGetDatum(InvalidOid);
904 nulls[Anum_pg_statistic_stacoll1 + slotnum - 1] = false;
905 }
906}
#define DEFAULT_NULL_FRAC
#define DEFAULT_N_DISTINCT
#define DEFAULT_AVG_WIDTH
#define STATISTIC_NUM_SLOTS
Definition: pg_statistic.h:127

References attnum, BoolGetDatum(), DEFAULT_AVG_WIDTH, DEFAULT_N_DISTINCT, DEFAULT_NULL_FRAC, Int16GetDatum(), InvalidOid, ObjectIdGetDatum(), STATISTIC_NUM_SLOTS, and values.

Referenced by attribute_statistics_update().

pg_clear_attribute_stats()

Datum pg_clear_attribute_stats ( PG_FUNCTION_ARGS  )

Definition at line 912 of file attribute_stats.c.

913{
914 char *nspname;
915 char *relname;
916 Oid reloid;
917 char *attname;
919 bool inherited;
920
925
928
929 reloid = stats_lookup_relid(nspname, relname);
930
931 if (RecoveryInProgress())
933 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
934 errmsg("recovery is in progress"),
935 errhint("Statistics cannot be modified during recovery.")));
936
938
940 attnum = get_attnum(reloid, attname);
941
942 if (attnum < 0)
944 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
945 errmsg("cannot clear statistics on system column \"%s\"",
946 attname)));
947
950 (errcode(ERRCODE_UNDEFINED_COLUMN),
951 errmsg("column \"%s\" of relation \"%s\" does not exist",
952 attname, get_rel_name(reloid))));
953
954 inherited = PG_GETARG_BOOL(C_INHERITED_ARG);
955
956 delete_pg_statistic(reloid, attnum, inherited);
958}
static bool delete_pg_statistic(Oid reloid, AttrNumber attnum, bool stainherit)
static struct StatsArgInfo cleararginfo[]
#define PG_RETURN_VOID()
Definition: fmgr.h:349
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2095

References attname, attnum, C_ATTNAME_ARG, C_ATTRELNAME_ARG, C_ATTRELSCHEMA_ARG, C_INHERITED_ARG, cleararginfo, delete_pg_statistic(), ereport, errcode(), errhint(), errmsg(), ERROR, get_attnum(), get_rel_name(), InvalidAttrNumber, PG_GETARG_BOOL, PG_GETARG_DATUM, PG_RETURN_VOID, RecoveryInProgress(), relname, stats_check_required_arg(), stats_lock_check_privileges(), stats_lookup_relid(), and TextDatumGetCString.

pg_restore_attribute_stats()

Datum pg_restore_attribute_stats ( PG_FUNCTION_ARGS  )

Definition at line 987 of file attribute_stats.c.

988{
989 LOCAL_FCINFO(positional_fcinfo, NUM_ATTRIBUTE_STATS_ARGS);
990 bool result = true;
991
992 InitFunctionCallInfoData(*positional_fcinfo, NULL, NUM_ATTRIBUTE_STATS_ARGS,
993 InvalidOid, NULL, NULL);
994
995 if (!stats_fill_fcinfo_from_arg_pairs(fcinfo, positional_fcinfo,
996 attarginfo))
997 result = false;
998
999 if (!attribute_statistics_update(positional_fcinfo))
1000 result = false;
1001
1002 PG_RETURN_BOOL(result);
1003}
static bool attribute_statistics_update(FunctionCallInfo fcinfo)
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
bool stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo, FunctionCallInfo positional_fcinfo, struct StatsArgInfo *arginfo)
Definition: stat_utils.c:285

References attarginfo, attribute_statistics_update(), InitFunctionCallInfoData, InvalidOid, LOCAL_FCINFO, NUM_ATTRIBUTE_STATS_ARGS, PG_RETURN_BOOL, and stats_fill_fcinfo_from_arg_pairs().

set_stats_slot()

static void set_stats_slot ( Datumvalues,
bool *  nulls,
bool *  replaces,
int16  stakind,
Oid  staop,
Oid  stacoll,
Datum  stanumbers,
bool  stanumbers_isnull,
Datum  stavalues,
bool  stavalues_isnull 
)
static

Definition at line 750 of file attribute_stats.c.

754{
755 int slotidx;
756 int first_empty = -1;
757 AttrNumber stakind_attnum;
758 AttrNumber staop_attnum;
759 AttrNumber stacoll_attnum;
760
761 /* find existing slot with given stakind */
762 for (slotidx = 0; slotidx < STATISTIC_NUM_SLOTS; slotidx++)
763 {
764 stakind_attnum = Anum_pg_statistic_stakind1 - 1 + slotidx;
765
766 if (first_empty < 0 &&
767 DatumGetInt16(values[stakind_attnum]) == 0)
768 first_empty = slotidx;
769 if (DatumGetInt16(values[stakind_attnum]) == stakind)
770 break;
771 }
772
773 if (slotidx >= STATISTIC_NUM_SLOTS && first_empty >= 0)
774 slotidx = first_empty;
775
776 if (slotidx >= STATISTIC_NUM_SLOTS)
778 (errmsg("maximum number of statistics slots exceeded: %d",
779 slotidx + 1)));
780
781 stakind_attnum = Anum_pg_statistic_stakind1 - 1 + slotidx;
782 staop_attnum = Anum_pg_statistic_staop1 - 1 + slotidx;
783 stacoll_attnum = Anum_pg_statistic_stacoll1 - 1 + slotidx;
784
785 if (DatumGetInt16(values[stakind_attnum]) != stakind)
786 {
787 values[stakind_attnum] = Int16GetDatum(stakind);
788 replaces[stakind_attnum] = true;
789 }
790 if (DatumGetObjectId(values[staop_attnum]) != staop)
791 {
792 values[staop_attnum] = ObjectIdGetDatum(staop);
793 replaces[staop_attnum] = true;
794 }
795 if (DatumGetObjectId(values[stacoll_attnum]) != stacoll)
796 {
797 values[stacoll_attnum] = ObjectIdGetDatum(stacoll);
798 replaces[stacoll_attnum] = true;
799 }
800 if (!stanumbers_isnull)
801 {
802 values[Anum_pg_statistic_stanumbers1 - 1 + slotidx] = stanumbers;
803 nulls[Anum_pg_statistic_stanumbers1 - 1 + slotidx] = false;
804 replaces[Anum_pg_statistic_stanumbers1 - 1 + slotidx] = true;
805 }
806 if (!stavalues_isnull)
807 {
808 values[Anum_pg_statistic_stavalues1 - 1 + slotidx] = stavalues;
809 nulls[Anum_pg_statistic_stavalues1 - 1 + slotidx] = false;
810 replaces[Anum_pg_statistic_stavalues1 - 1 + slotidx] = true;
811 }
812}
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:252
static int16 DatumGetInt16(Datum X)
Definition: postgres.h:172

References DatumGetInt16(), DatumGetObjectId(), ereport, errmsg(), ERROR, Int16GetDatum(), ObjectIdGetDatum(), STATISTIC_NUM_SLOTS, and values.

Referenced by attribute_statistics_update().

text_to_stavalues()

static Datum text_to_stavalues ( const char *  staname,
FmgrInfoarray_in,
Datum  d,
Oid  typid,
int32  typmod,
bool *  ok 
)
static

Definition at line 697 of file attribute_stats.c.

699{
700 LOCAL_FCINFO(fcinfo, 8);
701 char *s;
702 Datum result;
703 ErrorSaveContext escontext = {T_ErrorSaveContext};
704
705 escontext.details_wanted = true;
706
707 s = TextDatumGetCString(d);
708
710 (Node *) &escontext, NULL);
711
712 fcinfo->args[0].value = CStringGetDatum(s);
713 fcinfo->args[0].isnull = false;
714 fcinfo->args[1].value = ObjectIdGetDatum(typid);
715 fcinfo->args[1].isnull = false;
716 fcinfo->args[2].value = Int32GetDatum(typmod);
717 fcinfo->args[2].isnull = false;
718
719 result = FunctionCallInvoke(fcinfo);
720
721 pfree(s);
722
723 if (escontext.error_occurred)
724 {
725 escontext.error_data->elevel = WARNING;
726 ThrowErrorData(escontext.error_data);
727 *ok = false;
728 return (Datum) 0;
729 }
730
732 {
734 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
735 errmsg("\"%s\" array must not contain null values", staname)));
736 *ok = false;
737 return (Datum) 0;
738 }
739
740 *ok = true;
741
742 return result;
743}
#define DatumGetArrayTypeP(X)
Definition: array.h:261
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3767
Datum array_in(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:179
void ThrowErrorData(ErrorData *edata)
Definition: elog.c:1903
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:172
void pfree(void *pointer)
Definition: mcxt.c:1594
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:360
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:222
int elevel
Definition: elog.h:421
bool details_wanted
Definition: miscnodes.h:48
ErrorData * error_data
Definition: miscnodes.h:49
bool error_occurred
Definition: miscnodes.h:47

References array_contains_nulls(), array_in(), CStringGetDatum(), DatumGetArrayTypeP, ErrorSaveContext::details_wanted, ErrorData::elevel, ereport, errcode(), errmsg(), ErrorSaveContext::error_data, ErrorSaveContext::error_occurred, FunctionCallInvoke, InitFunctionCallInfoData, Int32GetDatum(), InvalidOid, LOCAL_FCINFO, ObjectIdGetDatum(), pfree(), TextDatumGetCString, ThrowErrorData(), and WARNING.

Referenced by attribute_statistics_update().

upsert_pg_statistic()

static void upsert_pg_statistic ( Relation  starel,
HeapTuple  oldtup,
Datumvalues,
bool *  nulls,
bool *  replaces 
)
static

Definition at line 818 of file attribute_stats.c.

820{
821 HeapTuple newtup;
822
823 if (HeapTupleIsValid(oldtup))
824 {
825 newtup = heap_modify_tuple(oldtup, RelationGetDescr(starel),
826 values, nulls, replaces);
827 CatalogTupleUpdate(starel, &newtup->t_self, newtup);
828 }
829 else
830 {
831 newtup = heap_form_tuple(RelationGetDescr(starel), values, nulls);
832 CatalogTupleInsert(starel, newtup);
833 }
834
835 heap_freetuple(newtup);
836
838}
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233

References CatalogTupleInsert(), CatalogTupleUpdate(), CommandCounterIncrement(), heap_form_tuple(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, RelationGetDescr, HeapTupleData::t_self, and values.

Referenced by attribute_statistics_update().

Variable Documentation

attarginfo

struct StatsArgInfo attarginfo[]
static
Initial value:
=
{
[ATTRELSCHEMA_ARG] = {"schemaname", TEXTOID},
[ATTRELNAME_ARG] = {"relname", TEXTOID},
[ATTNAME_ARG] = {"attname", TEXTOID},
[ATTNUM_ARG] = {"attnum", INT2OID},
[INHERITED_ARG] = {"inherited", BOOLOID},
[NULL_FRAC_ARG] = {"null_frac", FLOAT4OID},
[AVG_WIDTH_ARG] = {"avg_width", INT4OID},
[N_DISTINCT_ARG] = {"n_distinct", FLOAT4OID},
[MOST_COMMON_VALS_ARG] = {"most_common_vals", TEXTOID},
[MOST_COMMON_FREQS_ARG] = {"most_common_freqs", FLOAT4ARRAYOID},
[HISTOGRAM_BOUNDS_ARG] = {"histogram_bounds", TEXTOID},
[CORRELATION_ARG] = {"correlation", FLOAT4OID},
[MOST_COMMON_ELEMS_ARG] = {"most_common_elems", TEXTOID},
[MOST_COMMON_ELEM_FREQS_ARG] = {"most_common_elem_freqs", FLOAT4ARRAYOID},
[ELEM_COUNT_HISTOGRAM_ARG] = {"elem_count_histogram", FLOAT4ARRAYOID},
[RANGE_LENGTH_HISTOGRAM_ARG] = {"range_length_histogram", TEXTOID},
[RANGE_EMPTY_FRAC_ARG] = {"range_empty_frac", FLOAT4OID},
[RANGE_BOUNDS_HISTOGRAM_ARG] = {"range_bounds_histogram", TEXTOID},
}

Definition at line 60 of file attribute_stats.c.

Referenced by attribute_statistics_update(), and pg_restore_attribute_stats().

cleararginfo

struct StatsArgInfo cleararginfo[]
static
Initial value:
=
{
[C_ATTRELSCHEMA_ARG] = {"relation", TEXTOID},
[C_ATTRELNAME_ARG] = {"relation", TEXTOID},
[C_ATTNAME_ARG] = {"attname", TEXTOID},
[C_INHERITED_ARG] = {"inherited", BOOLOID},
}

Definition at line 92 of file attribute_stats.c.

Referenced by pg_clear_attribute_stats().

AltStyle によって変換されたページ (->オリジナル) /