PostgreSQL Source Code git master
Loading...
Searching...
No Matches
extended_stats_funcs.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_collation_d.h"
#include "catalog/pg_database.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_statistic_ext_data.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "statistics/extended_stats_internal.h"
#include "statistics/stat_utils.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/jsonb.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for extended_stats_funcs.c:

Go to the source code of this file.

Data Structures

struct  StakindFlags
 

Enumerations

enum  extended_stats_argnum {
  RELSCHEMA_ARG = 0 , RELNAME_ARG , STATSCHEMA_ARG , STATNAME_ARG ,
  INHERITED_ARG , NDISTINCT_ARG , DEPENDENCIES_ARG , MOST_COMMON_VALS_ARG ,
  MOST_COMMON_FREQS_ARG , MOST_COMMON_BASE_FREQS_ARG , EXPRESSIONS_ARG , NUM_EXTENDED_STATS_ARGS
}
 
enum  extended_stats_exprs_element {
  NULL_FRAC_ELEM = 0 , AVG_WIDTH_ELEM , N_DISTINCT_ELEM , MOST_COMMON_VALS_ELEM ,
  MOST_COMMON_FREQS_ELEM , HISTOGRAM_BOUNDS_ELEM , CORRELATION_ELEM , MOST_COMMON_ELEMS_ELEM ,
  MOST_COMMON_ELEM_FREQS_ELEM , ELEM_COUNT_HISTOGRAM_ELEM , RANGE_LENGTH_HISTOGRAM_ELEM , RANGE_EMPTY_FRAC_ELEM ,
  RANGE_BOUNDS_HISTOGRAM_ELEM , NUM_ATTRIBUTE_STATS_ELEMS
}
 

Functions

static bool extended_statistics_update (FunctionCallInfo fcinfo)
 
static HeapTuple get_pg_statistic_ext (Relation pg_stext, Oid nspoid, const char *stxname)
 
static bool delete_pg_statistic_ext_data (Oid stxoid, bool inherited)
 
static void expand_stxkind (HeapTuple tup, StakindFlags *enabled)
 
static void upsert_pg_statistic_ext_data (const Datum *values, const bool *nulls, const bool *replaces)
 
static bool check_mcvlist_array (const ArrayType *arr, int argindex, int required_ndims, int mcv_length)
 
static Datum import_expressions (Relation pgsd, int numexprs, Oid *atttypids, int32 *atttypmods, Oid *atttypcolls, Jsonb *exprs_jsonb, bool *exprs_is_perfect)
 
static Datum import_mcv (const ArrayType *mcv_arr, const ArrayType *freqs_arr, const ArrayType *base_freqs_arr, Oid *atttypids, int32 *atttypmods, Oid *atttypcolls, int numattrs, bool *ok)
 
static charjbv_string_get_cstr (JsonbValue *jval)
 
static bool jbv_to_infunc_datum (JsonbValue *jval, PGFunction func, AttrNumber exprnum, const char *argname, Datum *datum)
 
static bool key_in_expr_argnames (JsonbValue *key)
 
static bool check_all_expr_argnames_valid (JsonbContainer *cont, AttrNumber exprnum)
 
static Datum array_in_safe (FmgrInfo *array_in, const char *s, Oid typid, int32 typmod, AttrNumber exprnum, const char *element_name, bool *ok)
 
static Datum import_pg_statistic (Relation pgsd, JsonbContainer *cont, AttrNumber exprnum, FmgrInfo *array_in_fn, Oid typid, int32 typmod, Oid typcoll, bool *pg_statistic_ok)
 
Datum pg_restore_extended_stats (PG_FUNCTION_ARGS)
 
Datum pg_clear_extended_stats (PG_FUNCTION_ARGS)
 

Variables

static struct StatsArgInfo extarginfo []
 
static const charextexprargname [NUM_ATTRIBUTE_STATS_ELEMS]
 

Enumeration Type Documentation

◆ extended_stats_argnum

Enumerator
RELSCHEMA_ARG 
RELNAME_ARG 
STATSCHEMA_ARG 
STATNAME_ARG 
INHERITED_ARG 
NDISTINCT_ARG 
DEPENDENCIES_ARG 
MOST_COMMON_VALS_ARG 
MOST_COMMON_FREQS_ARG 
MOST_COMMON_BASE_FREQS_ARG 
EXPRESSIONS_ARG 
NUM_EXTENDED_STATS_ARGS 

Definition at line 46 of file extended_stats_funcs.c.

◆ extended_stats_exprs_element

Enumerator
NULL_FRAC_ELEM 
AVG_WIDTH_ELEM 
N_DISTINCT_ELEM 
MOST_COMMON_VALS_ELEM 
MOST_COMMON_FREQS_ELEM 
HISTOGRAM_BOUNDS_ELEM 
CORRELATION_ELEM 
MOST_COMMON_ELEMS_ELEM 
MOST_COMMON_ELEM_FREQS_ELEM 
ELEM_COUNT_HISTOGRAM_ELEM 
RANGE_LENGTH_HISTOGRAM_ELEM 
RANGE_EMPTY_FRAC_ELEM 
RANGE_BOUNDS_HISTOGRAM_ELEM 
NUM_ATTRIBUTE_STATS_ELEMS 

Definition at line 86 of file extended_stats_funcs.c.

87{
102};
@ MOST_COMMON_ELEM_FREQS_ELEM
@ NUM_ATTRIBUTE_STATS_ELEMS
@ RANGE_EMPTY_FRAC_ELEM
@ N_DISTINCT_ELEM
@ AVG_WIDTH_ELEM
@ ELEM_COUNT_HISTOGRAM_ELEM
@ HISTOGRAM_BOUNDS_ELEM
@ MOST_COMMON_FREQS_ELEM
@ CORRELATION_ELEM
@ RANGE_LENGTH_HISTOGRAM_ELEM
@ MOST_COMMON_VALS_ELEM
@ RANGE_BOUNDS_HISTOGRAM_ELEM
@ NULL_FRAC_ELEM
@ MOST_COMMON_ELEMS_ELEM

Function Documentation

◆ array_in_safe()

static Datum array_in_safe ( FmgrInfo array_in,
const char s,
Oid  typid,
int32  typmod,
AttrNumber  exprnum,
const char element_name,
bool ok 
)
static

Definition at line 1029 of file extended_stats_funcs.c.

