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 1028 of file extended_stats_funcs.c.

1030{
1031 LOCAL_FCINFO(fcinfo, 3);
1032 Datum result;
1033
1034 ErrorSaveContext escontext = {
1036 .details_wanted = true
1037 };
1038
1039 *ok = false;
1041 (Node *) &escontext, NULL);
1042
1043 fcinfo->args[0].value = CStringGetDatum(s);
1044 fcinfo->args[0].isnull = false;
1045 fcinfo->args[1].value = ObjectIdGetDatum(typid);
1046 fcinfo->args[1].isnull = false;
1047 fcinfo->args[2].value = Int32GetDatum(typmod);
1048 fcinfo->args[2].isnull = false;
1049
1050 result = FunctionCallInvoke(fcinfo);
1051
1052 /*
1053 * If the array_in function returned an error, we will want to report that
1054 * ERROR as a WARNING, and add some location context to the error message.
1055 * Overwriting the existing hint (if any) is not ideal, and an error
1056 * context would only work for level >= ERROR.
1057 */
1058 if (escontext.error_occurred)
1059 {
1061
1064 "Element \"%s\" in expression %d could not be parsed.",
1066 escontext.error_data->elevel = WARNING;
1067 escontext.error_data->hint = hint_str.data;
1068 ThrowErrorData(escontext.error_data);
1069 pfree(hint_str.data);
1070 return (Datum) 0;
1071 }
1072
1074 {
1077 errmsg("could not import element \"%s\" in expression %d: null value found",
1079 return (Datum) 0;
1080 }
1081
1082 *ok = true;
1083 return result;
1084}
#define DatumGetArrayTypeP(X)
Definition array.h:261
bool array_contains_nulls(const ArrayType *array)
Datum array_in(PG_FUNCTION_ARGS)
Definition arrayfuncs.c:181
void ThrowErrorData(ErrorData *edata)
Definition elog.c:2090
int errcode(int sqlerrcode)
Definition elog.c:874
#define WARNING
Definition elog.h:36
#define ereport(elevel,...)
Definition elog.h:150
#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:1616
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:370
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:421
char * hint
Definition elog.h:435
ErrorData * error_data
Definition miscnodes.h:49
Definition nodes.h:135

References appendStringInfo(), 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(), 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 899 of file extended_stats_funcs.c.

900{
901 bool all_keys_valid = true;
902
906
908
910
911 /* We always start off with a BEGIN OBJECT */
912 jitok = JsonbIteratorNext(&jbit, &jkey, false);
914
915 while (true)
916 {
918
919 jitok = JsonbIteratorNext(&jbit, &jkey, false);
920
921 /*
922 * We have run of keys. This is the only condition where it is
923 * memory-safe to break out of the loop.
924 */
925 if (jitok == WJB_END_OBJECT)
926 break;
927
928 /* We can only find keys inside an object */
929 Assert(jitok == WJB_KEY);
930 Assert(jkey.type == jbvString);
931
932 /* A value must follow the key */
933 jitok = JsonbIteratorNext(&jbit, &jval, false);
935
936 /*
937 * If we have already found an invalid key, there is no point in
938 * looking for more, because additional WARNINGs are just clutter. We
939 * must continue iterating over the json to ensure that we clean up
940 * all allocated memory.
941 */
942 if (!all_keys_valid)
943 continue;
944
946 {
948
951 errmsg("could not import element in expression %d: invalid key name",
952 exprnum));
953
955 all_keys_valid = false;
956 }
957 }
958 return all_keys_valid;
959}
#define Assert(condition)
Definition c.h:945
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_NDIM(a)
Definition array.h:290
#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 1665 of file extended_stats_funcs.c.

1666{
1669 bool result = false;
1670
1671 /* Is there already a pg_statistic_ext_data tuple for this attribute? */
1675
1677 {
1678 CatalogTupleDelete(sed, &oldtup->t_self);
1680 result = true;
1681 }
1682
1684
1686
1687 return result;
1688}
#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:264
HeapTuple SearchSysCache2(SysCacheIdentifier cacheId, Datum key1, Datum key2)
Definition syscache.c:230
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:1102

