PostgreSQL Source Code git master
Loading...
Searching...
No Matches
extended_stats_funcs.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * extended_stats_funcs.c
4 * Functions for manipulating extended statistics.
5 *
6 * This file includes the set of facilities required to support the direct
7 * manipulations of extended statistics objects.
8 *
9 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
11 *
12 * IDENTIFICATION
13 * src/backend/statistics/extended_stats_funcs.c
14 *
15 *-------------------------------------------------------------------------
16 */
17#include "postgres.h"
18
19#include "access/heapam.h"
20#include "catalog/indexing.h"
21#include "catalog/namespace.h"
22#include "catalog/pg_collation_d.h"
23#include "catalog/pg_database.h"
24#include "catalog/pg_operator.h"
27#include "miscadmin.h"
28#include "nodes/makefuncs.h"
29#include "nodes/nodeFuncs.h"
30#include "optimizer/optimizer.h"
33#include "utils/acl.h"
34#include "utils/array.h"
35#include "utils/builtins.h"
36#include "utils/fmgroids.h"
37#include "utils/jsonb.h"
38#include "utils/lsyscache.h"
39#include "utils/syscache.h"
40#include "utils/typcache.h"
41
42
43/*
44 * Index of the arguments for the SQL functions.
45 */
61
62/*
63 * The argument names and type OIDs of the arguments for the SQL
64 * functions.
65 */
66static struct StatsArgInfo extarginfo[] =
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};
81
82/*
83 * An index of the elements of a stxdexpr Datum, which repeat for each
84 * expression in the extended statistics object.
85 */
103
104/*
105 * The argument names of the repeating arguments for stxdexpr.
106 */
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};
123
125
127 const char *stxname);
129
130/*
131 * Track the extended statistics kinds expected for a pg_statistic_ext
132 * tuple.
133 */
134typedef struct
135{
138 bool mcv;
141
142static void expand_stxkind(HeapTuple tup, StakindFlags *enabled);
143static void upsert_pg_statistic_ext_data(const Datum *values,
144 const bool *nulls,
145 const bool *replaces);
146
147static bool check_mcvlist_array(const ArrayType *arr, int argindex,
148 int required_ndims, int mcv_length);
150 Oid *atttypids, int32 *atttypmods,
152 bool *exprs_is_perfect);
153static Datum import_mcv(const ArrayType *mcv_arr,
154 const ArrayType *freqs_arr,
156 Oid *atttypids, int32 *atttypmods,
158 bool *ok);
159
160static char *jbv_string_get_cstr(JsonbValue *jval);
162 AttrNumber exprnum, const char *argname,
163 Datum *datum);
164static bool key_in_expr_argnames(JsonbValue *key);
166static Datum array_in_safe(FmgrInfo *array_in, const char *s, Oid typid,
167 int32 typmod, AttrNumber exprnum,
168 const char *element_name, bool *ok);
171 Oid typid, int32 typmod, Oid typcoll,
172 bool *pg_statistic_ok);
173
174/*
175 * Fetch a pg_statistic_ext row by name and namespace OID.
176 */
177static HeapTuple
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}
219
220/*
221 * Decode the stxkind column so that we know which stats types to expect,
222 * returning a StakindFlags set depending on the stats kinds expected by
223 * a pg_statistic_ext tuple.
224 */
225static void
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}
263
264/*
265 * Perform the actual storage of a pg_statistic_ext_data tuple.
266 */
267static void
303
304/*
305 * Insert or update an extended statistics object.
306 *
307 * Major errors, such as the table not existing or permission errors, are
308 * reported as ERRORs. There are a couple of paths that generate a WARNING,
309 * like when the statistics object or its schema do not exist, a conversion
310 * failure on one statistic kind, or when other statistic kinds may still
311 * be updated.
312 */
313static bool
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\"",
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\"",
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}
767
768/*
769 * Consistency checks to ensure that other mcvlist arrays are in alignment
770 * with the mcv array.
771 */
772static bool
773check_mcvlist_array(const ArrayType *arr, int argindex, int required_ndims,
774 int mcv_length)
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}
806
807/*
808 * Create the stxdmcv datum from the equal-sized arrays of most common values,
809 * their null flags, and the frequency and base frequency associated with
810 * each value.
811 */
812static Datum
814 const ArrayType *base_freqs_arr, Oid *atttypids, int32 *atttypmods,
815 Oid *atttypcolls, int numattrs, bool *ok)
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)",
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}
879
880/*
881 * Check if key is found in the list of expression argnames.
882 */
883static bool
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}
895
896/*
897 * Verify that all of the keys in the object are valid argnames.
898 */
899static bool
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}
961
962/*
963 * Simple conversion of jbvString to cstring
964 */
965static char *
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}
977
978/*
979 * Apply a jbvString value to a safe scalar input function.
980 */
981static bool
983 const char *argname, Datum *datum)
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}
1019
1020/*
1021 * Build an array datum with element type elemtypid from a text datum, used as
1022 * value of an attribute in a pg_statistic tuple.
1023 *
1024 * If an error is encountered, capture it, and reduce the elevel to WARNING.
1025 *
1026 * This is an adaptation of statatt_build_stavalues().
1027 */
1028static Datum
1029array_in_safe(FmgrInfo *array_in, const char *s, Oid typid, int32 typmod,
1030 AttrNumber exprnum, const char *element_name, bool *ok)
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}
1095
1096/*
1097 * Create a pg_statistic tuple from an expression JSONB container.
1098 *
1099 * The pg_statistic tuple is pre-populated with acceptable defaults, therefore
1100 * even if there is an issue with all of the keys in the container, we can
1101 * still return a legit tuple datum.
1102 *
1103 * Set pg_statistic_ok to true if all of the values found in the container
1104 * were imported without issue. pg_statistic_ok is switched to "true" once
1105 * the full pg_statistic tuple has been built and validated.
1106 */
1107static Datum
1110 Oid typid, int32 typmod, Oid typcoll,
1111 bool *pg_statistic_ok)
1112{
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}
1544
1545/*
1546 * Create the stxdexpr datum, which is an array of pg_statistic rows with all
1547 * of the object identification fields left at defaults, using the json array
1548 * of objects/nulls referenced against the datatypes for the expressions.
1549 *
1550 * The exprs_is_perfect will be set to true if all pg_statistic rows were
1551 * imported cleanly. If any of them experienced a problem (and thus were
1552 * set as if they were null), then the expression is kept but exprs_is_perfect
1553 * will be marked as false.
1554 *
1555 * This datum is needed to fill out a complete pg_statistic_ext_data tuple.
1556 */
1557static Datum
1559 Oid *atttypids, int32 *atttypmods,
1561 bool *exprs_is_perfect)
1562{
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",
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};
1682
1683/*
1684 * Remove an existing pg_statistic_ext_data row for a given pg_statistic_ext
1685 * row and "inherited" pair.
1686 */
1687static bool
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}
1712
1713/*
1714 * Restore (insert or replace) statistics for the given statistics object.
1715 *
1716 * This function accepts variadic arguments in key-value pairs, which are
1717 * given to stats_fill_fcinfo_from_arg_pairs to be mapped into positional
1718 * arguments.
1719 */
1720Datum
1737
1738/*
1739 * Delete statistics for the given statistics object.
1740 */
1741Datum
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}
#define ARR_NDIM(a)
Definition array.h:290
#define PG_GETARG_ARRAYTYPE_P(n)
Definition array.h:263
#define ARR_DATA_PTR(a)
Definition array.h:322
#define DatumGetArrayTypeP(X)
Definition array.h:261
#define ARR_ELEMTYPE(a)
Definition array.h:292
#define ARR_DIMS(a)
Definition array.h:294
#define ARR_HASNULL(a)
Definition array.h:291
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
bool array_contains_nulls(const ArrayType *array)
Datum array_in(PG_FUNCTION_ARGS)
Definition arrayfuncs.c:181
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
int16 AttrNumber
Definition attnum.h:21
#define InvalidAttrNumber
Definition attnum.h:23
static Datum values[MAXATTR]
Definition bootstrap.c:190
static void cleanup(void)
Definition bootstrap.c:886
#define TextDatumGetCString(d)
Definition builtins.h:99
#define Assert(condition)
Definition c.h:943
double float8
Definition c.h:714
int32_t int32
Definition c.h:620
#define OidIsValid(objectId)
Definition c.h:858
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
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)
void ThrowErrorData(ErrorData *edata)
Definition elog.c:2091
int errcode(int sqlerrcode)
Definition elog.c:875
int errhint(const char *fmt,...) pg_attribute_printf(1
#define WARNING
Definition elog.h:37
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
static bool key_in_expr_argnames(JsonbValue *key)
extended_stats_argnum
@ INHERITED_ARG
@ EXPRESSIONS_ARG
@ RELSCHEMA_ARG
@ NUM_EXTENDED_STATS_ARGS
@ RELNAME_ARG
@ MOST_COMMON_BASE_FREQS_ARG
@ MOST_COMMON_FREQS_ARG
@ STATNAME_ARG
@ STATSCHEMA_ARG
@ MOST_COMMON_VALS_ARG
@ NDISTINCT_ARG
@ DEPENDENCIES_ARG
Datum pg_clear_extended_stats(PG_FUNCTION_ARGS)
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 bool delete_pg_statistic_ext_data(Oid stxoid, bool inherited)
static struct StatsArgInfo extarginfo[]
Datum pg_restore_extended_stats(PG_FUNCTION_ARGS)
extended_stats_exprs_element
@ 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
static bool jbv_to_infunc_datum(JsonbValue *jval, PGFunction func, AttrNumber exprnum, const char *argname, Datum *datum)
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 void expand_stxkind(HeapTuple tup, StakindFlags *enabled)
static char * jbv_string_get_cstr(JsonbValue *jval)
static HeapTuple get_pg_statistic_ext(Relation pg_stext, Oid nspoid, const char *stxname)
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 extended_statistics_update(FunctionCallInfo fcinfo)
static bool check_all_expr_argnames_valid(JsonbContainer *cont, AttrNumber exprnum)
static const char * extexprargname[NUM_ATTRIBUTE_STATS_ELEMS]
static bool check_mcvlist_array(const ArrayType *arr, int argindex, int required_ndims, int mcv_length)
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
Datum float4in(PG_FUNCTION_ARGS)
Definition float.c:205
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition fmgr.c:129
bool DirectInputFunctionCallSafe(PGFunction func, char *str, Oid typioparam, int32 typmod, Node *escontext, Datum *result)
Definition fmgr.c:1641
#define PG_RETURN_VOID()
Definition fmgr.h:350
#define DatumGetByteaPP(X)
Definition fmgr.h:292
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition fmgr.h:150
#define PG_ARGISNULL(n)
Definition fmgr.h:209
#define PG_GETARG_DATUM(n)
Definition fmgr.h:268
#define LOCAL_FCINFO(name, nargs)
Definition fmgr.h:110
#define FunctionCallInvoke(fcinfo)
Definition fmgr.h:172
#define PG_GETARG_BOOL(n)
Definition fmgr.h:274
Datum(* PGFunction)(FunctionCallInfo fcinfo)
Definition fmgr.h:40
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
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
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1118
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition heaptuple.c:989
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
#define nitems(x)
Definition indent.h:31
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition indexing.c:365
long val
Definition informix.c:689
static bool success
Definition initdb.c:188
Datum int4in(PG_FUNCTION_ARGS)
Definition int.c:316
int i
Definition isn.c:77
@ jbvBinary
Definition jsonb.h:238
@ jbvNull
Definition jsonb.h:230
@ jbvString
Definition jsonb.h:231
#define JsonContainerSize(jc)
Definition jsonb.h:208
#define JB_ROOT_IS_ARRAY(jbp_)
Definition jsonb.h:224
#define PG_GETARG_JSONB_P(x)
Definition jsonb.h:418
#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
JsonbValue * getKeyJsonValueFromContainer(JsonbContainer *container, const char *keyVal, int keyLen, JsonbValue *res)
Definition jsonb_util.c:402
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition jsonb_util.c:935
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition jsonb_util.c:973
JsonbValue * getIthJsonbValueFromContainer(JsonbContainer *container, uint32 i)
Definition jsonb_util.c:472
#define ShareUpdateExclusiveLock
Definition lockdefs.h:39
#define RowExclusiveLock
Definition lockdefs.h:38
Oid get_multirange_range(Oid multirangeOid)
Definition lsyscache.c:3761
Oid get_rel_type_id(Oid relid)
Definition lsyscache.c:2210
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3599
bool type_is_multirange(Oid typid)
Definition lsyscache.c:2931
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition makefuncs.c:473
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
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc0(Size size)
Definition mcxt.c:1420
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
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
static char * errmsg
int16 attnum
FormData_pg_attribute * Form_pg_attribute
NameData relname
Definition pg_class.h:40
const void size_t len
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
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
#define PointerGetDatum(X)
Definition postgres.h:354
#define InvalidOid
unsigned int Oid
static int fb(int x)
tree ctl root
Definition radixtree.h:1857
void * stringToNode(const char *str)
Definition read.c:90
#define RelationGetDescr(relation)
Definition rel.h:542
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
bool statatt_get_elem_type(Oid atttypid, char atttyptype, Oid *elemtypid, Oid *elem_eq_opr)
Definition stat_utils.c:523
bool stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo, FunctionCallInfo positional_fcinfo, struct StatsArgInfo *arginfo)
Definition stat_utils.c:348
void RangeVarCallbackForStats(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition stat_utils.c:142
void statatt_init_empty_tuple(Oid reloid, int16 attnum, bool inherited, Datum *values, bool *nulls, bool *replaces)
Definition stat_utils.c:722
void stats_check_required_arg(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum)
Definition stat_utils.c:51
void statatt_set_slot(Datum *values, bool *nulls, bool *replaces, int16 stakind, Oid staop, Oid stacoll, Datum stanumbers, bool stanumbers_isnull, Datum stavalues, bool stavalues_isnull)
Definition stat_utils.c:644
#define BTEqualStrategyNumber
Definition stratnum.h:31
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
enum jbvType type
Definition jsonb.h:257
char * val
Definition jsonb.h:266
Definition jsonb.h:215
Definition pg_list.h:54
Definition nodes.h:135
const char * argname
Definition stat_utils.h:24
Definition c.h:776
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache2(SysCacheIdentifier cacheId, Datum key1, Datum key2)
Definition syscache.c:231
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:626
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:596
#define SearchSysCacheCopy1(cacheId, key1)
Definition syscache.h:91
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40
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
void CommandCounterIncrement(void)
Definition xact.c:1130
bool RecoveryInProgress(void)
Definition xlog.c:6832
static zic_t corr[TZ_MAX_LEAPS]
Definition zic.c:410