1031{
1032 LOCAL_FCINFO(fcinfo, 3);
1033 Datum result;
1034
1035 ErrorSaveContext escontext = {
1037 .details_wanted = true
1038 };
1039
1040 *ok = false;
1042 (Node *) &escontext, NULL);
1043
1044 fcinfo->args[0].value = CStringGetDatum(s);
1045 fcinfo->args[0].isnull = false;
1046 fcinfo->args[1].value = ObjectIdGetDatum(typid);
1047 fcinfo->args[1].isnull = false;
1048 fcinfo->args[2].value = Int32GetDatum(typmod);
1049 fcinfo->args[2].isnull = false;
1050
1051 result = FunctionCallInvoke(fcinfo);
1052
1053 /*
1054 * If the array_in function returned an error, we will want to report that
1055 * ERROR as a WARNING, and add some location context to the error message.
1056 * Overwriting the existing hint (if any) is not ideal, and an error
1057 * context would only work for level >= ERROR.
1058 */
1059 if (escontext.error_occurred)
1060 {
1062
1065 "Element \"%s\" in expression %d could not be parsed.",
1067 escontext.error_data->elevel = WARNING;
1068 escontext.error_data->hint = hint_str.data;
1069 ThrowErrorData(escontext.error_data);
1070 pfree(hint_str.data);
1071 return (Datum) 0;
1072 }
1073
1075 {
1078 errmsg("could not import element \"%s\" in expression %d: must be a one-dimensional array",
1080 return (Datum) 0;
1081 }
1082
1084 {
1087 errmsg("could not import element \"%s\" in expression %d: null value found",
1089 return (Datum) 0;
1090 }
1091
1092 *ok = true;
1093 return result;
1094}
#define ARR_NDIM(a)
Definition array.h:290
#define DatumGetArrayTypeP(X)
Definition array.h:261
bool array_contains_nulls(const ArrayType *array)
Datum array_in(PG_FUNCTION_ARGS)
Definition arrayfuncs.c:181
uint32 result
void ThrowErrorData(ErrorData *edata)
Definition elog.c:2091
int errcode(int sqlerrcode)
Definition elog.c:875
#define WARNING
Definition elog.h:37
#define ereport(elevel,...)
Definition elog.h:152
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition fmgr.h:150
#define LOCAL_FCINFO(name, nargs)
Definition fmgr.h:110
#define FunctionCallInvoke(fcinfo)
Definition fmgr.h:172
void pfree(void *pointer)
Definition mcxt.c:1619
static char * errmsg
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
#define InvalidOid
static int fb(int x)
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
int elevel
Definition elog.h:423
char * hint
Definition elog.h:437
ErrorData * error_data
Definition miscnodes.h:49
Definition nodes.h:135

References appendStringInfo(), ARR_NDIM, array_contains_nulls(), array_in(), CStringGetDatum(), DatumGetArrayTypeP, ErrorData::elevel, ereport, errcode(), errmsg, ErrorSaveContext::error_data, ErrorSaveContext::error_occurred, fb(), FunctionCallInvoke, ErrorData::hint, InitFunctionCallInfoData, initStringInfo(), Int32GetDatum(), InvalidOid, LOCAL_FCINFO, ObjectIdGetDatum(), pfree(), result, ThrowErrorData(), ErrorSaveContext::type, and WARNING.

Referenced by import_pg_statistic().

◆ check_all_expr_argnames_valid()

static bool check_all_expr_argnames_valid ( JsonbContainer cont,
AttrNumber  exprnum 
)
static

Definition at line 900 of file extended_stats_funcs.c.

901{
902 bool all_keys_valid = true;
903
907
909
911
912 /* We always start off with a BEGIN OBJECT */
913 jitok = JsonbIteratorNext(&jbit, &jkey, false);
915
916 while (true)
917 {
919
920 jitok = JsonbIteratorNext(&jbit, &jkey, false);
921
922 /*
923 * We have run of keys. This is the only condition where it is
924 * memory-safe to break out of the loop.
925 */
926 if (jitok == WJB_END_OBJECT)
927 break;
928
929 /* We can only find keys inside an object */
930 Assert(jitok == WJB_KEY);
931 Assert(jkey.type == jbvString);
932
933 /* A value must follow the key */
934 jitok = JsonbIteratorNext(&jbit, &jval, false);
936
937 /*
938 * If we have already found an invalid key, there is no point in
939 * looking for more, because additional WARNINGs are just clutter. We
940 * must continue iterating over the json to ensure that we clean up
941 * all allocated memory.
942 */
943 if (!all_keys_valid)
944 continue;
945
947 {
949
952 errmsg("could not import element in expression %d: invalid key name",
953 exprnum));
954
956 all_keys_valid = false;
957 }
958 }
959 return all_keys_valid;
960}
#define Assert(condition)
Definition c.h:943
static bool key_in_expr_argnames(JsonbValue *key)
static char * jbv_string_get_cstr(JsonbValue *jval)
@ jbvString
Definition jsonb.h:231
#define JsonContainerIsObject(jc)
Definition jsonb.h:210
JsonbIteratorToken
Definition jsonb.h:21
@ WJB_KEY
Definition jsonb.h:23
@ WJB_VALUE
Definition jsonb.h:24
@ WJB_END_OBJECT
Definition jsonb.h:29
@ WJB_BEGIN_OBJECT
Definition jsonb.h:28
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition jsonb_util.c:935
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition jsonb_util.c:973

References Assert, ereport, errcode(), errmsg, fb(), jbv_string_get_cstr(), jbvString, JsonbIteratorInit(), JsonbIteratorNext(), JsonContainerIsObject, key_in_expr_argnames(), pfree(), WARNING, WJB_BEGIN_OBJECT, WJB_END_OBJECT, WJB_KEY, and WJB_VALUE.

Referenced by import_pg_statistic().

◆ check_mcvlist_array()

static bool check_mcvlist_array ( const ArrayType arr,
int  argindex,
int  required_ndims,
int  mcv_length 
)
static

Definition at line 773 of file extended_stats_funcs.c.

775{
776 if (ARR_NDIM(arr) != required_ndims)
777 {
780 errmsg("could not parse array \"%s\": incorrect number of dimensions (%d required)",
781 extarginfo[argindex].argname, required_ndims));
782 return false;
783 }
784
785 if (array_contains_nulls(arr))
786 {
789 errmsg("could not parse array \"%s\": NULL value found",
790 extarginfo[argindex].argname));
791 return false;
792 }
793
794 if (ARR_DIMS(arr)[0] != mcv_length)
795 {
798 errmsg("could not parse array \"%s\": incorrect number of elements (same as \"%s\" required)",
799 extarginfo[argindex].argname,
801 return false;
802 }
803
804 return true;
805}
#define ARR_DIMS(a)
Definition array.h:294
static struct StatsArgInfo extarginfo[]

References StatsArgInfo::argname, ARR_DIMS, ARR_NDIM, array_contains_nulls(), ereport, errcode(), errmsg, extarginfo, fb(), MOST_COMMON_VALS_ARG, and WARNING.

Referenced by import_mcv().

◆ delete_pg_statistic_ext_data()

static bool delete_pg_statistic_ext_data ( Oid  stxoid,
bool  inherited 
)
static

Definition at line 1688 of file extended_stats_funcs.c.

1689{
1692 bool result = false;
1693
1694 /* Is there already a pg_statistic_ext_data tuple for this attribute? */
1698
1700 {
1701 CatalogTupleDelete(sed, &oldtup->t_self);
1703 result = true;
1704 }
1705
1707
1709
1710 return result;
1711}
#define HeapTupleIsValid(tuple)
Definition htup.h:78
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition indexing.c:365
#define RowExclusiveLock
Definition lockdefs.h:38
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache2(SysCacheIdentifier cacheId, Datum key1, Datum key2)
Definition syscache.c:231
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

References BoolGetDatum(), CatalogTupleDelete(), CommandCounterIncrement(), fb(), HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), result, RowExclusiveLock, SearchSysCache2(), table_close(), and table_open().

Referenced by pg_clear_extended_stats().

◆ expand_stxkind()

static void expand_stxkind ( HeapTuple  tup,
StakindFlags enabled 
)
static

Definition at line 226 of file extended_stats_funcs.c.

227{
228 Datum datum;
229 ArrayType *arr;
230 char *kinds;
231
233 tup,
235 arr = DatumGetArrayTypeP(datum);
236 if (ARR_NDIM(arr) != 1 || ARR_HASNULL(arr) || ARR_ELEMTYPE(arr) != CHAROID)
237 elog(ERROR, "stxkind is not a one-dimension char array");
238
239 kinds = (char *) ARR_DATA_PTR(arr);
240
241 for (int i = 0; i < ARR_DIMS(arr)[0]; i++)
242 {
243 switch (kinds[i])
244 {
246 enabled->ndistinct = true;
247 break;
249 enabled->dependencies = true;
250 break;
251 case STATS_EXT_MCV:
252 enabled->mcv = true;
253 break;
255 enabled->expressions = true;
256 break;
257 default:
258 elog(ERROR, "incorrect stxkind %c found", kinds[i]);
259 break;
260 }
261 }
262}
#define ARR_DATA_PTR(a)
Definition array.h:322
#define ARR_ELEMTYPE(a)
Definition array.h:292
#define ARR_HASNULL(a)
Definition array.h:291
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
int i
Definition isn.c:77
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:626

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, DatumGetArrayTypeP, StakindFlags::dependencies, elog, ERROR, StakindFlags::expressions, fb(), i, StakindFlags::mcv, StakindFlags::ndistinct, and SysCacheGetAttrNotNull().

Referenced by extended_statistics_update().

◆ extended_statistics_update()

static bool extended_statistics_update ( FunctionCallInfo  fcinfo)
static

Definition at line 314 of file extended_stats_funcs.c.