References BoolGetDatum(), CatalogTupleDelete(), CommandCounterIncrement(), fb(), HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), 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:39
#define elog(elevel,...)
Definition elog.h:226
int i
Definition isn.c:77
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:625

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 * VacAttrStatP 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 AttNumber order, but we do not rely
590 * 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 attytypids, attytypmods, 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:188
static void cleanup(void)
Definition bootstrap.c:879
#define TextDatumGetCString(d)
Definition builtins.h:99
int32_t int32
Definition c.h:614
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition clauses.c:2498
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:77
#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:1384
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:1848
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:299
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:778
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:595
bool RecoveryInProgress(void)
Definition xlog.c:6444

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:860
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:514
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 1535 of file extended_stats_funcs.c.

1539{
1540 const char *argname = extarginfo[EXPRESSIONS_ARG].argname;
1542 ArrayBuildState *astate = NULL;
1543 Datum result = (Datum) 0;
1544 int num_import_ok = 0;
1547
1549
1550 *exprs_is_perfect = false;
1551
1552 /* Json schema must be [{expr},...] */
1554 {
1557 errmsg("could not parse \"%s\": root-level array required", argname));
1558 goto exprs_error;
1559 }
1560
1561 root = &exprs_jsonb->root;
1562
1563 /*
1564 * The number of elements in the array must match the number of
1565 * expressions in the stats object definition.
1566 */
1569 {
1572 errmsg("could not parse \"%s\": incorrect number of elements (%d required)",
1573 argname, num_root_elements));
1574 goto exprs_error;
1575 }
1576
1578
1579 /*
1580 * Iterate over each expected expression object in the array. Some of
1581 * them could be null. If the element is a completely wrong data type,
1582 * give a WARNING and then treat the element like a NULL element in the
1583 * result array.
1584 *
1585 * Each expression *MUST* have a value appended in the result pg_statistic
1586 * array.
1587 */
1588 for (int i = 0; i < numexprs; i++)
1589 {
1590 Datum pgstdat = (Datum) 0;
1591 bool isnull = false;
1592 AttrNumber exprattnum = -1 - i;
1593
1595
1596 switch (elem->type)
1597 {
1598 case jbvBinary:
1599 {
1600 bool sta_ok = false;
1601
1602 /* a real stats object */
1603 pgstdat = import_pg_statistic(pgsd, elem->val.binary.data,
1605 atttypids[i], atttypmods[i],
1606 atttypcolls[i], &sta_ok);
1607
1608 /*
1609 * If some incorrect data has been found, assign NULL for
1610 * this expression as a mean to give up.
1611 */
1612 if (sta_ok)
1613 num_import_ok++;
1614 else
1615 {
1616 isnull = true;
1617 pgstdat = (Datum) 0;
1618 }
1619 }
1620 break;
1621
1622 case jbvNull:
1623 /* NULL placeholder for invalid data, still fine */
1624 isnull = true;
1625 num_import_ok++;
1626 break;
1627
1628 default:
1629 /* cannot possibly be valid */
1632 errmsg("could not parse \"%s\": invalid element in expression %d",
1633 argname, exprattnum));
1634 goto exprs_error;
1635 }
1636
1637 astate = accumArrayResult(astate, pgstdat, isnull, pgstypoid,
1639 }
1640
1641 /*
1642 * The expressions datum is perfect *if and only if* all of the
1643 * pg_statistic elements were also ok, for a number of elements equal to
1644 * the number of expressions. Anything else means a failure in restoring
1645 * the data of this statistics object.
1646 */
1648
1649 if (astate != NULL)
1650 result = makeArrayResult(astate, CurrentMemoryContext);
1651
1652 return result;
1653
1655 if (astate != NULL)
1656 pfree(astate);
1657 return (Datum) 0;
1658};
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:2199
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
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(), 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:716
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 1098 of file extended_stats_funcs.c.

