PostgreSQL Source Code git master
Loading...
Searching...
No Matches
attribute_stats.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 * attribute_stats.c
3 *
4 * PostgreSQL relation attribute statistics manipulation.
5 *
6 * Code supporting the direct import of relation attribute statistics, similar
7 * to what is done by the ANALYZE command.
8 *
9 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
11 *
12 * IDENTIFICATION
13 * src/backend/statistics/attribute_stats.c
14 *
15 *-------------------------------------------------------------------------
16 */
17
18#include "postgres.h"
19
20#include "access/heapam.h"
21#include "catalog/indexing.h"
22#include "catalog/namespace.h"
23#include "catalog/pg_operator.h"
24#include "nodes/makefuncs.h"
27#include "utils/array.h"
28#include "utils/builtins.h"
29#include "utils/fmgroids.h"
30#include "utils/lsyscache.h"
31#include "utils/syscache.h"
32
33/*
34 * Positional argument numbers, names, and types for
35 * attribute_statistics_update() and pg_restore_attribute_stats().
36 */
37
60
61static struct StatsArgInfo attarginfo[] =
62{
63 [ATTRELSCHEMA_ARG] = {"schemaname", TEXTOID},
64 [ATTRELNAME_ARG] = {"relname", TEXTOID},
65 [ATTNAME_ARG] = {"attname", TEXTOID},
66 [ATTNUM_ARG] = {"attnum", INT2OID},
67 [INHERITED_ARG] = {"inherited", BOOLOID},
68 [NULL_FRAC_ARG] = {"null_frac", FLOAT4OID},
69 [AVG_WIDTH_ARG] = {"avg_width", INT4OID},
70 [N_DISTINCT_ARG] = {"n_distinct", FLOAT4OID},
71 [MOST_COMMON_VALS_ARG] = {"most_common_vals", TEXTOID},
72 [MOST_COMMON_FREQS_ARG] = {"most_common_freqs", FLOAT4ARRAYOID},
73 [HISTOGRAM_BOUNDS_ARG] = {"histogram_bounds", TEXTOID},
74 [CORRELATION_ARG] = {"correlation", FLOAT4OID},
75 [MOST_COMMON_ELEMS_ARG] = {"most_common_elems", TEXTOID},
76 [MOST_COMMON_ELEM_FREQS_ARG] = {"most_common_elem_freqs", FLOAT4ARRAYOID},
77 [ELEM_COUNT_HISTOGRAM_ARG] = {"elem_count_histogram", FLOAT4ARRAYOID},
78 [RANGE_LENGTH_HISTOGRAM_ARG] = {"range_length_histogram", TEXTOID},
79 [RANGE_EMPTY_FRAC_ARG] = {"range_empty_frac", FLOAT4OID},
80 [RANGE_BOUNDS_HISTOGRAM_ARG] = {"range_bounds_histogram", TEXTOID},
82};
83
84/*
85 * Positional argument numbers, names, and types for
86 * pg_clear_attribute_stats().
87 */
88
97
98static struct StatsArgInfo cleararginfo[] =
99{
100 [C_ATTRELSCHEMA_ARG] = {"relation", TEXTOID},
101 [C_ATTRELNAME_ARG] = {"relation", TEXTOID},
102 [C_ATTNAME_ARG] = {"attname", TEXTOID},
103 [C_INHERITED_ARG] = {"inherited", BOOLOID},
105};
106
109 const Datum *values, const bool *nulls, const bool *replaces);
110static bool delete_pg_statistic(Oid reloid, AttrNumber attnum, bool stainherit);
111
112/*
113 * Insert or Update Attribute Statistics
114 *
115 * See pg_statistic.h for an explanation of how each statistic kind is
116 * stored. Custom statistics kinds are not supported.
117 *
118 * Depending on the statistics kind, we need to derive information from the
119 * attribute for which we're storing the stats. For instance, the MCVs are
120 * stored as an anyarray, and the representation of the array needs to store
121 * the correct element type, which must be derived from the attribute.
122 *
123 * Major errors, such as the table not existing, the attribute not existing,
124 * or a permissions failure are always reported at ERROR. Other errors, such
125 * as a conversion failure on one statistic kind, are reported as a WARNING
126 * and other statistic kinds may still be updated.
127 */
128static bool
130{
131 char *nspname;
132 char *relname;
133 Oid reloid;
134 char *attname;
136 bool inherited;
138
141
143 int32 atttypmod;
144 char atttyptype;
146 Oid eq_opr = InvalidOid;
147 Oid lt_opr = InvalidOid;
148
151
153
164
166 bool nulls[Natts_pg_statistic] = {0};
167 bool replaces[Natts_pg_statistic] = {0};
168
169 bool result = true;
170
173
176
177 if (RecoveryInProgress())
180 errmsg("recovery is in progress"),
181 errhint("Statistics cannot be modified during recovery.")));
182
183 /* lock before looking up attribute */
184 reloid = RangeVarGetRelidExtended(makeRangeVar(nspname, relname, -1),
187
188 /* user can specify either attname or attnum, but not both */
190 {
194 errmsg("cannot specify both \"%s\" and \"%s\"", "attname", "attnum")));
196 attnum = get_attnum(reloid, attname);
197 /* note that this test covers attisdropped cases too: */
201 errmsg("column \"%s\" of relation \"%s\" does not exist",
202 attname, relname)));
203 }
204 else if (!PG_ARGISNULL(ATTNUM_ARG))
205 {
207 attname = get_attname(reloid, attnum, true);
208 /* annoyingly, get_attname doesn't check attisdropped */
209 if (attname == NULL ||
213 errmsg("column %d of relation \"%s\" does not exist",
214 attnum, relname)));
215 }
216 else
217 {
220 errmsg("must specify either \"%s\" or \"%s\"", "attname", "attnum")));
221 attname = NULL; /* keep compiler quiet */
222 attnum = 0;
223 }
224
225 if (attnum < 0)
228 errmsg("cannot modify statistics on system column \"%s\"",
229 attname)));
230
233
234 /*
235 * Check argument sanity. If some arguments are unusable, emit a WARNING
236 * and set the corresponding argument to NULL in fcinfo.
237 */
238
240 {
241 do_mcv = false;
242 result = false;
243 }
244
246 {
247 do_mcelem = false;
248 result = false;
249 }
251 {
252 do_dechist = false;
253 result = false;
254 }
255
256 if (!stats_check_arg_pair(fcinfo, attarginfo,
258 {
259 do_mcv = false;
260 result = false;
261 }
262
263 if (!stats_check_arg_pair(fcinfo, attarginfo,
266 {
267 do_mcelem = false;
268 result = false;
269 }
270
271 if (!stats_check_arg_pair(fcinfo, attarginfo,
274 {
276 result = false;
277 }
278
279 /* derive information from attribute */
280 statatt_get_type(reloid, attnum,
281 &atttypid, &atttypmod,
283 &eq_opr, &lt_opr);
284
285 /* if needed, derive element type */
286 if (do_mcelem || do_dechist)
287 {
290 {
292 (errmsg("could not determine element type of column \"%s\"", attname),
293 errdetail("Cannot set %s or %s.",
294 "STATISTIC_KIND_MCELEM", "STATISTIC_KIND_DECHIST")));
297
298 do_mcelem = false;
299 do_dechist = false;
300 result = false;
301 }
302 }
303
304 /* histogram and correlation require less-than operator */
305 if ((do_histogram || do_correlation) && !OidIsValid(lt_opr))
306 {
309 errmsg("could not determine less-than operator for column \"%s\"", attname),
310 errdetail("Cannot set %s or %s.",
311 "STATISTIC_KIND_HISTOGRAM", "STATISTIC_KIND_CORRELATION")));
312
313 do_histogram = false;
314 do_correlation = false;
315 result = false;
316 }
317
318 /* only range types can have range stats */
321 {
324 errmsg("column \"%s\" is not a range type", attname),
325 errdetail("Cannot set %s or %s.",
326 "STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM", "STATISTIC_KIND_BOUNDS_HISTOGRAM")));
327
328 do_bounds_histogram = false;
330 result = false;
331 }
332
334
336
338
339 /* initialize from existing tuple if exists */
342 else
344 replaces);
345
346 /* if specified, set to argument values */
348 {
351 }
353 {
356 }
358 {
361 }
362
363 /* STATISTIC_KIND_MCV */
364 if (do_mcv)
365 {
366 bool converted;
368 Datum stavalues = statatt_build_stavalues("most_common_vals",
371 atttypid, atttypmod,
372 &converted);
373
374 if (converted)
375 {
378 int nvals = ARR_DIMS(vals_arr)[0];
379 int nnums = ARR_DIMS(nums_arr)[0];
380
381 if (nvals != nnums)
382 {
385 errmsg("could not parse \"%s\": incorrect number of elements (same as \"%s\" required)",
386 "most_common_vals",
387 "most_common_freqs")));
388 result = false;
389 }
390 else
391 {
394 eq_opr, atttypcoll,
395 stanumbers, false, stavalues, false);
396 }
397 }
398 else
399 result = false;
400 }
401
402 /* STATISTIC_KIND_HISTOGRAM */
403 if (do_histogram)
404 {
405 Datum stavalues;
406 bool converted = false;
407
408 stavalues = statatt_build_stavalues("histogram_bounds",
411 atttypid, atttypmod,
412 &converted);
413
414 if (converted)
415 {
418 lt_opr, atttypcoll,
419 0, true, stavalues, false);
420 }
421 else
422 result = false;
423 }
424
425 /* STATISTIC_KIND_CORRELATION */
426 if (do_correlation)
427 {
430 Datum stanumbers = PointerGetDatum(arry);
431
434 lt_opr, atttypcoll,
435 stanumbers, false, 0, true);
436 }
437
438 /* STATISTIC_KIND_MCELEM */
439 if (do_mcelem)
440 {
442 bool converted = false;
443 Datum stavalues;
444
445 stavalues = statatt_build_stavalues("most_common_elems",
448 elemtypid, atttypmod,
449 &converted);
450
451 if (converted)
452 {
456 stanumbers, false, stavalues, false);
457 }
458 else
459 result = false;
460 }
461
462 /* STATISTIC_KIND_DECHIST */
463 if (do_dechist)
464 {
466
470 stanumbers, false, 0, true);
471 }
472
473 /*
474 * STATISTIC_KIND_BOUNDS_HISTOGRAM
475 *
476 * This stakind appears before STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM even
477 * though it is numerically greater, and all other stakinds appear in
478 * numerical order. We duplicate this quirk for consistency.
479 */
481 {
482 bool converted = false;
483 Datum stavalues;
484
485 stavalues = statatt_build_stavalues("range_bounds_histogram",
488 atttypid, atttypmod,
489 &converted);
490
491 if (converted)
492 {
496 0, true, stavalues, false);
497 }
498 else
499 result = false;
500 }
501
502 /* STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM */
504 {
505 /* The anyarray is always a float8[] for this stakind */
508 Datum stanumbers = PointerGetDatum(arry);
509
510 bool converted = false;
511 Datum stavalues;
512
513 stavalues = statatt_build_stavalues("range_length_histogram",
516 FLOAT8OID, 0, &converted);
517
518 if (converted)
519 {
523 stanumbers, false, stavalues, false);
524 }
525 else
526 result = false;
527 }
528
530
534
535 return result;
536}
537
538/*
539 * Upsert the pg_statistic record.
540 */
541static void
543 const Datum *values, const bool *nulls, const bool *replaces)
544{
546
548 {
550 values, nulls, replaces);
552 }
553 else
554 {
557 }
558
560
562}
563
564/*
565 * Delete pg_statistic record.
566 */
567static bool
569{
572 bool result = false;
573
574 /* Is there already a pg_statistic tuple for this attribute? */
576 ObjectIdGetDatum(reloid),
579
581 {
582 CatalogTupleDelete(sd, &oldtup->t_self);
584 result = true;
585 }
586
588
590
591 return result;
592}
593
594/*
595 * Delete statistics for the given attribute.
596 */
597Datum
599{
600 char *nspname;
601 char *relname;
602 Oid reloid;
603 char *attname;
605 bool inherited;
607
612
615
616 if (RecoveryInProgress())
619 errmsg("recovery is in progress"),
620 errhint("Statistics cannot be modified during recovery.")));
621
622 reloid = RangeVarGetRelidExtended(makeRangeVar(nspname, relname, -1),
625
627 attnum = get_attnum(reloid, attname);
628
629 if (attnum < 0)
632 errmsg("cannot clear statistics on system column \"%s\"",
633 attname)));
634
638 errmsg("column \"%s\" of relation \"%s\" does not exist",
639 attname, get_rel_name(reloid))));
640
642
645}
646
647/*
648 * Import statistics for a given relation attribute.
649 *
650 * Inserts or replaces a row in pg_statistic for the given relation and
651 * attribute name or number. It takes input parameters that correspond to
652 * columns in the view pg_stats.
653 *
654 * Parameters are given in a pseudo named-attribute style: they must be
655 * pairs of parameter names (as text) and values (of appropriate types).
656 * We do that, rather than using regular named-parameter notation, so
657 * that we can add or change parameters without fear of breaking
658 * carelessly-written calls.
659 *
660 * Parameters null_frac, avg_width, and n_distinct all correspond to NOT NULL
661 * columns in pg_statistic. The remaining parameters all belong to a specific
662 * stakind. Some stakinds require multiple parameters, which must be specified
663 * together (or neither specified).
664 *
665 * Parameters are only superficially validated. Omitting a parameter or
666 * passing NULL leaves the statistic unchanged.
667 *
668 * Parameters corresponding to ANYARRAY columns are instead passed in as text
669 * values, which is a valid input string for an array of the type or element
670 * type of the attribute. Any error generated by the array_in() function will
671 * in turn fail the function.
672 */
673Datum
#define DatumGetArrayTypeP(X)
Definition array.h:261
#define ARR_DIMS(a)
Definition array.h:294
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
int16 AttrNumber
Definition attnum.h:21
#define InvalidAttrNumber
Definition attnum.h:23
static bool delete_pg_statistic(Oid reloid, AttrNumber attnum, bool stainherit)
attribute_stats_argnum
@ 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
static struct StatsArgInfo cleararginfo[]
static void upsert_pg_statistic(Relation starel, HeapTuple oldtup, const Datum *values, const bool *nulls, const bool *replaces)
static struct StatsArgInfo attarginfo[]
static bool attribute_statistics_update(FunctionCallInfo fcinfo)
clear_attribute_stats_argnum
@ C_INHERITED_ARG
@ C_NUM_ATTRIBUTE_STATS_ARGS
@ C_ATTNAME_ARG
@ C_ATTRELNAME_ARG
@ C_ATTRELSCHEMA_ARG
Datum pg_clear_attribute_stats(PG_FUNCTION_ARGS)
Datum pg_restore_attribute_stats(PG_FUNCTION_ARGS)
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define TextDatumGetCString(d)
Definition builtins.h:99
int32_t int32
Definition c.h:620
#define OidIsValid(objectId)
Definition c.h:858
uint32 result
int errcode(int sqlerrcode)
Definition elog.c:875
int errhint(const char *fmt,...) pg_attribute_printf(1
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define WARNING
Definition elog.h:37
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition fmgr.c:129
#define PG_RETURN_VOID()
Definition fmgr.h:350
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition fmgr.h:150
#define PG_ARGISNULL(n)
Definition fmgr.h:209
#define PG_GETARG_DATUM(n)
Definition fmgr.h:268
#define LOCAL_FCINFO(name, nargs)
Definition fmgr.h:110
#define PG_GETARG_BOOL(n)
Definition fmgr.h:274
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
#define PG_GETARG_INT16(n)
Definition fmgr.h:271
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1118
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition heaptuple.c:1254
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
#define HeapTupleIsValid(tuple)
Definition htup.h:78
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition indexing.c:365
#define ShareUpdateExclusiveLock
Definition lockdefs.h:39
#define RowExclusiveLock
Definition lockdefs.h:38
char * get_rel_name(Oid relid)
Definition lsyscache.c:2159
AttrNumber get_attnum(Oid relid, const char *attname)
Definition lsyscache.c:1015
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition lsyscache.c:984
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition makefuncs.c:473
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition namespace.c:442
static char * errmsg
NameData attname
int16 attnum
NameData relname
Definition pg_class.h:40
static Datum Int16GetDatum(int16 X)
Definition postgres.h:172
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
#define PointerGetDatum(X)
Definition postgres.h:354
#define InvalidOid
unsigned int Oid
static int fb(int x)
#define RelationGetDescr(relation)
Definition rel.h:542
bool statatt_get_elem_type(Oid atttypid, char atttyptype, Oid *elemtypid, Oid *elem_eq_opr)
Definition stat_utils.c:523
Datum statatt_build_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid, int32 typmod, bool *ok)
Definition stat_utils.c:567
bool stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo, FunctionCallInfo positional_fcinfo, struct StatsArgInfo *arginfo)
Definition stat_utils.c:348
void RangeVarCallbackForStats(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition stat_utils.c:142
void statatt_init_empty_tuple(Oid reloid, int16 attnum, bool inherited, Datum *values, bool *nulls, bool *replaces)
Definition stat_utils.c:722
bool stats_check_arg_array(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum)
Definition stat_utils.c:70
void statatt_get_type(Oid reloid, AttrNumber attnum, Oid *atttypid, int32 *atttypmod, char *atttyptype, Oid *atttypcoll, Oid *eq_opr, Oid *lt_opr)
Definition stat_utils.c:437
void stats_check_required_arg(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum)
Definition stat_utils.c:51
void statatt_set_slot(Datum *values, bool *nulls, bool *replaces, int16 stakind, Oid staop, Oid stacoll, Datum stanumbers, bool stanumbers_isnull, Datum stavalues, bool stavalues_isnull)
Definition stat_utils.c:644
bool stats_check_arg_pair(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum1, int argnum2)
Definition stat_utils.c:111
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
bool SearchSysCacheExistsAttName(Oid relid, const char *attname)
Definition syscache.c:518
HeapTuple SearchSysCache3(SysCacheIdentifier cacheId, Datum key1, Datum key2, Datum key3)
Definition syscache.c:241
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40
void CommandCounterIncrement(void)
Definition xact.c:1130
bool RecoveryInProgress(void)
Definition xlog.c:6832