315{
316 char *relnspname;
317 char *relname;
318 Oid nspoid;
319 char *nspname;
320 char *stxname;
321 bool inherited;
324
325 StakindFlags enabled = {false, false, false, false};
326 StakindFlags has = {false, false, false, false};
327
329
331 bool nulls[Natts_pg_statistic_ext_data] = {0};
333 bool success = true;
335 bool isnull;
336 List *exprs = NIL;
337 int numattnums = 0;
338 int numexprs = 0;
339 int numattrs = 0;
340
341 /* arrays of type info, if we need them */
342 Oid *atttypids = NULL;
343 int32 *atttypmods = NULL;
345 Oid relid;
347
348 /*
349 * Fill out the StakindFlags "has" structure based on which parameters
350 * were provided to the function.
351 *
352 * The MCV stats composite value is an array of record type, but this is
353 * externally represented as three arrays that must be interleaved into
354 * the array of records (pg_stats_ext stores four arrays,
355 * most_common_val_nulls is built from the contents of most_common_vals).
356 * Therefore, none of the three array values is meaningful unless the
357 * other two are also present and in sync in terms of array length.
358 */
362 has.ndistinct = !PG_ARGISNULL(NDISTINCT_ARG);
363 has.dependencies = !PG_ARGISNULL(DEPENDENCIES_ARG);
364 has.expressions = !PG_ARGISNULL(EXPRESSIONS_ARG);
365
366 if (RecoveryInProgress())
367 {
370 errmsg("recovery is in progress"),
371 errhint("Statistics cannot be modified during recovery."));
372 return false;
373 }
374
375 /* relation arguments */
380
381 /* extended statistics arguments */
388
389 /*
390 * First open the relation where we expect to find the statistics. This
391 * is similar to relation and attribute statistics, so as ACL checks are
392 * done before any locks are taken, even before any attempts related to
393 * the extended stats object.
394 */
398
399 nspoid = get_namespace_oid(nspname, true);
400 if (nspoid == InvalidOid)
401 {
404 errmsg("could not find schema \"%s\"", nspname));
405 success = false;
406 goto cleanup;
407 }
408
411
412 if (!HeapTupleIsValid(tup))
413 {
416 errmsg("could not find extended statistics object \"%s.%s\"",
417 nspname, stxname));
418 success = false;
419 goto cleanup;
420 }
421
423
424 /*
425 * The relation tracked by the stats object has to match with the relation
426 * we have already locked.
427 */
428 if (stxform->stxrelid != relid)
429 {
432 errmsg("could not restore extended statistics object \"%s.%s\": incorrect relation \"%s.%s\" specified",
433 nspname, stxname,
435
436 success = false;
437 goto cleanup;
438 }
439
440 /* Find out what extended statistics kinds we should expect. */
441 expand_stxkind(tup, &enabled);
442 numattnums = stxform->stxkeys.dim1;
443
444 /* decode expression (if any) */
446 tup,
448 &isnull);
449 if (!isnull)
450 {
451 char *s;
452
454 exprs = (List *) stringToNode(s);
455 pfree(s);
456
457 /*
458 * Run the expressions through eval_const_expressions(). This is not
459 * just an optimization, but is necessary, because the planner will be
460 * comparing them to similarly-processed qual clauses, and may fail to
461 * detect valid matches without this.
462 *
463 * We must not use canonicalize_qual(), however, since these are not
464 * qual expressions.
465 */
466 exprs = (List *) eval_const_expressions(NULL, (Node *) exprs);
467
468 /* May as well fix opfuncids too */
469 fix_opfuncids((Node *) exprs);
470
471 /* Compute the number of expression, for input validation. */
472 numexprs = list_length(exprs);
473 }
474
476
477 /*
478 * If the object cannot support ndistinct, we should not have data for it.
479 */
480 if (has.ndistinct && !enabled.ndistinct)
481 {
484 errmsg("cannot specify parameter \"%s\"",
485 extarginfo[NDISTINCT_ARG].argname),
486 errhint("Extended statistics object \"%s.%s\" does not support statistics of this type.",
487 nspname, stxname));
488
489 has.ndistinct = false;
490 success = false;
491 }
492
493 /*
494 * If the object cannot support dependencies, we should not have data for
495 * it.
496 */
497 if (has.dependencies && !enabled.dependencies)
498 {
501 errmsg("cannot specify parameter \"%s\"",
503 errhint("Extended statistics object \"%s.%s\" does not support statistics of this type.",
504 nspname, stxname));
505 has.dependencies = false;
506 success = false;
507 }
508
509 /*
510 * If the object cannot hold an MCV value, but any of the MCV parameters
511 * are set, then issue a WARNING and ensure that we do not try to load MCV
512 * stats later. In pg_stats_ext, most_common_val_nulls, most_common_freqs
513 * and most_common_base_freqs are NULL if most_common_vals is NULL.
514 */
515 if (!enabled.mcv)
516 {
520 {
523 errmsg("cannot specify parameters \"%s\", \"%s\", or \"%s\"",
527 errhint("Extended statistics object \"%s.%s\" does not support statistics of this type.",
528 nspname, stxname));
529
530 has.mcv = false;
531 success = false;
532 }
533 }
534 else if (!has.mcv)
535 {
536 /*
537 * If we do not have all of the MCV arrays set while the extended
538 * statistics object expects something, something is wrong. This
539 * issues a WARNING if a partial input has been provided.
540 */
544 {
547 errmsg("could not use \"%s\", \"%s\", and \"%s\": missing one or more parameters",
551 success = false;
552 }
553 }
554
555 /*
556 * If the object cannot support expressions, we should not have data for
557 * them.
558 */
559 if (has.expressions && !enabled.expressions)
560 {
563 errmsg("cannot specify parameter \"%s\"",
564 extarginfo[EXPRESSIONS_ARG].argname),
565 errhint("Extended statistics object \"%s.%s\" does not support statistics of this type.",
566 nspname, stxname));
567
568 has.expressions = false;
569 success = false;
570 }
571
572 /*
573 * Either of these statistic types requires that we supply a semi-filled
574 * VacAttrStatsP array.
575 *
576 * It is not possible to use the existing lookup_var_attr_stats() and
577 * examine_attribute() because these functions will skip attributes where
578 * attstattarget is 0, and we may have statistics data to import for those
579 * attributes.
580 */
581 if (has.mcv || has.expressions)
582 {
584 atttypmods = palloc0_array(int32, numattrs);
586
587 /*
588 * The leading stxkeys are attribute numbers up through numattnums.
589 * These keys must be in ascending AttrNumber order, but we do not
590 * rely on that.
591 */
592 for (int i = 0; i < numattnums; i++)
593 {
594 AttrNumber attnum = stxform->stxkeys.values[i];
596 ObjectIdGetDatum(relid),
598
600
601 /* Attribute not found */
603 elog(ERROR, "stxkeys references nonexistent attnum %d", attnum);
604
606
607 if (attr->attisdropped)
608 elog(ERROR, "stxkeys references dropped attnum %d", attnum);
609
610 atttypids[i] = attr->atttypid;
611 atttypmods[i] = attr->atttypmod;
612 atttypcolls[i] = attr->attcollation;
614 }
615
616 /*
617 * After all the positive number attnums in stxkeys come the negative
618 * numbers (if any) which represent expressions in the order that they
619 * appear in stxdexpr. Because the expressions are always
620 * monotonically decreasing from -1, there is no point in looking at
621 * the values in stxkeys, it's enough to know how many of them there
622 * are.
623 */
624 for (int i = numattnums; i < numattrs; i++)
625 {
626 Node *expr = list_nth(exprs, i - numattnums);
627
628 atttypids[i] = exprType(expr);
629 atttypmods[i] = exprTypmod(expr);
630 atttypcolls[i] = exprCollation(expr);
631 }
632 }
633
634 /*
635 * Populate the pg_statistic_ext_data result tuple.
636 */
637
638 /* Primary Key: cannot be NULL or replaced. */
640 nulls[Anum_pg_statistic_ext_data_stxoid - 1] = false;
643
644 /* All unspecified parameters will be left unmodified */
647 nulls[Anum_pg_statistic_ext_data_stxdmcv - 1] = true;
648 nulls[Anum_pg_statistic_ext_data_stxdexpr - 1] = true;
649
650 /*
651 * For each stats kind, deserialize the data at hand and perform a round
652 * of validation. The resulting tuple is filled with a set of updated
653 * values.
654 */
655
656 if (has.ndistinct)
657 {
661
662 if (statext_ndistinct_validate(ndistinct, &stxform->stxkeys,
664 {
668 }
669 else
670 success = false;
671
672 statext_ndistinct_free(ndistinct);
673 }
674
675 if (has.dependencies)
676 {
680
681 if (statext_dependencies_validate(dependencies, &stxform->stxkeys,
683 {
687 }
688 else
689 success = false;
690
691 statext_dependencies_free(dependencies);
692 }
693
694 if (has.mcv)
695 {
696 Datum datum;
697 bool val_ok = false;
698
702 atttypids, atttypmods, atttypcolls, numattrs,
703 &val_ok);
704
705 if (val_ok)
706 {
707 Assert(datum != (Datum) 0);
709 nulls[Anum_pg_statistic_ext_data_stxdmcv - 1] = false;
711 }
712 else
713 success = false;
714 }
715
716 if (has.expressions)
717 {
718 Datum datum;
720 bool ok = false;
721
723
724 /*
725 * Generate the expressions array.
726 *
727 * The atttypids, atttypmods, and atttypcolls arrays have all the
728 * regular attributes listed first, so we can pass those arrays with a
729 * start point after the last regular attribute. There are numexprs
730 * elements remaining.
731 */
734 &atttypmods[numattnums],
737 &ok);
738
740
741 if (ok)
742 {
743 Assert(datum != (Datum) 0);
746 nulls[Anum_pg_statistic_ext_data_stxdexpr - 1] = false;
747 }
748 else
749 success = false;
750 }
751
753
754cleanup:
757 if (pg_stext != NULL)
759 if (atttypids != NULL)
761 if (atttypmods != NULL)
762 pfree(atttypmods);
763 if (atttypcolls != NULL)
765 return success;
766}
#define PG_GETARG_ARRAYTYPE_P(n)
Definition array.h:263
int16 AttrNumber
Definition attnum.h:21
static Datum values[MAXATTR]
Definition bootstrap.c:190
static void cleanup(void)
Definition bootstrap.c:886
#define TextDatumGetCString(d)
Definition builtins.h:99
int32_t int32
Definition c.h:620
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition clauses.c:2500
MVDependencies * statext_dependencies_deserialize(bytea *data)
bool statext_dependencies_validate(const MVDependencies *dependencies, const int2vector *stxkeys, int numexprs, int elevel)
void statext_dependencies_free(MVDependencies *dependencies)
int errhint(const char *fmt,...) pg_attribute_printf(1
static void upsert_pg_statistic_ext_data(const Datum *values, const bool *nulls, const bool *replaces)
static Datum import_expressions(Relation pgsd, int numexprs, Oid *atttypids, int32 *atttypmods, Oid *atttypcolls, Jsonb *exprs_jsonb, bool *exprs_is_perfect)
static void expand_stxkind(HeapTuple tup, StakindFlags *enabled)
static HeapTuple get_pg_statistic_ext(Relation pg_stext, Oid nspoid, const char *stxname)
static Datum import_mcv(const ArrayType *mcv_arr, const ArrayType *freqs_arr, const ArrayType *base_freqs_arr, Oid *atttypids, int32 *atttypmods, Oid *atttypcolls, int numattrs, bool *ok)
#define palloc0_array(type, count)
Definition fe_memutils.h:92
#define DatumGetByteaPP(X)
Definition fmgr.h:292
#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
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
static void * GETSTRUCT(const HeapTupleData *tuple)
static bool success
Definition initdb.c:188
#define PG_GETARG_JSONB_P(x)
Definition jsonb.h:418
#define ShareUpdateExclusiveLock
Definition lockdefs.h:39
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition makefuncs.c:473
void statext_ndistinct_free(MVNDistinct *ndistinct)
Definition mvdistinct.c:332
MVNDistinct * statext_ndistinct_deserialize(bytea *data)
Definition mvdistinct.c:247
bool statext_ndistinct_validate(const MVNDistinct *ndistinct, const int2vector *stxkeys, int numexprs, int elevel)
Definition mvdistinct.c:352
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition namespace.c:3607
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition namespace.c:442
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition nodeFuncs.c:304
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:826
void fix_opfuncids(Node *node)
Definition nodeFuncs.c:1859
int16 attnum
FormData_pg_attribute * Form_pg_attribute
NameData relname
Definition pg_class.h:40
const void * data
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
static void * list_nth(const List *list, int n)
Definition pg_list.h:331
END_CATALOG_STRUCT typedef FormData_pg_statistic_ext * Form_pg_statistic_ext
static Datum Int16GetDatum(int16 X)
Definition postgres.h:172
unsigned int Oid
void * stringToNode(const char *str)
Definition read.c:90
void RangeVarCallbackForStats(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition stat_utils.c:142
void stats_check_required_arg(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum)
Definition stat_utils.c:51
Definition pg_list.h:54
Definition c.h:776
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:596
bool RecoveryInProgress(void)
Definition xlog.c:6832

References StatsArgInfo::argname, Assert, attnum, BoolGetDatum(), cleanup(), data, DatumGetByteaPP, StakindFlags::dependencies, DEPENDENCIES_ARG, elog, ereport, errcode(), errhint(), errmsg, ERROR, eval_const_expressions(), expand_stxkind(), exprCollation(), StakindFlags::expressions, EXPRESSIONS_ARG, exprType(), exprTypmod(), extarginfo, fb(), fix_opfuncids(), Form_pg_statistic_ext, get_namespace_oid(), get_pg_statistic_ext(), GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, i, import_expressions(), import_mcv(), INHERITED_ARG, Int16GetDatum(), InvalidOid, list_length(), list_nth(), makeRangeVar(), StakindFlags::mcv, MOST_COMMON_BASE_FREQS_ARG, MOST_COMMON_FREQS_ARG, MOST_COMMON_VALS_ARG, StakindFlags::ndistinct, NDISTINCT_ARG, NIL, ObjectIdGetDatum(), palloc0_array, pfree(), PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_GETARG_BOOL, PG_GETARG_DATUM, PG_GETARG_JSONB_P, RangeVarCallbackForStats(), RangeVarGetRelidExtended(), RecoveryInProgress(), ReleaseSysCache(), relname, RELNAME_ARG, RELSCHEMA_ARG, RowExclusiveLock, SearchSysCache2(), ShareUpdateExclusiveLock, statext_dependencies_deserialize(), statext_dependencies_free(), statext_dependencies_validate(), statext_ndistinct_deserialize(), statext_ndistinct_free(), statext_ndistinct_validate(), STATNAME_ARG, stats_check_required_arg(), STATSCHEMA_ARG, stringToNode(), success, SysCacheGetAttr(), table_close(), table_open(), TextDatumGetCString, upsert_pg_statistic_ext_data(), values, and WARNING.

Referenced by pg_restore_extended_stats().

◆ get_pg_statistic_ext()

static HeapTuple get_pg_statistic_ext ( Relation  pg_stext,
Oid  nspoid,
const char stxname 
)
static

Definition at line 178 of file extended_stats_funcs.c.

179{
180 ScanKeyData key[2];
181 SysScanDesc scan;
184
185 ScanKeyInit(&key[0],
188 F_NAMEEQ,
190 ScanKeyInit(&key[1],
193 F_OIDEQ,
195
196 /*
197 * Try to find matching pg_statistic_ext row.
198 */
201 true,
202 NULL,
203 2,
204 key);
205
206 /* Lookup is based on a unique index, so we get either 0 or 1 tuple. */
207 tup = systable_getnext(scan);
208
211
212 systable_endscan(scan);
213
214 if (!OidIsValid(stxoid))
215 return NULL;
216
218}
#define OidIsValid(objectId)
Definition c.h:858
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:612
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:523
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
#define BTEqualStrategyNumber
Definition stratnum.h:31
#define SearchSysCacheCopy1(cacheId, key1)
Definition syscache.h:91

References BTEqualStrategyNumber, CStringGetDatum(), fb(), Form_pg_statistic_ext, GETSTRUCT(), HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), OidIsValid, ScanKeyInit(), SearchSysCacheCopy1, systable_beginscan(), systable_endscan(), and systable_getnext().

Referenced by extended_statistics_update(), and pg_clear_extended_stats().

◆ import_expressions()

static Datum import_expressions ( Relation  pgsd,
int  numexprs,
Oid atttypids,
int32 atttypmods,
Oid atttypcolls,
Jsonb exprs_jsonb,
bool exprs_is_perfect 
)
static

Definition at line 1558 of file extended_stats_funcs.c.

1562{
1563 const char *argname = extarginfo[EXPRESSIONS_ARG].argname;
1565 ArrayBuildState *astate = NULL;
1566 Datum result = (Datum) 0;
1567 int num_import_ok = 0;
1570
1572
1573 *exprs_is_perfect = false;
1574
1575 /* Json schema must be [{expr},...] */
1577 {
1580 errmsg("could not parse \"%s\": root-level array required", argname));
1581 goto exprs_error;
1582 }
1583
1584 root = &exprs_jsonb->root;
1585
1586 /*
1587 * The number of elements in the array must match the number of
1588 * expressions in the stats object definition.
1589 */
1592 {
1595 errmsg("could not parse \"%s\": incorrect number of elements (%d required)",
1596 argname, numexprs));
1597 goto exprs_error;
1598 }
1599
1601
1602 /*
1603 * Iterate over each expected expression object in the array. Some of
1604 * them could be null. If the element is a completely wrong data type,
1605 * give a WARNING and then treat the element like a NULL element in the
1606 * result array.
1607 *
1608 * Each expression *MUST* have a value appended in the result pg_statistic
1609 * array.
1610 */
1611 for (int i = 0; i < numexprs; i++)
1612 {
1613 Datum pgstdat = (Datum) 0;
1614 bool isnull = false;
1615 AttrNumber exprattnum = -1 - i;
1616
1618
1619 switch (elem->type)
1620 {
1621 case jbvBinary:
1622 {
1623 bool sta_ok = false;
1624
1625 /* a real stats object */
1626 pgstdat = import_pg_statistic(pgsd, elem->val.binary.data,
1628 atttypids[i], atttypmods[i],
1629 atttypcolls[i], &sta_ok);
1630
1631 /*
1632 * If some incorrect data has been found, assign NULL for
1633 * this expression as a mean to give up.
1634 */
1635 if (sta_ok)
1636 num_import_ok++;
1637 else
1638 {
1639 isnull = true;
1640 pgstdat = (Datum) 0;
1641 }
1642 }
1643 break;
1644
1645 case jbvNull:
1646 /* NULL placeholder for invalid data, still fine */
1647 isnull = true;
1648 num_import_ok++;
1649 break;
1650
1651 default:
1652 /* cannot possibly be valid */
1655 errmsg("could not parse \"%s\": invalid element in expression %d",
1656 argname, exprattnum));
1657 goto exprs_error;
1658 }
1659
1660 astate = accumArrayResult(astate, pgstdat, isnull, pgstypoid,
1662 }
1663
1664 /*
1665 * The expressions datum is perfect *if and only if* all of the
1666 * pg_statistic elements were also ok, for a number of elements equal to
1667 * the number of expressions. Anything else means a failure in restoring
1668 * the data of this statistics object.
1669 */
1671
1672 if (astate != NULL)
1674
1675 return result;
1676
1678 if (astate != NULL)
1679 pfree(astate);
1680 return (Datum) 0;
1681};
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
static Datum import_pg_statistic(Relation pgsd, JsonbContainer *cont, AttrNumber exprnum, FmgrInfo *array_in_fn, Oid typid, int32 typmod, Oid typcoll, bool *pg_statistic_ok)
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition fmgr.c:129
@ jbvBinary
Definition jsonb.h:238
@ jbvNull
Definition jsonb.h:230
#define JsonContainerSize(jc)
Definition jsonb.h:208
#define JB_ROOT_IS_ARRAY(jbp_)
Definition jsonb.h:224
JsonbValue * getIthJsonbValueFromContainer(JsonbContainer *container, uint32 i)
Definition jsonb_util.c:472
Oid get_rel_type_id(Oid relid)
Definition lsyscache.c:2210
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
tree ctl root
Definition radixtree.h:1857
enum jbvType type
Definition jsonb.h:257
char * val
Definition jsonb.h:266
const char * argname
Definition stat_utils.h:24

References accumArrayResult(), StatsArgInfo::argname, CurrentMemoryContext, ereport, errcode(), errmsg, EXPRESSIONS_ARG, extarginfo, fb(), fmgr_info(), get_rel_type_id(), getIthJsonbValueFromContainer(), i, import_pg_statistic(), JB_ROOT_IS_ARRAY, jbvBinary, jbvNull, JsonContainerSize, makeArrayResult(), pfree(), result, root, JsonbValue::type, JsonbValue::val, and WARNING.

Referenced by extended_statistics_update().

◆ import_mcv()

static Datum import_mcv ( const ArrayType mcv_arr,
const ArrayType freqs_arr,
const ArrayType base_freqs_arr,
Oid atttypids,
int32 atttypmods,
Oid atttypcolls,
int  numattrs,
bool ok 
)
static

Definition at line 813 of file extended_stats_funcs.c.

816{
817 int nitems;
819 bool *mcv_nulls;
820 int check_nummcv;
821 Datum mcv = (Datum) 0;
822
823 *ok = false;
824
825 /*
826 * mcv_arr is an array of arrays. Each inner array must have the same
827 * number of elements "numattrs".
828 */
829 if (ARR_NDIM(mcv_arr) != 2)
830 {
833 errmsg("could not parse array \"%s\": incorrect number of dimensions (%d required)",
834 extarginfo[MOST_COMMON_VALS_ARG].argname, 2));
835 goto mcv_error;
836 }
837
838 if (ARR_DIMS(mcv_arr)[1] != numattrs)
839 {
842 errmsg("could not parse array \"%s\": found %d attributes but expected %d",
845 goto mcv_error;
846 }
847
848 /*
849 * "most_common_freqs" and "most_common_base_freqs" arrays must be of the
850 * same length, one-dimension and cannot contain NULLs. We use mcv_arr as
851 * the reference array for determining their length.
852 */
853 nitems = ARR_DIMS(mcv_arr)[0];
856 {
857 /* inconsistent input arrays found */
858 goto mcv_error;
859 }
860
861 /*
862 * This part builds the contents for "most_common_val_nulls", based on the
863 * values from "most_common_vals".
864 */
867
869 atttypids, atttypmods, atttypcolls,
873
874 *ok = (mcv != (Datum) 0);
875
877 return mcv;
878}
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
double float8
Definition c.h:714
static bool check_mcvlist_array(const ArrayType *arr, int argindex, int required_ndims, int mcv_length)
#define nitems(x)
Definition indent.h:31
Datum statext_mcv_import(int elevel, int numattrs, Oid *atttypids, int32 *atttypmods, Oid *atttypcolls, int nitems, Datum *mcv_elems, bool *mcv_nulls, float8 *freqs, float8 *base_freqs)
Definition mcv.c:2204

References StatsArgInfo::argname, ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, check_mcvlist_array(), deconstruct_array_builtin(), ereport, errcode(), errmsg, extarginfo, fb(), MOST_COMMON_BASE_FREQS_ARG, MOST_COMMON_FREQS_ARG, MOST_COMMON_VALS_ARG, nitems, statext_mcv_import(), and WARNING.

Referenced by extended_statistics_update().

◆ import_pg_statistic()

static Datum import_pg_statistic ( Relation  pgsd,
JsonbContainer cont,
AttrNumber  exprnum,
FmgrInfo array_in_fn,
Oid  typid,
int32  typmod,
Oid  typcoll,
bool pg_statistic_ok 
)
static

Definition at line 1108 of file extended_stats_funcs.c.

1112{
1113 const char *argname = extarginfo[EXPRESSIONS_ARG].argname;
1114 TypeCacheEntry *typcache;
1116 bool nulls[Natts_pg_statistic];
1119 Datum pgstdat = (Datum) 0;
1122 bool found[NUM_ATTRIBUTE_STATS_ELEMS] = {0};
1124
1125 /* Assume the worst by default. */
1126 *pg_statistic_ok = false;
1127
1129 {
1132 errmsg("could not parse \"%s\": invalid element in expression %d",
1133 argname, exprnum));
1134 goto pg_statistic_error;
1135 }
1136
1137 /*
1138 * Loop through all keys that we need to look up. If any value found is
1139 * neither a string nor a NULL, there is not much we can do, so just give
1140 * on the entire tuple for this expression.
1141 */
1142 for (int i = 0; i < NUM_ATTRIBUTE_STATS_ELEMS; i++)
1143 {
1144 const char *s = extexprargname[i];
1145 int len = strlen(s);
1146
1148 continue;
1149
1150 switch (val[i].type)
1151 {
1152 case jbvString:
1153 found[i] = true;
1154 break;
1155
1156 case jbvNull:
1157 break;
1158
1159 default:
1162 errmsg("could not parse \"%s\": invalid element in expression %d", argname, exprnum),
1163 errhint("Value of element \"%s\" must be type a null or a string.", s));
1164 goto pg_statistic_error;
1165 }
1166 }
1167
1168 /* Look for invalid keys */
1170 goto pg_statistic_error;
1171
1172 /*
1173 * There are two arg pairs, MCV+MCF and MCEV+MCEF. Both values must
1174 * either be found or not be found. Any disagreement is a warning. Once
1175 * we have ruled out disagreeing pairs, we can use either found flag as a
1176 * proxy for the other.
1177 */
1178 if (found[MOST_COMMON_VALS_ELEM] != found[MOST_COMMON_FREQS_ELEM])
1179 {
1182 errmsg("could not parse \"%s\": invalid element in expression %d",
1183 argname, exprnum),
1184 errhint("\"%s\" and \"%s\" must be both either strings or nulls.",
1187 goto pg_statistic_error;
1188 }
1190 {
1193 errmsg("could not parse \"%s\": invalid element in expression %d",
1194 argname, exprnum),
1195 errhint("\"%s\" and \"%s\" must be both either strings or nulls.",
1198 goto pg_statistic_error;
1199 }
1200
1201 /*
1202 * Range types may expect three values to be set. All three of them must
1203 * either be found or not be found. Any disagreement is a warning.
1204 */
1207 {
1210 errmsg("could not parse \"%s\": invalid element in expression %d",
1211 argname, exprnum),
1212 errhint("\"%s\", \"%s\", and \"%s\" must be all either strings or all nulls.",
1216 goto pg_statistic_error;
1217 }
1218
1219 /* This finds the right operators even if atttypid is a domain */
1221
1223 values, nulls, replaces);
1224
1225 /*
1226 * Special case: collation for tsvector is DEFAULT_COLLATION_OID. See
1227 * compute_tsvector_stats().
1228 */
1229 if (typid == TSVECTOROID)
1231
1232 /*
1233 * We only need to fetch element type and eq operator if we have a stat of
1234 * type MCELEM or DECHIST, otherwise the values are unnecessary and not
1235 * meaningful.
1236 */
1238 {
1239 if (!statatt_get_elem_type(typid, typcache->typtype,
1240 &elemtypid, &elemeqopr))
1241 {
1244 errmsg("could not parse \"%s\": invalid element type in expression %d",
1245 argname, exprnum));
1246 goto pg_statistic_error;
1247 }
1248 }
1249
1250 /*
1251 * These three fields can only be set if dealing with a range or
1252 * multi-range type.
1253 */
1254 if (found[RANGE_LENGTH_HISTOGRAM_ELEM] ||
1255 found[RANGE_EMPTY_FRAC_ELEM] ||
1257 {
1258 if (typcache->typtype != TYPTYPE_RANGE &&
1259 typcache->typtype != TYPTYPE_MULTIRANGE)
1260 {
1263 errmsg("could not parse \"%s\": invalid data in expression %d",
1264 argname, exprnum),
1265 errhint("\"%s\", \"%s\", and \"%s\" can only be set for a range type.",
1269 goto pg_statistic_error;
1270 }
1271 }
1272
1273 /* null_frac */
1274 if (found[NULL_FRAC_ELEM])
1275 {
1276 Datum datum;
1277
1281 else
1282 goto pg_statistic_error;
1283 }
1284
1285 /* avg_width */
1286 if (found[AVG_WIDTH_ELEM])
1287 {
1288 Datum datum;
1289
1293 else
1294 goto pg_statistic_error;
1295 }
1296
1297 /* n_distinct */
1298 if (found[N_DISTINCT_ELEM])
1299 {
1300 Datum datum;
1301
1305 else
1306 goto pg_statistic_error;
1307 }
1308
1309 /*
1310 * The STAKIND statistics are the same as the ones found in attribute
1311 * stats. However, these are all derived from json strings, whereas the
1312 * ones derived for attribute stats are a mix of datatypes. This limits
1313 * the opportunities for code sharing between the two.
1314 *
1315 * Some statistic kinds have both a stanumbers and a stavalues components.
1316 * In those cases, both values must either be NOT NULL or both NULL, and
1317 * if they aren't then we need to reject that stakind completely.
1318 * Currently we go a step further and reject the expression array
1319 * completely.
1320 */
1321
1322 if (found[MOST_COMMON_VALS_ELEM])
1323 {
1324 Datum stavalues;
1325 Datum stanumbers;
1326 bool val_ok = false;
1327 bool num_ok = false;
1328 char *s;
1329
1331 stavalues = array_in_safe(array_in_fn, s, typid, typmod, exprnum,
1333 &val_ok);
1334
1335 pfree(s);
1336
1338 stanumbers = array_in_safe(array_in_fn, s, FLOAT4OID, -1, exprnum,
1340 &num_ok);
1341 pfree(s);
1342
1343 /* Only set the slot if both datums have been built */
1344 if (val_ok && num_ok)
1345 {
1347 ArrayType *nums_arr = DatumGetArrayTypeP(stanumbers);
1348 int nvals = ARR_DIMS(vals_arr)[0];
1349 int nnums = ARR_DIMS(nums_arr)[0];
1350
1351 if (nvals != nnums)
1352 {
1355 errmsg("could not parse \"%s\": incorrect number of elements (same as \"%s\" required)",
1356 "most_common_vals",
1357 "most_common_freqs")));
1358 goto pg_statistic_error;
1359 }
1360
1363 typcache->eq_opr, typcoll,
1364 stanumbers, false, stavalues, false);
1365 }
1366 else
1367 goto pg_statistic_error;
1368 }
1369
1370 /* STATISTIC_KIND_HISTOGRAM */
1371 if (found[HISTOGRAM_BOUNDS_ELEM])
1372 {
1373 Datum stavalues;
1374 bool val_ok = false;
1376
1377 stavalues = array_in_safe(array_in_fn, s, typid, typmod, exprnum,
1379 &val_ok);
1380 pfree(s);
1381
1382 if (val_ok)
1385 typcache->lt_opr, typcoll,
1386 0, true, stavalues, false);
1387 else
1388 goto pg_statistic_error;
1389 }
1390
1391 /* STATISTIC_KIND_CORRELATION */
1392 if (found[CORRELATION_ELEM])
1393 {
1394 Datum corr[] = {(Datum) 0};
1395
1398 {
1400 Datum stanumbers = PointerGetDatum(arry);
1401
1404 typcache->lt_opr, typcoll,
1405 stanumbers, false, 0, true);
1406 }
1407 else
1408 goto pg_statistic_error;
1409 }
1410
1411 /* STATISTIC_KIND_MCELEM */
1412 if (found[MOST_COMMON_ELEMS_ELEM])
1413 {
1414 Datum stavalues;
1415 Datum stanumbers;
1416 bool val_ok = false;
1417 bool num_ok = false;
1418 char *s;
1419
1421 stavalues = array_in_safe(array_in_fn, s, elemtypid, typmod, exprnum,
1423 &val_ok);
1424 pfree(s);
1425
1426
1428 stanumbers = array_in_safe(array_in_fn, s, FLOAT4OID, -1, exprnum,
1430 &num_ok);
1431 pfree(s);
1432
1433 /* Only set the slot if both datums have been built */
1434 if (val_ok && num_ok)
1438 stanumbers, false, stavalues, false);
1439 else
1440 goto pg_statistic_error;
1441 }
1442
1443 /* STATISTIC_KIND_DECHIST */
1444 if (found[ELEM_COUNT_HISTOGRAM_ELEM])
1445 {
1446 Datum stanumbers;
1447 bool num_ok = false;
1448 char *s;
1449
1451 stanumbers = array_in_safe(array_in_fn, s, FLOAT4OID, -1, exprnum,
1453 &num_ok);
1454 pfree(s);
1455
1456 if (num_ok)
1458 elemeqopr, typcoll, stanumbers, false, 0, true);
1459 else
1460 goto pg_statistic_error;
1461 }
1462
1463 /*
1464 * STATISTIC_KIND_BOUNDS_HISTOGRAM
1465 *
1466 * This stakind appears before STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM even
1467 * though it is numerically greater, and all other stakinds appear in
1468 * numerical order.
1469 */
1470 if (found[RANGE_BOUNDS_HISTOGRAM_ELEM])
1471 {
1472 Datum stavalues;
1473 bool val_ok = false;
1474 char *s;
1475 Oid rtypid = typid;
1476
1477 /*
1478 * If it's a multirange, step down to the range type, as is done by
1479 * multirange_typanalyze().
1480 */
1481 if (type_is_multirange(typid))
1483
1485
1486 stavalues = array_in_safe(array_in_fn, s, rtypid, typmod, exprnum,
1488 &val_ok);
1489
1490 if (val_ok)
1494 0, true, stavalues, false);
1495 else
1496 goto pg_statistic_error;
1497 }
1498
1499 /* STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM */
1500 if (found[RANGE_LENGTH_HISTOGRAM_ELEM])
1501 {
1502 Datum empty_frac[] = {(Datum) 0};
1503 Datum stavalues;
1504 Datum stanumbers;
1505 bool val_ok = false;
1506 char *s;
1507
1510 {
1512
1513 stanumbers = PointerGetDatum(arry);
1514 }
1515 else
1516 goto pg_statistic_error;
1517
1519 stavalues = array_in_safe(array_in_fn, s, FLOAT8OID, -1, exprnum,
1521 &val_ok);
1522
1523 if (val_ok)
1527 stanumbers, false, stavalues, false);
1528 else
1529 goto pg_statistic_error;
1530 }
1531
1534
1536
1537 *pg_statistic_ok = true;
1538
1539 return pgstdat;
1540
1542 return (Datum) 0;
1543}
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
#define InvalidAttrNumber
Definition attnum.h:23
static bool jbv_to_infunc_datum(JsonbValue *jval, PGFunction func, AttrNumber exprnum, const char *argname, Datum *datum)
static Datum array_in_safe(FmgrInfo *array_in, const char *s, Oid typid, int32 typmod, AttrNumber exprnum, const char *element_name, bool *ok)
static bool check_all_expr_argnames_valid(JsonbContainer *cont, AttrNumber exprnum)
static const char * extexprargname[NUM_ATTRIBUTE_STATS_ELEMS]
Datum float4in(PG_FUNCTION_ARGS)
Definition float.c:205
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition heaptuple.c:989
long val
Definition informix.c:689
Datum int4in(PG_FUNCTION_ARGS)
Definition int.c:316
JsonbValue * getKeyJsonValueFromContainer(JsonbContainer *container, const char *keyVal, int keyLen, JsonbValue *res)
Definition jsonb_util.c:402
Oid get_multirange_range(Oid multirangeOid)
Definition lsyscache.c:3761
bool type_is_multirange(Oid typid)
Definition lsyscache.c:2931
const void size_t len
#define PointerGetDatum(X)
Definition postgres.h:354
#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
void statatt_init_empty_tuple(Oid reloid, int16 attnum, bool inherited, Datum *values, bool *nulls, bool *replaces)
Definition stat_utils.c:722
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
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:389
#define TYPECACHE_EQ_OPR
Definition typcache.h:138
#define TYPECACHE_LT_OPR
Definition typcache.h:139
const char * type
static zic_t corr[TZ_MAX_LEAPS]
Definition zic.c:410