1102{
1103 const char *argname = extarginfo[EXPRESSIONS_ARG].argname;
1104 TypeCacheEntry *typcache;
1106 bool nulls[Natts_pg_statistic];
1109 Datum pgstdat = (Datum) 0;
1112 bool found[NUM_ATTRIBUTE_STATS_ELEMS] = {0};
1114
1115 /* Assume the worst by default. */
1116 *pg_statistic_ok = false;
1117
1119 {
1122 errmsg("could not parse \"%s\": invalid element in expression %d",
1123 argname, exprnum));
1124 goto pg_statistic_error;
1125 }
1126
1127 /*
1128 * Loop through all keys that we need to look up. If any value found is
1129 * neither a string nor a NULL, there is not much we can do, so just give
1130 * on the entire tuple for this expression.
1131 */
1132 for (int i = 0; i < NUM_ATTRIBUTE_STATS_ELEMS; i++)
1133 {
1134 const char *s = extexprargname[i];
1135 int len = strlen(s);
1136
1138 continue;
1139
1140 switch (val[i].type)
1141 {
1142 case jbvString:
1143 found[i] = true;
1144 break;
1145
1146 case jbvNull:
1147 break;
1148
1149 default:
1152 errmsg("could not parse \"%s\": invalid element in expression %d", argname, exprnum),
1153 errhint("Value of element \"%s\" must be type a null or a string.", s));
1154 goto pg_statistic_error;
1155 }
1156 }
1157
1158 /* Look for invalid keys */
1160 goto pg_statistic_error;
1161
1162 /*
1163 * There are two arg pairs, MCV+MCF and MCEV+MCEF. Both values must
1164 * either be found or not be found. Any disagreement is a warning. Once
1165 * we have ruled out disagreeing pairs, we can use either found flag as a
1166 * proxy for the other.
1167 */
1168 if (found[MOST_COMMON_VALS_ELEM] != found[MOST_COMMON_FREQS_ELEM])
1169 {
1172 errmsg("could not parse \"%s\": invalid element in expression %d",
1173 argname, exprnum),
1174 errhint("\"%s\" and \"%s\" must be both either strings or nulls.",
1177 goto pg_statistic_error;
1178 }
1180 {
1183 errmsg("could not parse \"%s\": invalid element in expression %d",
1184 argname, exprnum),
1185 errhint("\"%s\" and \"%s\" must be both either strings or nulls.",
1188 goto pg_statistic_error;
1189 }
1190
1191 /*
1192 * Range types may expect three values to be set. All three of them must
1193 * either be found or not be found. Any disagreement is a warning.
1194 */
1197 {
1200 errmsg("could not parse \"%s\": invalid element in expression %d",
1201 argname, exprnum),
1202 errhint("\"%s\", \"%s\", and \"%s\" must be all either strings or all nulls.",
1206 goto pg_statistic_error;
1207 }
1208
1209 /* This finds the right operators even if atttypid is a domain */
1211
1213 values, nulls, replaces);
1214
1215 /*
1216 * Special case: collation for tsvector is DEFAULT_COLLATION_OID. See
1217 * compute_tsvector_stats().
1218 */
1219 if (typid == TSVECTOROID)
1221
1222 /*
1223 * We only need to fetch element type and eq operator if we have a stat of
1224 * type MCELEM or DECHIST, otherwise the values are unnecessary and not
1225 * meaningful.
1226 */
1228 {
1229 if (!statatt_get_elem_type(typid, typcache->typtype,
1230 &elemtypid, &elemeqopr))
1231 {
1234 errmsg("could not parse \"%s\": invalid element type in expression %d",
1235 argname, exprnum));
1236 goto pg_statistic_error;
1237 }
1238 }
1239
1240 /*
1241 * These three fields can only be set if dealing with a range or
1242 * multi-range type.
1243 */
1244 if (found[RANGE_LENGTH_HISTOGRAM_ELEM] ||
1245 found[RANGE_EMPTY_FRAC_ELEM] ||
1247 {
1248 if (typcache->typtype != TYPTYPE_RANGE &&
1249 typcache->typtype != TYPTYPE_MULTIRANGE)
1250 {
1253 errmsg("could not parse \"%s\": invalid data in expression %d",
1254 argname, exprnum),
1255 errhint("\"%s\", \"%s\", and \"%s\" can only be set for a range type.",
1259 goto pg_statistic_error;
1260 }
1261 }
1262
1263 /* null_frac */
1264 if (found[NULL_FRAC_ELEM])
1265 {
1266 Datum datum;
1267
1271 else
1272 goto pg_statistic_error;
1273 }
1274
1275 /* avg_width */
1276 if (found[AVG_WIDTH_ELEM])
1277 {
1278 Datum datum;
1279
1283 else
1284 goto pg_statistic_error;
1285 }
1286
1287 /* n_distinct */
1288 if (found[N_DISTINCT_ELEM])
1289 {
1290 Datum datum;
1291
1295 else
1296 goto pg_statistic_error;
1297 }
1298
1299 /*
1300 * The STAKIND statistics are the same as the ones found in attribute
1301 * stats. However, these are all derived from json strings, whereas the
1302 * ones derived for attribute stats are a mix of datatypes. This limits
1303 * the opportunities for code sharing between the two.
1304 *
1305 * Some statistic kinds have both a stanumbers and a stavalues components.
1306 * In those cases, both values must either be NOT NULL or both NULL, and
1307 * if they aren't then we need to reject that stakind completely.
1308 * Currently we go a step further and reject the expression array
1309 * completely.
1310 *
1311 * Once it is established that the pairs are in NULL/NOT-NULL alignment,
1312 * we can test either expr_nulls[] value to see if the stakind has
1313 * value(s) that we can set or not.
1314 */
1315
1316 if (found[MOST_COMMON_VALS_ELEM])
1317 {
1318 Datum stavalues;
1319 Datum stanumbers;
1320 bool val_ok = false;
1321 bool num_ok = false;
1322 char *s;
1323
1325 stavalues = array_in_safe(array_in_fn, s, typid, typmod, exprnum,
1327 &val_ok);
1328
1329 pfree(s);
1330
1332 stanumbers = array_in_safe(array_in_fn, s, FLOAT4OID, -1, exprnum,
1334 &num_ok);
1335 pfree(s);
1336
1337 /* Only set the slot if both datums have been built */
1338 if (val_ok && num_ok)
1341 typcache->eq_opr, typcoll,
1342 stanumbers, false, stavalues, false);
1343 else
1344 goto pg_statistic_error;
1345 }
1346
1347 /* STATISTIC_KIND_HISTOGRAM */
1348 if (found[HISTOGRAM_BOUNDS_ELEM])
1349 {
1350 Datum stavalues;
1351 bool val_ok = false;
1353
1354 stavalues = array_in_safe(array_in_fn, s, typid, typmod, exprnum,
1356 &val_ok);
1357 pfree(s);
1358
1359 if (val_ok)
1362 typcache->lt_opr, typcoll,
1363 0, true, stavalues, false);
1364 else
1365 goto pg_statistic_error;
1366 }
1367
1368 /* STATISTIC_KIND_CORRELATION */
1369 if (found[CORRELATION_ELEM])
1370 {
1371 Datum corr[] = {(Datum) 0};
1372
1375 {
1377 Datum stanumbers = PointerGetDatum(arry);
1378
1381 typcache->lt_opr, typcoll,
1382 stanumbers, false, 0, true);
1383 }
1384 else
1385 goto pg_statistic_error;
1386 }
1387
1388 /* STATISTIC_KIND_MCELEM */
1389 if (found[MOST_COMMON_ELEMS_ELEM])
1390 {
1391 Datum stavalues;
1392 Datum stanumbers;
1393 bool val_ok = false;
1394 bool num_ok = false;
1395 char *s;
1396
1398 stavalues = array_in_safe(array_in_fn, s, elemtypid, typmod, exprnum,
1400 &val_ok);
1401 pfree(s);
1402
1403
1405 stanumbers = array_in_safe(array_in_fn, s, FLOAT4OID, -1, exprnum,
1407 &num_ok);
1408 pfree(s);
1409
1410 /* Only set the slot if both datums have been built */
1411 if (val_ok && num_ok)
1415 stanumbers, false, stavalues, false);
1416 else
1417 goto pg_statistic_error;
1418 }
1419
1420 /* STATISTIC_KIND_DECHIST */
1421 if (found[ELEM_COUNT_HISTOGRAM_ELEM])
1422 {
1423 Datum stanumbers;
1424 bool num_ok = false;
1425 char *s;
1426
1428 stanumbers = array_in_safe(array_in_fn, s, FLOAT4OID, -1, exprnum,
1430 &num_ok);
1431 pfree(s);
1432
1433 if (num_ok)
1435 elemeqopr, typcoll, stanumbers, false, 0, true);
1436 else
1437 goto pg_statistic_error;
1438 }
1439
1440 /*
1441 * STATISTIC_KIND_BOUNDS_HISTOGRAM
1442 *
1443 * This stakind appears before STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM even
1444 * though it is numerically greater, and all other stakinds appear in
1445 * numerical order.
1446 */
1447 if (found[RANGE_BOUNDS_HISTOGRAM_ELEM])
1448 {
1449 Datum stavalues;
1450 bool val_ok = false;
1451 char *s;
1452 Oid rtypid = typid;
1453
1454 /*
1455 * If it's a multirange, step down to the range type, as is done by
1456 * multirange_typanalyze().
1457 */
1458 if (type_is_multirange(typid))
1460
1462
1463 stavalues = array_in_safe(array_in_fn, s, rtypid, typmod, exprnum,
1465 &val_ok);
1466
1467 if (val_ok)
1471 0, true, stavalues, false);
1472 else
1473 goto pg_statistic_error;
1474 }
1475
1476 /* STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM */
1477 if (found[RANGE_LENGTH_HISTOGRAM_ELEM])
1478 {
1479 Datum empty_frac[] = {(Datum) 0};
1480 Datum stavalues;
1481 Datum stanumbers;
1482 bool val_ok = false;
1483 char *s;
1484
1487 {
1489
1490 stanumbers = PointerGetDatum(arry);
1491 }
1492 else
1493 goto pg_statistic_error;
1494
1496 stavalues = array_in_safe(array_in_fn, s, FLOAT8OID, -1, exprnum,
1498 &val_ok);
1499
1500 if (val_ok)
1504 stanumbers, false, stavalues, false);
1505 else
1506 goto pg_statistic_error;
1507 }
1508
1511
1513
1514 *pg_statistic_ok = true;
1515
1516 return pgstdat;
1517
1519 return (Datum) 0;
1520}
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:181
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1037
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition heaptuple.c:1001
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:3705
bool type_is_multirange(Oid typid)
Definition lsyscache.c:2920
const void size_t len
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
#define RelationGetDescr(relation)
Definition rel.h:540
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:713
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:635
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:406