References StatsArgInfo::argname, ARR_DIMS, array_in_safe(), AVG_WIDTH_ELEM, check_all_expr_argnames_valid(), construct_array_builtin(), corr, CORRELATION_ELEM, DatumGetArrayTypeP, ELEM_COUNT_HISTOGRAM_ELEM, TypeCacheEntry::eq_opr, ereport, errcode(), errhint(), errmsg, EXPRESSIONS_ARG, extarginfo, extexprargname, fb(), float4in(), get_multirange_range(), getKeyJsonValueFromContainer(), heap_copy_tuple_as_datum(), heap_form_tuple(), heap_freetuple(), HISTOGRAM_BOUNDS_ELEM, i, int4in(), InvalidAttrNumber, InvalidOid, jbv_string_get_cstr(), jbv_to_infunc_datum(), jbvNull, jbvString, JsonContainerIsObject, len, lookup_type_cache(), TypeCacheEntry::lt_opr, MOST_COMMON_ELEM_FREQS_ELEM, MOST_COMMON_ELEMS_ELEM, MOST_COMMON_FREQS_ELEM, MOST_COMMON_VALS_ELEM, N_DISTINCT_ELEM, NULL_FRAC_ELEM, NUM_ATTRIBUTE_STATS_ELEMS, pfree(), PointerGetDatum, RANGE_BOUNDS_HISTOGRAM_ELEM, RANGE_EMPTY_FRAC_ELEM, RANGE_LENGTH_HISTOGRAM_ELEM, RelationGetDescr, statatt_get_elem_type(), statatt_init_empty_tuple(), statatt_set_slot(), type, type_is_multirange(), TYPECACHE_EQ_OPR, TYPECACHE_LT_OPR, TypeCacheEntry::typtype, val, values, and WARNING.

Referenced by import_expressions().

◆ jbv_string_get_cstr()

static char * jbv_string_get_cstr ( JsonbValue jval)
static

Definition at line 966 of file extended_stats_funcs.c.

967{
968 char *s;
969
970 Assert(jval->type == jbvString);
971
972 s = palloc0(jval->val.string.len + 1);
973 memcpy(s, jval->val.string.val, jval->val.string.len);
974
975 return s;
976}
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
void * palloc0(Size size)
Definition mcxt.c:1420

References Assert, fb(), jbvString, memcpy(), and palloc0().

Referenced by check_all_expr_argnames_valid(), import_pg_statistic(), and jbv_to_infunc_datum().

◆ jbv_to_infunc_datum()

static bool jbv_to_infunc_datum ( JsonbValue jval,
PGFunction  func,
AttrNumber  exprnum,
const char argname,
Datum datum 
)
static

Definition at line 982 of file extended_stats_funcs.c.

984{
985 ErrorSaveContext escontext = {
987 .details_wanted = true
988 };
989
990 char *s = jbv_string_get_cstr(jval);
991 bool ok;
992
994 (Node *) &escontext, datum);
995
996 /*
997 * If we got a type import error, use the report generated and add an
998 * error hint before throwing a warning.
999 */
1000 if (!ok)
1001 {
1003
1006 "Element \"%s\" in expression %d could not be parsed.",
1007 argname, exprnum);
1008
1009 escontext.error_data->elevel = WARNING;
1010 escontext.error_data->hint = hint_str.data;
1011
1012 ThrowErrorData(escontext.error_data);
1013 pfree(hint_str.data);
1014 }
1015
1016 pfree(s);
1017 return ok;
1018}
bool DirectInputFunctionCallSafe(PGFunction func, char *str, Oid typioparam, int32 typmod, Node *escontext, Datum *result)
Definition fmgr.c:1641