References StatsArgInfo::argname, array_in_safe(), AVG_WIDTH_ELEM, check_all_expr_argnames_valid(), construct_array_builtin(), corr, CORRELATION_ELEM, 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 965 of file extended_stats_funcs.c.

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

References Assert, fb(), jbvString, 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 981 of file extended_stats_funcs.c.

983{
984 ErrorSaveContext escontext = {
986 .details_wanted = true
987 };
988
989 char *s = jbv_string_get_cstr(jval);
990 bool ok;
991
993 (Node *) &escontext, datum);
994
995 /*
996 * If we got a type import error, use the report generated and add an
997 * error hint before throwing a warning.
998 */
999 if (!ok)
1000 {
1002
1005 "Element \"%s\" in expression %d could not be parsed.",
1006 argname, exprnum);
1007
1008 escontext.error_data->elevel = WARNING;
1009 escontext.error_data->hint = hint_str.data;
1010
1011 ThrowErrorData(escontext.error_data);
1012 pfree(hint_str.data);
1013 }
1014
1015 pfree(s);
1016 return ok;
1017}
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 (strncmp(extexprargname[i], key->val.string.val, key->val.string.len) == 0)
890 return true;
891 }
892 return false;
893}

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 1719 of file extended_stats_funcs.c.

1720{
1721 char *relnspname;
1722 char *relname;
1723 char *nspname;
1724 Oid nspoid;
1725 Oid relid;
1726 char *stxname;
1727 bool inherited;
1729 HeapTuple tup;
1732
1733 /* relation arguments */
1738
1739 /* extended statistics arguments */
1746
1747 if (RecoveryInProgress())
1748 {
1751 errmsg("recovery is in progress"),
1752 errhint("Statistics cannot be modified during recovery."));
1754 }
1755
1756 /*
1757 * First open the relation where we expect to find the statistics. This
1758 * is similar to relation and attribute statistics, so as ACL checks are
1759 * done before any locks are taken, even before any attempts related to
1760 * the extended stats object.
1761 */
1765
1766 /* Now check if the namespace of the stats object exists. */
1767 nspoid = get_namespace_oid(nspname, true);
1768 if (nspoid == InvalidOid)
1769 {
1772 errmsg("could not find schema \"%s\"", nspname));
1774 }
1775
1778
1779 if (!HeapTupleIsValid(tup))
1780 {
1784 errmsg("could not find extended statistics object \"%s.%s\"",
1785 nspname, stxname));
1787 }
1788
1790
1791 /*
1792 * This should be consistent, based on the lock taken on the table when we
1793 * started.
1794 */
1795 if (stxform->stxrelid != relid)
1796 {
1800 errmsg("could not clear extended statistics object \"%s.%s\": incorrect relation \"%s.%s\" specified",
1804 }
1805
1808
1810
1812}
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:3588

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 1698 of file extended_stats_funcs.c.

1699{
1701 bool result = true;
1702
1704 InvalidOid, NULL, NULL);
1705
1707 result = false;
1708
1710 result = false;
1711
1712 PG_RETURN_BOOL(result);
1713}
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, 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:1130
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().