References appendStringInfo(), StatsArgInfo::argname, DirectInputFunctionCallSafe(), ErrorData::elevel, ErrorSaveContext::error_data, fb(), ErrorData::hint, initStringInfo(), InvalidOid, jbv_string_get_cstr(), pfree(), ThrowErrorData(), ErrorSaveContext::type, and WARNING.

Referenced by import_pg_statistic().

◆ key_in_expr_argnames()

static bool key_in_expr_argnames ( JsonbValue key)
static

Definition at line 884 of file extended_stats_funcs.c.

885{
886 Assert(key->type == jbvString);
887 for (int i = 0; i < NUM_ATTRIBUTE_STATS_ELEMS; i++)
888 {
889 if (strlen(extexprargname[i]) == key->val.string.len &&
890 strncmp(extexprargname[i], key->val.string.val, key->val.string.len) == 0)
891 return true;
892 }
893 return false;
894}

References Assert, extexprargname, fb(), i, jbvString, and NUM_ATTRIBUTE_STATS_ELEMS.

Referenced by check_all_expr_argnames_valid().

◆ pg_clear_extended_stats()

Datum pg_clear_extended_stats ( PG_FUNCTION_ARGS  )

Definition at line 1742 of file extended_stats_funcs.c.

1743{
1744 char *relnspname;
1745 char *relname;
1746 char *nspname;
1747 Oid nspoid;
1748 Oid relid;
1749 char *stxname;
1750 bool inherited;
1752 HeapTuple tup;
1755
1756 /* relation arguments */
1761
1762 /* extended statistics arguments */
1769
1770 if (RecoveryInProgress())
1771 {
1774 errmsg("recovery is in progress"),
1775 errhint("Statistics cannot be modified during recovery."));
1777 }
1778
1779 /*
1780 * First open the relation where we expect to find the statistics. This
1781 * is similar to relation and attribute statistics, so as ACL checks are
1782 * done before any locks are taken, even before any attempts related to
1783 * the extended stats object.
1784 */
1788
1789 /* Now check if the namespace of the stats object exists. */
1790 nspoid = get_namespace_oid(nspname, true);
1791 if (nspoid == InvalidOid)
1792 {
1795 errmsg("could not find schema \"%s\"", nspname));
1797 }
1798
1801
1802 if (!HeapTupleIsValid(tup))
1803 {
1807 errmsg("could not find extended statistics object \"%s.%s\"",
1808 nspname, stxname));
1810 }
1811
1813
1814 /*
1815 * This should be consistent, based on the lock taken on the table when we
1816 * started.
1817 */
1818 if (stxform->stxrelid != relid)
1819 {
1824 errmsg("could not clear extended statistics object \"%s.%s\": incorrect relation \"%s.%s\" specified",
1828 }
1829
1832
1834
1836}
static bool delete_pg_statistic_ext_data(Oid stxoid, bool inherited)
#define PG_RETURN_VOID()
Definition fmgr.h:350
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3599

References delete_pg_statistic_ext_data(), ereport, errcode(), errhint(), errmsg, extarginfo, fb(), Form_pg_statistic_ext, get_namespace_name(), get_namespace_oid(), get_pg_statistic_ext(), GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, INHERITED_ARG, InvalidOid, makeRangeVar(), PG_GETARG_BOOL, PG_GETARG_DATUM, PG_RETURN_VOID, RangeVarCallbackForStats(), RangeVarGetRelidExtended(), RecoveryInProgress(), relname, RELNAME_ARG, RELSCHEMA_ARG, RowExclusiveLock, ShareUpdateExclusiveLock, STATNAME_ARG, stats_check_required_arg(), STATSCHEMA_ARG, table_close(), table_open(), TextDatumGetCString, and WARNING.

◆ pg_restore_extended_stats()

Datum pg_restore_extended_stats ( PG_FUNCTION_ARGS  )

Definition at line 1721 of file extended_stats_funcs.c.

1722{
1724 bool result = true;
1725
1727 InvalidOid, NULL, NULL);
1728
1730 result = false;
1731
1733 result = false;
1734
1736}
static bool extended_statistics_update(FunctionCallInfo fcinfo)
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
bool stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo, FunctionCallInfo positional_fcinfo, struct StatsArgInfo *arginfo)
Definition stat_utils.c:348

References extarginfo, extended_statistics_update(), fb(), InitFunctionCallInfoData, InvalidOid, LOCAL_FCINFO, NUM_EXTENDED_STATS_ARGS, PG_RETURN_BOOL, result, and stats_fill_fcinfo_from_arg_pairs().

◆ upsert_pg_statistic_ext_data()

static void upsert_pg_statistic_ext_data ( const Datum values,
const bool nulls,
const bool replaces 
)
static

Definition at line 268 of file extended_stats_funcs.c.

270{
274
276
280
282 {
285 values,
286 nulls,
287 replaces);
290 }
291 else
292 {
295 }
296
298
300
302}
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1118
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233

References CatalogTupleInsert(), CatalogTupleUpdate(), CommandCounterIncrement(), fb(), heap_form_tuple(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache2(), table_close(), table_open(), and values.

Referenced by extended_statistics_update().

Variable Documentation

◆ extarginfo

struct StatsArgInfo extarginfo[]
static
Initial value:
=
{
[RELSCHEMA_ARG] = {"schemaname", TEXTOID},
[RELNAME_ARG] = {"relname", TEXTOID},
[STATSCHEMA_ARG] = {"statistics_schemaname", TEXTOID},
[STATNAME_ARG] = {"statistics_name", TEXTOID},
[INHERITED_ARG] = {"inherited", BOOLOID},
[NDISTINCT_ARG] = {"n_distinct", PG_NDISTINCTOID},
[DEPENDENCIES_ARG] = {"dependencies", PG_DEPENDENCIESOID},
[MOST_COMMON_VALS_ARG] = {"most_common_vals", TEXTARRAYOID},
[MOST_COMMON_FREQS_ARG] = {"most_common_freqs", FLOAT8ARRAYOID},
[MOST_COMMON_BASE_FREQS_ARG] = {"most_common_base_freqs", FLOAT8ARRAYOID},
[EXPRESSIONS_ARG] = {"exprs", JSONBOID},
}

Definition at line 66 of file extended_stats_funcs.c.

67{
68 [RELSCHEMA_ARG] = {"schemaname", TEXTOID},
69 [RELNAME_ARG] = {"relname", TEXTOID},
70 [STATSCHEMA_ARG] = {"statistics_schemaname", TEXTOID},
71 [STATNAME_ARG] = {"statistics_name", TEXTOID},
72 [INHERITED_ARG] = {"inherited", BOOLOID},
73 [NDISTINCT_ARG] = {"n_distinct", PG_NDISTINCTOID},
74 [DEPENDENCIES_ARG] = {"dependencies", PG_DEPENDENCIESOID},
75 [MOST_COMMON_VALS_ARG] = {"most_common_vals", TEXTARRAYOID},
76 [MOST_COMMON_FREQS_ARG] = {"most_common_freqs", FLOAT8ARRAYOID},
77 [MOST_COMMON_BASE_FREQS_ARG] = {"most_common_base_freqs", FLOAT8ARRAYOID},
78 [EXPRESSIONS_ARG] = {"exprs", JSONBOID},
80};

Referenced by check_mcvlist_array(), extended_statistics_update(), import_expressions(), import_mcv(), import_pg_statistic(), pg_clear_extended_stats(), and pg_restore_extended_stats().

◆ extexprargname

const char* extexprargname[NUM_ATTRIBUTE_STATS_ELEMS]
static
Initial value:
=
{
"null_frac",
"avg_width",
"n_distinct",
"most_common_vals",
"most_common_freqs",
"histogram_bounds",
"correlation",
"most_common_elems",
"most_common_elem_freqs",
"elem_count_histogram",
"range_length_histogram",
"range_empty_frac",
"range_bounds_histogram"
}

Definition at line 107 of file extended_stats_funcs.c.

108{
109 "null_frac",
110 "avg_width",
111 "n_distinct",
112 "most_common_vals",
113 "most_common_freqs",
114 "histogram_bounds",
115 "correlation",
116 "most_common_elems",
117 "most_common_elem_freqs",
118 "elem_count_histogram",
119 "range_length_histogram",
120 "range_empty_frac",
121 "range_bounds_histogram"
122};

Referenced by import_pg_statistic(), and key_in_expr_argnames().