PostgreSQL Source Code git master
Loading...
Searching...
No Matches
extended_stats_internal.h File Reference
Include dependency graph for extended_stats_internal.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  StdAnalyzeData
 
struct  ScalarItem
 
struct  DimensionInfo
 
struct  MultiSortSupportData
 
struct  SortItem
 
struct  StatsBuildData
 

Typedefs

typedef struct DimensionInfo DimensionInfo
 
typedef struct MultiSortSupportData MultiSortSupportData
 
typedef MultiSortSupportDataMultiSortSupport
 
typedef struct SortItem SortItem
 
typedef struct StatsBuildData StatsBuildData
 

Functions

MVNDistinctstatext_ndistinct_build (double totalrows, StatsBuildData *data)
 
byteastatext_ndistinct_serialize (MVNDistinct *ndistinct)
 
MVNDistinctstatext_ndistinct_deserialize (bytea *data)
 
bool statext_ndistinct_validate (const MVNDistinct *ndistinct, const int2vector *stxkeys, int numexprs, int elevel)
 
void statext_ndistinct_free (MVNDistinct *ndistinct)
 
MVDependenciesstatext_dependencies_build (StatsBuildData *data)
 
byteastatext_dependencies_serialize (MVDependencies *dependencies)
 
MVDependenciesstatext_dependencies_deserialize (bytea *data)
 
bool statext_dependencies_validate (const MVDependencies *dependencies, const int2vector *stxkeys, int numexprs, int elevel)
 
void statext_dependencies_free (MVDependencies *dependencies)
 
MCVListstatext_mcv_build (StatsBuildData *data, double totalrows, int stattarget)
 
byteastatext_mcv_serialize (MCVList *mcvlist, VacAttrStats **stats)
 
MCVListstatext_mcv_deserialize (bytea *data)
 
void statext_mcv_free (MCVList *mcvlist)
 
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)
 
MultiSortSupport multi_sort_init (int ndims)
 
void multi_sort_add_dimension (MultiSortSupport mss, int sortdim, Oid oper, Oid collation)
 
int multi_sort_compare (const void *a, const void *b, void *arg)
 
int multi_sort_compare_dim (int dim, const SortItem *a, const SortItem *b, MultiSortSupport mss)
 
int multi_sort_compare_dims (int start, int end, const SortItem *a, const SortItem *b, MultiSortSupport mss)
 
int compare_scalars_simple (const void *a, const void *b, void *arg)
 
int compare_datums_simple (Datum a, Datum b, SortSupport ssup)
 
AttrNumberbuild_attnums_array (Bitmapset *attrs, int nexprs, int *numattrs)
 
SortItembuild_sorted_items (StatsBuildData *data, int *nitems, MultiSortSupport mss, int numattrs, AttrNumber *attnums)
 
bool examine_opclause_args (List *args, Node **exprp, Const **cstp, bool *expronleftp)
 
Selectivity mcv_combine_selectivities (Selectivity simple_sel, Selectivity mcv_sel, Selectivity mcv_basesel, Selectivity mcv_totalsel)
 
Selectivity mcv_clauselist_selectivity (PlannerInfo *root, StatisticExtInfo *stat, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Selectivity *basesel, Selectivity *totalsel)
 
Selectivity mcv_clause_selectivity_or (PlannerInfo *root, StatisticExtInfo *stat, MCVList *mcv, Node *clause, bool **or_matches, Selectivity *basesel, Selectivity *overlap_mcvsel, Selectivity *overlap_basesel, Selectivity *totalsel)
 

Typedef Documentation

◆ DimensionInfo

◆ MultiSortSupport

◆ MultiSortSupportData

◆ SortItem

◆ StatsBuildData

Function Documentation

◆ build_attnums_array()

AttrNumber * build_attnums_array ( Bitmapset attrs,
int  nexprs,
int numattrs 
)
extern

Definition at line 987 of file extended_stats.c.

988{
989 int i,
990 j;
991 AttrNumber *attnums;
992 int num = bms_num_members(attrs);
993
994 if (numattrs)
995 *numattrs = num;
996
997 /* build attnums from the bitmapset */
998 attnums = palloc_array(AttrNumber, num);
999 i = 0;
1000 j = -1;
1001 while ((j = bms_next_member(attrs, j)) >= 0)
1002 {
1003 int attnum = (j - nexprs);
1004
1005 /*
1006 * Make sure the bitmap contains only user-defined attributes. As
1007 * bitmaps can't contain negative values, this can be violated in two
1008 * ways. Firstly, the bitmap might contain 0 as a member, and secondly
1009 * the integer value might be larger than MaxAttrNumber.
1010 */
1013 Assert(attnum >= (-nexprs));
1014
1015 attnums[i++] = (AttrNumber) attnum;
1016
1017 /* protect against overflows */
1018 Assert(i <= num);
1019 }
1020
1021 return attnums;
1022}
int16 AttrNumber
Definition attnum.h:21
#define AttributeNumberIsValid(attributeNumber)
Definition attnum.h:34
#define MaxAttrNumber
Definition attnum.h:24
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1425
int bms_num_members(const Bitmapset *a)
Definition bitmapset.c:879
#define Assert(condition)
Definition c.h:1002
#define palloc_array(type, count)
Definition fe_memutils.h:91
int j
Definition isn.c:78
int i
Definition isn.c:77
int16 attnum
static int fb(int x)

References Assert, attnum, AttributeNumberIsValid, bms_next_member(), bms_num_members(), fb(), i, j, MaxAttrNumber, and palloc_array.

◆ build_sorted_items()

SortItem * build_sorted_items ( StatsBuildData data,
int nitems,
MultiSortSupport  mss,
int  numattrs,
AttrNumber attnums 
)
extern

Definition at line 1032 of file extended_stats.c.

1035{
1036 int i,
1037 j,
1038 nrows;
1039 int nvalues = data->numrows * numattrs;
1040 Size len;
1041 SortItem *items;
1042 Datum *values;
1043 bool *isnull;
1044 char *ptr;
1045 int *typlen;
1046
1047 /* Compute the total amount of memory we need (both items and values). */
1048 len = MAXALIGN(data->numrows * sizeof(SortItem)) +
1049 nvalues * (sizeof(Datum) + sizeof(bool));
1050
1051 /* Allocate the memory and split it into the pieces. */
1052 ptr = palloc0(len);
1053
1054 /* items to sort */
1055 items = (SortItem *) ptr;
1056 /* MAXALIGN ensures that the following Datums are suitably aligned */
1057 ptr += MAXALIGN(data->numrows * sizeof(SortItem));
1058
1059 /* values and null flags */
1060 values = (Datum *) ptr;
1061 ptr += nvalues * sizeof(Datum);
1062
1063 isnull = (bool *) ptr;
1064 ptr += nvalues * sizeof(bool);
1065
1066 /* make sure we consumed the whole buffer exactly */
1067 Assert((ptr - (char *) items) == len);
1068
1069 /* fix the pointers to Datum and bool arrays */
1070 nrows = 0;
1071 for (i = 0; i < data->numrows; i++)
1072 {
1073 items[nrows].values = &values[nrows * numattrs];
1074 items[nrows].isnull = &isnull[nrows * numattrs];
1075
1076 nrows++;
1077 }
1078
1079 /* build a local cache of typlen for all attributes */
1080 typlen = palloc_array(int, data->nattnums);
1081 for (i = 0; i < data->nattnums; i++)
1082 typlen[i] = get_typlen(data->stats[i]->attrtypid);
1083
1084 nrows = 0;
1085 for (i = 0; i < data->numrows; i++)
1086 {
1087 bool toowide = false;
1088
1089 /* load the values/null flags from sample rows */
1090 for (j = 0; j < numattrs; j++)
1091 {
1092 Datum value;
1093 bool isnull;
1094 int attlen;
1095 AttrNumber attnum = attnums[j];
1096
1097 int idx;
1098
1099 /* match attnum to the pre-calculated data */
1100 for (idx = 0; idx < data->nattnums; idx++)
1101 {
1102 if (attnum == data->attnums[idx])
1103 break;
1104 }
1105
1106 Assert(idx < data->nattnums);
1107
1108 value = data->values[idx][i];
1109 isnull = data->nulls[idx][i];
1110 attlen = typlen[idx];
1111
1112 /*
1113 * If this is a varlena value, check if it's too wide and if yes
1114 * then skip the whole item. Otherwise detoast the value.
1115 *
1116 * XXX It may happen that we've already detoasted some preceding
1117 * values for the current item. We don't bother to cleanup those
1118 * on the assumption that those are small (below WIDTH_THRESHOLD)
1119 * and will be discarded at the end of analyze.
1120 */
1121 if ((!isnull) && (attlen == -1))
1122 {
1124 {
1125 toowide = true;
1126 break;
1127 }
1128
1130 }
1131
1132 items[nrows].values[j] = value;
1133 items[nrows].isnull[j] = isnull;
1134 }
1135
1136 if (toowide)
1137 continue;
1138
1139 nrows++;
1140 }
1141
1142 /* store the actual number of items (ignoring the too-wide ones) */
1143 *nitems = nrows;
1144
1145 /* all items were too wide */
1146 if (nrows == 0)
1147 {
1148 /* everything is allocated as a single chunk */
1149 pfree(items);
1150 return NULL;
1151 }
1152
1153 /* do the sort, using the multi-sort */
1154 qsort_interruptible(items, nrows, sizeof(SortItem),
1156
1157 return items;
1158}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:263
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define MAXALIGN(LEN)
Definition c.h:955
size_t Size
Definition c.h:748
Size toast_raw_datum_size(Datum value)
Definition detoast.c:545
#define WIDTH_THRESHOLD
int multi_sort_compare(const void *a, const void *b, void *arg)
#define PG_DETOAST_DATUM(datum)
Definition fmgr.h:240
#define nitems(x)
Definition indent.h:31
static struct @175 value
int16 get_typlen(Oid typid)
Definition lsyscache.c:2511
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc0(Size size)
Definition mcxt.c:1420
int16 attlen
const void size_t len
const void * data
void qsort_interruptible(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
uint64_t Datum
Definition postgres.h:70
#define PointerGetDatum(X)
Definition postgres.h:354
static ItemArray items

References Assert, attlen, attnum, data, fb(), get_typlen(), i, idx(), items, j, len, MAXALIGN, multi_sort_compare(), nitems, palloc0(), palloc_array, pfree(), PG_DETOAST_DATUM, PointerGetDatum, qsort_interruptible(), toast_raw_datum_size(), value, values, and WIDTH_THRESHOLD.

Referenced by dependency_degree(), and statext_mcv_build().

◆ compare_datums_simple()

int compare_datums_simple ( Datum  a,
Datum  b,
SortSupport  ssup 
)
extern

Definition at line 973 of file extended_stats.c.

974{
975 return ApplySortComparator(a, false, b, false, ssup);
976}
int b
Definition isn.c:74
int a
Definition isn.c:73
static int ApplySortComparator(Datum datum1, bool isNull1, Datum datum2, bool isNull2, SortSupport ssup)

References a, ApplySortComparator(), and b.

Referenced by compare_scalars_simple(), and statext_mcv_serialize().

◆ compare_scalars_simple()

int compare_scalars_simple ( const void a,
const void b,
void arg 
)
extern

Definition at line 965 of file extended_stats.c.

966{
967 return compare_datums_simple(*(const Datum *) a,
968 *(const Datum *) b,
969 (SortSupport) arg);
970}
Datum arg
Definition elog.c:1323
int compare_datums_simple(Datum a, Datum b, SortSupport ssup)

References a, arg, b, and compare_datums_simple().

Referenced by statext_mcv_serialize().

◆ examine_opclause_args()

bool examine_opclause_args ( List args,
Node **  exprp,
Const **  cstp,
bool expronleftp 
)
extern

Definition at line 2075 of file extended_stats.c.

2077{
2078 Node *expr;
2079 Const *cst;
2080 bool expronleft;
2081 Node *leftop,
2082 *rightop;
2083
2084 /* enforced by statext_is_compatible_clause_internal */
2085 Assert(list_length(args) == 2);
2086
2087 leftop = linitial(args);
2088 rightop = lsecond(args);
2089
2090 /* strip RelabelType from either side of the expression */
2091 if (IsA(leftop, RelabelType))
2092 leftop = (Node *) ((RelabelType *) leftop)->arg;
2093
2094 if (IsA(rightop, RelabelType))
2095 rightop = (Node *) ((RelabelType *) rightop)->arg;
2096
2097 if (IsA(rightop, Const))
2098 {
2099 expr = leftop;
2100 cst = (Const *) rightop;
2101 expronleft = true;
2102 }
2103 else if (IsA(leftop, Const))
2104 {
2105 expr = rightop;
2106 cst = (Const *) leftop;
2107 expronleft = false;
2108 }
2109 else
2110 return false;
2111
2112 /* return pointers to the extracted parts if requested */
2113 if (exprp)
2114 *exprp = expr;
2115
2116 if (cstp)
2117 *cstp = cst;
2118
2119 if (expronleftp)
2121
2122 return true;
2123}
#define IsA(nodeptr, _type_)
Definition nodes.h:162
static int list_length(const List *l)
Definition pg_list.h:152
#define linitial(l)
Definition pg_list.h:178
#define lsecond(l)
Definition pg_list.h:183
Definition nodes.h:133

References arg, Assert, fb(), IsA, linitial, list_length(), and lsecond.

Referenced by mcv_get_match_bitmap(), and statext_is_compatible_clause_internal().

◆ mcv_clause_selectivity_or()

Selectivity mcv_clause_selectivity_or ( PlannerInfo root,
StatisticExtInfo stat,
MCVList mcv,
Node clause,
bool **  or_matches,
Selectivity basesel,
Selectivity overlap_mcvsel,
Selectivity overlap_basesel,
Selectivity totalsel 
)
extern

Definition at line 2120 of file mcv.c.

2124{
2125 Selectivity s = 0.0;
2126 bool *new_matches;
2127
2128 /* build the OR-matches bitmap, if not built already */
2129 if (*or_matches == NULL)
2130 *or_matches = palloc0_array(bool, mcv->nitems);
2131
2132 /* build the match bitmap for the new clause */
2134 stat->exprs, mcv, false);
2135
2136 /*
2137 * Sum the frequencies for all the MCV items matching this clause and also
2138 * those matching the overlap between this clause and any of the preceding
2139 * clauses as described above.
2140 */
2141 *basesel = 0.0;
2142 *overlap_mcvsel = 0.0;
2143 *overlap_basesel = 0.0;
2144 *totalsel = 0.0;
2145 for (uint32 i = 0; i < mcv->nitems; i++)
2146 {
2147 *totalsel += mcv->items[i].frequency;
2148
2149 if (new_matches[i])
2150 {
2151 s += mcv->items[i].frequency;
2152 *basesel += mcv->items[i].base_frequency;
2153
2154 if ((*or_matches)[i])
2155 {
2156 *overlap_mcvsel += mcv->items[i].frequency;
2158 }
2159 }
2160
2161 /* update the OR-matches bitmap for the next clause */
2162 (*or_matches)[i] = (*or_matches)[i] || new_matches[i];
2163 }
2164
2166
2167 return s;
2168}
uint32_t uint32
Definition c.h:683
#define palloc0_array(type, count)
Definition fe_memutils.h:92
static bool * mcv_get_match_bitmap(PlannerInfo *root, List *clauses, Bitmapset *keys, List *exprs, MCVList *mcvlist, bool is_or)
Definition mcv.c:1596
double Selectivity
Definition nodes.h:258
#define list_make1(x1)
Definition pg_list.h:244
tree ctl root
Definition radixtree.h:1857
double frequency
Definition statistics.h:80
double base_frequency
Definition statistics.h:81
uint32 nitems
Definition statistics.h:91
MCVItem items[FLEXIBLE_ARRAY_MEMBER]
Definition statistics.h:94

References MCVItem::base_frequency, fb(), MCVItem::frequency, i, MCVList::items, list_make1, mcv_get_match_bitmap(), MCVList::nitems, palloc0_array, pfree(), and root.

Referenced by statext_mcv_clauselist_selectivity().

◆ mcv_clauselist_selectivity()

Selectivity mcv_clauselist_selectivity ( PlannerInfo root,
StatisticExtInfo stat,
List clauses,
int  varRelid,
JoinType  jointype,
SpecialJoinInfo sjinfo,
RelOptInfo rel,
Selectivity basesel,
Selectivity totalsel 
)
extern

Definition at line 2043 of file mcv.c.

2048{
2049 MCVList *mcv;
2050 Selectivity s = 0.0;
2051 RangeTblEntry *rte = root->simple_rte_array[rel->relid];
2052
2053 /* match/mismatch bitmap for each MCV item */
2054 bool *matches = NULL;
2055
2056 /* load the MCV list stored in the statistics object */
2057 mcv = statext_mcv_load(stat->statOid, rte->inh);
2058
2059 /* build a match bitmap for the clauses */
2060 matches = mcv_get_match_bitmap(root, clauses, stat->keys, stat->exprs,
2061 mcv, false);
2062
2063 /* sum frequencies for all the matching MCV items */
2064 *basesel = 0.0;
2065 *totalsel = 0.0;
2066 for (uint32 i = 0; i < mcv->nitems; i++)
2067 {
2068 *totalsel += mcv->items[i].frequency;
2069
2070 if (matches[i] != false)
2071 {
2072 *basesel += mcv->items[i].base_frequency;
2073 s += mcv->items[i].frequency;
2074 }
2075 }
2076
2077 return s;
2078}
MCVList * statext_mcv_load(Oid mvoid, bool inh)
Definition mcv.c:556
Index relid
Definition pathnodes.h:1069

References MCVItem::base_frequency, fb(), MCVItem::frequency, i, MCVList::items, mcv_get_match_bitmap(), MCVList::nitems, RelOptInfo::relid, root, and statext_mcv_load().

Referenced by statext_mcv_clauselist_selectivity().

◆ mcv_combine_selectivities()

Selectivity mcv_combine_selectivities ( Selectivity  simple_sel,
Selectivity  mcv_sel,
Selectivity  mcv_basesel,
Selectivity  mcv_totalsel 
)
extern

Definition at line 2001 of file mcv.c.

2005{
2008
2009 /* estimated selectivity of values not covered by MCV matches */
2012
2013 /* this non-MCV selectivity cannot exceed 1 - mcv_totalsel */
2014 if (other_sel > 1.0 - mcv_totalsel)
2015 other_sel = 1.0 - mcv_totalsel;
2016
2017 /* overall selectivity is the sum of the MCV and non-MCV parts */
2018 sel = mcv_sel + other_sel;
2020
2021 return sel;
2022}
#define CLAMP_PROBABILITY(p)
Definition selfuncs.h:63

References CLAMP_PROBABILITY, and fb().

Referenced by statext_mcv_clauselist_selectivity().

◆ multi_sort_add_dimension()

void multi_sort_add_dimension ( MultiSortSupport  mss,
int  sortdim,
Oid  oper,
Oid  collation 
)
extern

Definition at line 897 of file extended_stats.c.

899{
900 SortSupport ssup = &mss->ssup[sortdim];
901
903 ssup->ssup_collation = collation;
904 ssup->ssup_nulls_first = false;
905
907}
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition parse_oper.c:376
void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
MemoryContext ssup_cxt
Definition sortsupport.h:66

References CurrentMemoryContext, fb(), oper(), PrepareSortSupportFromOrderingOp(), SortSupportData::ssup_collation, SortSupportData::ssup_cxt, and SortSupportData::ssup_nulls_first.

Referenced by build_mss(), dependency_degree(), and ndistinct_for_combination().

◆ multi_sort_compare()

int multi_sort_compare ( const void a,
const void b,
void arg 
)
extern

Definition at line 911 of file extended_stats.c.

912{
914 const SortItem *ia = a;
915 const SortItem *ib = b;
916 int i;
917
918 for (i = 0; i < mss->ndims; i++)
919 {
920 int compare;
921
922 compare = ApplySortComparator(ia->values[i], ia->isnull[i],
923 ib->values[i], ib->isnull[i],
924 &mss->ssup[i]);
925
926 if (compare != 0)
927 return compare;
928 }
929
930 /* equal by default */
931 return 0;
932}
MultiSortSupportData * MultiSortSupport
static int compare(const void *arg1, const void *arg2)
Definition geqo_pool.c:145

References a, ApplySortComparator(), arg, b, compare(), fb(), and i.

Referenced by build_distinct_groups(), build_sorted_items(), count_distinct_groups(), ndistinct_for_combination(), and statext_mcv_build().

◆ multi_sort_compare_dim()

int multi_sort_compare_dim ( int  dim,
const SortItem a,
const SortItem b,
MultiSortSupport  mss 
)
extern

Definition at line 936 of file extended_stats.c.

938{
939 return ApplySortComparator(a->values[dim], a->isnull[dim],
940 b->values[dim], b->isnull[dim],
941 &mss->ssup[dim]);
942}

References a, ApplySortComparator(), b, and fb().

Referenced by dependency_degree().

◆ multi_sort_compare_dims()

int multi_sort_compare_dims ( int  start,
int  end,
const SortItem a,
const SortItem b,
MultiSortSupport  mss 
)
extern

Definition at line 945 of file extended_stats.c.

948{
949 int dim;
950
951 for (dim = start; dim <= end; dim++)
952 {
953 int r = ApplySortComparator(a->values[dim], a->isnull[dim],
954 b->values[dim], b->isnull[dim],
955 &mss->ssup[dim]);
956
957 if (r != 0)
958 return r;
959 }
960
961 return 0;
962}
return str start

References a, ApplySortComparator(), b, fb(), and start.

Referenced by dependency_degree().

◆ multi_sort_init()

MultiSortSupport multi_sort_init ( int  ndims)
extern

Definition at line 878 of file extended_stats.c.

879{
881
882 Assert(ndims >= 2);
883
885 + sizeof(SortSupportData) * ndims);
886
887 mss->ndims = ndims;
888
889 return mss;
890}

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

Referenced by build_mss(), dependency_degree(), and ndistinct_for_combination().

◆ statext_dependencies_build()

MVDependencies * statext_dependencies_build ( StatsBuildData data)
extern

Definition at line 342 of file dependencies.c.

343{
344 int i,
345 k;
346
347 /* result */
348 MVDependencies *dependencies = NULL;
349 MemoryContext cxt;
350
351 Assert(data->nattnums >= 2);
352
353 /* tracks memory allocated by dependency_degree calls */
355 "dependency_degree cxt",
357
358 /*
359 * We'll try build functional dependencies starting from the smallest ones
360 * covering just 2 columns, to the largest ones, covering all columns
361 * included in the statistics object. We start from the smallest ones
362 * because we want to be able to skip already implied ones.
363 */
364 for (k = 2; k <= data->nattnums; k++)
365 {
366 AttrNumber *dependency; /* array with k elements */
367
368 /* prepare a DependencyGenerator of variation */
370
371 /* generate all possible variations of k values (out of n) */
372 while ((dependency = DependencyGenerator_next(DependencyGenerator)))
373 {
374 double degree;
375 MVDependency *d;
377
378 /* release memory used by dependency degree calculation */
380
381 /* compute how valid the dependency seems */
382 degree = dependency_degree(data, k, dependency);
383
386
387 /*
388 * if the dependency seems entirely invalid, don't store it
389 */
390 if (degree == 0.0)
391 continue;
392
393 d = (MVDependency *) palloc0(offsetof(MVDependency, attributes)
394 + k * sizeof(AttrNumber));
395
396 /* copy the dependency (and keep the indexes into stxkeys) */
397 d->degree = degree;
398 d->nattributes = k;
399 for (i = 0; i < k; i++)
400 d->attributes[i] = data->attnums[dependency[i]];
401
402 /* initialize the list of dependencies */
403 if (dependencies == NULL)
404 {
405 dependencies = palloc0_object(MVDependencies);
406
407 dependencies->magic = STATS_DEPS_MAGIC;
408 dependencies->type = STATS_DEPS_TYPE_BASIC;
409 dependencies->ndeps = 0;
410 }
411
412 dependencies->ndeps++;
413 dependencies = (MVDependencies *) repalloc(dependencies,
415 + dependencies->ndeps * sizeof(MVDependency *));
416
417 dependencies->deps[dependencies->ndeps - 1] = d;
418 }
419
420 /*
421 * we're done with variations of k elements, so free the
422 * DependencyGenerator
423 */
425 }
426
428
429 return dependencies;
430}
static AttrNumber * DependencyGenerator_next(DependencyGenerator state)
static void DependencyGenerator_free(DependencyGenerator state)
static DependencyGenerator DependencyGenerator_init(int n, int k)
static double dependency_degree(StatsBuildData *data, int k, AttrNumber *dependency)
#define palloc0_object(type)
Definition fe_memutils.h:90
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:406
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1635
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:475
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
#define STATS_DEPS_MAGIC
Definition statistics.h:43
#define STATS_DEPS_TYPE_BASIC
Definition statistics.h:44
MVDependency * deps[FLEXIBLE_ARRAY_MEMBER]
Definition statistics.h:62
AttrNumber nattributes
Definition statistics.h:53
double degree
Definition statistics.h:52
AttrNumber attributes[FLEXIBLE_ARRAY_MEMBER]
Definition statistics.h:54

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, MVDependency::attributes, CurrentMemoryContext, data, MVDependency::degree, dependency_degree(), DependencyGenerator_free(), DependencyGenerator_init(), DependencyGenerator_next(), MVDependencies::deps, fb(), i, MVDependencies::magic, MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), MVDependency::nattributes, MVDependencies::ndeps, palloc0(), palloc0_object, repalloc(), STATS_DEPS_MAGIC, STATS_DEPS_TYPE_BASIC, and MVDependencies::type.

Referenced by BuildRelationExtStatistics().

◆ statext_dependencies_deserialize()

MVDependencies * statext_dependencies_deserialize ( bytea data)
extern

Definition at line 491 of file dependencies.c.

492{
494 MVDependencies *dependencies;
495 char *tmp;
496
497 if (data == NULL)
498 return NULL;
499
501 elog(ERROR, "invalid MVDependencies size %zu (expected at least %zu)",
503
504 /* read the MVDependencies header */
505 dependencies = palloc0_object(MVDependencies);
506
507 /* initialize pointer to the data part (skip the varlena header) */
508 tmp = VARDATA_ANY(data);
509
510 /* read the header fields and perform basic sanity checks */
511 memcpy(&dependencies->magic, tmp, sizeof(uint32));
512 tmp += sizeof(uint32);
513 memcpy(&dependencies->type, tmp, sizeof(uint32));
514 tmp += sizeof(uint32);
515 memcpy(&dependencies->ndeps, tmp, sizeof(uint32));
516 tmp += sizeof(uint32);
517
518 if (dependencies->magic != STATS_DEPS_MAGIC)
519 elog(ERROR, "invalid dependency magic %d (expected %d)",
520 dependencies->magic, STATS_DEPS_MAGIC);
521
522 if (dependencies->type != STATS_DEPS_TYPE_BASIC)
523 elog(ERROR, "invalid dependency type %d (expected %d)",
524 dependencies->type, STATS_DEPS_TYPE_BASIC);
525
526 if (dependencies->ndeps == 0)
527 elog(ERROR, "invalid zero-length item array in MVDependencies");
528
529 /* what minimum bytea size do we expect for those parameters */
530 min_expected_size = MinSizeOfItems(dependencies->ndeps);
531
533 elog(ERROR, "invalid dependencies size %zu (expected at least %zu)",
535
536 /* allocate space for the MCV items */
537 dependencies = repalloc(dependencies, offsetof(MVDependencies, deps)
538 + (dependencies->ndeps * sizeof(MVDependency *)));
539
540 for (uint32 i = 0; i < dependencies->ndeps; i++)
541 {
542 double degree;
543 AttrNumber k;
544 MVDependency *d;
545
546 /* degree of validity */
547 memcpy(&degree, tmp, sizeof(double));
548 tmp += sizeof(double);
549
550 /* number of attributes */
551 memcpy(&k, tmp, sizeof(AttrNumber));
552 tmp += sizeof(AttrNumber);
553
554 /* is the number of attributes valid? */
555 Assert((k >= 2) && (k <= STATS_MAX_DIMENSIONS));
556
557 /* now that we know the number of attributes, allocate the dependency */
558 d = (MVDependency *) palloc0(offsetof(MVDependency, attributes)
559 + (k * sizeof(AttrNumber)));
560
561 d->degree = degree;
562 d->nattributes = k;
563
564 /* copy attribute numbers */
565 memcpy(d->attributes, tmp, sizeof(AttrNumber) * d->nattributes);
566 tmp += sizeof(AttrNumber) * d->nattributes;
567
568 dependencies->deps[i] = d;
569
570 /* still within the bytea */
571 Assert(tmp <= ((char *) data + VARSIZE_ANY(data)));
572 }
573
574 /* we should have consumed the whole bytea exactly */
575 Assert(tmp == ((char *) data + VARSIZE_ANY(data)));
576
577 return dependencies;
578}
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
#define SizeOfHeader
#define MinSizeOfItems(ndeps)
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define STATS_MAX_DIMENSIONS
Definition statistics.h:19
static Size VARSIZE_ANY(const void *PTR)
Definition varatt.h:460
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition varatt.h:472
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486

References Assert, MVDependency::attributes, data, MVDependency::degree, MVDependencies::deps, elog, ERROR, fb(), i, MVDependencies::magic, memcpy(), MinSizeOfItems, MVDependency::nattributes, MVDependencies::ndeps, palloc0(), palloc0_object, repalloc(), SizeOfHeader, STATS_DEPS_MAGIC, STATS_DEPS_TYPE_BASIC, STATS_MAX_DIMENSIONS, MVDependencies::type, VARDATA_ANY(), VARSIZE_ANY(), and VARSIZE_ANY_EXHDR().

Referenced by extended_statistics_update(), pg_dependencies_out(), and statext_dependencies_load().

◆ statext_dependencies_free()

void statext_dependencies_free ( MVDependencies dependencies)
extern

Definition at line 584 of file dependencies.c.

585{
586 for (uint32 i = 0; i < dependencies->ndeps; i++)
587 pfree(dependencies->deps[i]);
588 pfree(dependencies);
589}

References MVDependencies::deps, i, MVDependencies::ndeps, and pfree().

Referenced by extended_statistics_update().

◆ statext_dependencies_serialize()

bytea * statext_dependencies_serialize ( MVDependencies dependencies)
extern

Definition at line 437 of file dependencies.c.

438{
439 bytea *output;
440 char *tmp;
441 Size len;
442
443 /* we need to store ndeps, with a number of attributes for each one */
445
446 /* and also include space for the actual attribute numbers and degrees */
447 for (uint32 i = 0; i < dependencies->ndeps; i++)
448 len += SizeOfItem(dependencies->deps[i]->nattributes);
449
450 output = (bytea *) palloc0(len);
452
453 tmp = VARDATA(output);
454
455 /* Store the base struct values (magic, type, ndeps) */
456 memcpy(tmp, &dependencies->magic, sizeof(uint32));
457 tmp += sizeof(uint32);
458 memcpy(tmp, &dependencies->type, sizeof(uint32));
459 tmp += sizeof(uint32);
460 memcpy(tmp, &dependencies->ndeps, sizeof(uint32));
461 tmp += sizeof(uint32);
462
463 /* store number of attributes and attribute numbers for each dependency */
464 for (uint32 i = 0; i < dependencies->ndeps; i++)
465 {
466 MVDependency *d = dependencies->deps[i];
467
468 memcpy(tmp, &d->degree, sizeof(double));
469 tmp += sizeof(double);
470
471 memcpy(tmp, &d->nattributes, sizeof(AttrNumber));
472 tmp += sizeof(AttrNumber);
473
474 memcpy(tmp, d->attributes, sizeof(AttrNumber) * d->nattributes);
475 tmp += sizeof(AttrNumber) * d->nattributes;
476
477 /* protect against overflow */
478 Assert(tmp <= ((char *) output + len));
479 }
480
481 /* make sure we've produced exactly the right amount of data */
482 Assert(tmp == ((char *) output + len));
483
484 return output;
485}
#define VARHDRSZ
Definition c.h:840
#define SizeOfItem(natts)
FILE * output
Definition c.h:835
static char * VARDATA(const void *PTR)
Definition varatt.h:305
static void SET_VARSIZE(void *PTR, Size len)
Definition varatt.h:432

References Assert, MVDependency::attributes, MVDependency::degree, MVDependencies::deps, fb(), i, len, MVDependencies::magic, memcpy(), MVDependency::nattributes, MVDependencies::ndeps, output, palloc0(), SET_VARSIZE(), SizeOfHeader, SizeOfItem, MVDependencies::type, VARDATA(), and VARHDRSZ.

Referenced by build_mvdependencies(), and statext_store().

◆ statext_dependencies_validate()

bool statext_dependencies_validate ( const MVDependencies dependencies,
const int2vector stxkeys,
int  numexprs,
int  elevel 
)
extern

Definition at line 604 of file dependencies.c.

607{
609
610 /* Scan through each dependency entry */
611 for (uint32 i = 0; i < dependencies->ndeps; i++)
612 {
613 const MVDependency *dep = dependencies->deps[i];
614
615 /*
616 * Cross-check each attribute in a dependency entry with the extended
617 * stats object definition.
618 */
619 for (int j = 0; j < dep->nattributes; j++)
620 {
622 bool ok = false;
623
624 if (attnum > 0)
625 {
626 /* attribute number in stxkeys */
627 for (int k = 0; k < stxkeys->dim1; k++)
628 {
629 if (attnum == stxkeys->values[k])
630 {
631 ok = true;
632 break;
633 }
634 }
635 }
636 else if ((attnum < 0) && (attnum >= attnum_expr_lowbound))
637 {
638 /* attribute number for an expression */
639 ok = true;
640 }
641
642 if (!ok)
643 {
644 ereport(elevel,
646 errmsg("could not validate \"%s\" object: invalid attribute number %d found",
647 "pg_dependencies", attnum)));
648 return false;
649 }
650 }
651 }
652
653 return true;
654}
int errcode(int sqlerrcode)
Definition elog.c:875
#define ereport(elevel,...)
Definition elog.h:152
static char * errmsg

References attnum, MVDependency::attributes, MVDependencies::deps, ereport, errcode(), errmsg, fb(), i, j, and MVDependencies::ndeps.

Referenced by extended_statistics_update().

◆ statext_mcv_build()

MCVList * statext_mcv_build ( StatsBuildData data,
double  totalrows,
int  stattarget 
)
extern

Definition at line 178 of file mcv.c.

179{
180 int i,
181 numattrs,
182 numrows,
183 ngroups,
184 nitems;
185 double mincount;
190
191 /* comparator for all the columns */
192 mss = build_mss(data);
193
194 /* sort the rows */
196 data->nattnums, data->attnums);
197
198 if (!items)
199 return NULL;
200
201 /* for convenience */
202 numattrs = data->nattnums;
203 numrows = data->numrows;
204
205 /* transform the sorted rows into groups (sorted by frequency) */
207
208 /*
209 * The maximum number of MCV items to store, based on the statistics
210 * target we computed for the statistics object (from the target set for
211 * the object itself, attributes and the system default). In any case, we
212 * can't keep more groups than we have available.
213 */
214 nitems = stattarget;
215 if (nitems > ngroups)
216 nitems = ngroups;
217
218 /*
219 * Decide how many items to keep in the MCV list. We can't use the same
220 * algorithm as per-column MCV lists, because that only considers the
221 * actual group frequency - but we're primarily interested in how the
222 * actual frequency differs from the base frequency (product of simple
223 * per-column frequencies, as if the columns were independent).
224 *
225 * Using the same algorithm might exclude items that are close to the
226 * "average" frequency of the sample. But that does not say whether the
227 * observed frequency is close to the base frequency or not. We also need
228 * to consider unexpectedly uncommon items (again, compared to the base
229 * frequency), and the single-column algorithm does not have to.
230 *
231 * We simply decide how many items to keep by computing the minimum count
232 * using get_mincount_for_mcv_list() and then keep all items that seem to
233 * be more common than that.
234 */
236
237 /*
238 * Walk the groups until we find the first group with a count below the
239 * mincount threshold (the index of that group is the number of groups we
240 * want to keep).
241 */
242 for (i = 0; i < nitems; i++)
243 {
244 if (groups[i].count < mincount)
245 {
246 nitems = i;
247 break;
248 }
249 }
250
251 /*
252 * At this point, we know the number of items for the MCV list. There
253 * might be none (for uniform distribution with many groups), and in that
254 * case, there will be no MCV list. Otherwise, construct the MCV list.
255 */
256 if (nitems > 0)
257 {
258 int j;
261
262 /* frequencies for values in each attribute */
263 SortItem **freqs;
264 int *nfreqs;
265
266 /* used to search values */
268 + sizeof(SortSupportData));
269
270 /* compute frequencies for values in each column */
273
274 /*
275 * Allocate the MCV list structure, set the global parameters.
276 */
278 sizeof(MCVItem) * nitems);
279
280 mcvlist->magic = STATS_MCV_MAGIC;
282 mcvlist->ndimensions = numattrs;
283 mcvlist->nitems = nitems;
284
285 /* store info about data type OIDs */
286 for (i = 0; i < numattrs; i++)
287 mcvlist->types[i] = data->stats[i]->attrtypid;
288
289 /* Copy the first chunk of groups into the result. */
290 for (i = 0; i < nitems; i++)
291 {
292 /* just point to the proper place in the list */
293 MCVItem *item = &mcvlist->items[i];
294
296 item->isnull = palloc_array(bool, numattrs);
297
298 /* copy values for the group */
299 memcpy(item->values, groups[i].values, sizeof(Datum) * numattrs);
300 memcpy(item->isnull, groups[i].isnull, sizeof(bool) * numattrs);
301
302 /* groups should be sorted by frequency in descending order */
303 Assert((i == 0) || (groups[i - 1].count >= groups[i].count));
304
305 /* group frequency */
306 item->frequency = (double) groups[i].count / numrows;
307
308 /* base frequency, if the attributes were independent */
309 item->base_frequency = 1.0;
310 for (j = 0; j < numattrs; j++)
311 {
312 SortItem *freq;
313
314 /* single dimension */
315 tmp->ndims = 1;
316 tmp->ssup[0] = mss->ssup[j];
317
318 /* fill search key */
319 key.values = &groups[i].values[j];
320 key.isnull = &groups[i].isnull[j];
321
322 freq = (SortItem *) bsearch_arg(&key, freqs[j], nfreqs[j],
323 sizeof(SortItem),
324 multi_sort_compare, tmp);
325
326 item->base_frequency *= ((double) freq->count) / numrows;
327 }
328 }
329
330 pfree(nfreqs);
331 pfree(freqs);
332 }
333
334 pfree(items);
335 pfree(groups);
336
337 return mcvlist;
338}
SortItem * build_sorted_items(StatsBuildData *data, int *nitems, MultiSortSupport mss, int numattrs, AttrNumber *attnums)
static MultiSortSupport build_mss(StatsBuildData *data)
Definition mcv.c:345
static double get_mincount_for_mcv_list(int samplerows, double totalrows)
Definition mcv.c:146
static SortItem ** build_column_frequencies(SortItem *groups, int ngroups, MultiSortSupport mss, int *ncounts)
Definition mcv.c:488
static SortItem * build_distinct_groups(int numrows, SortItem *items, MultiSortSupport mss, int *ndistinct)
Definition mcv.c:422
void * palloc(Size size)
Definition mcxt.c:1390
void * bsearch_arg(const void *key, const void *base0, size_t nmemb, size_t size, int(*compar)(const void *, const void *, void *), void *arg)
Definition bsearch_arg.c:55
#define STATS_MCV_TYPE_BASIC
Definition statistics.h:67
#define STATS_MCV_MAGIC
Definition statistics.h:66
bool * isnull
Definition statistics.h:82
Datum * values
Definition statistics.h:83
SortSupportData ssup[FLEXIBLE_ARRAY_MEMBER]

References Assert, MCVItem::base_frequency, bsearch_arg(), build_column_frequencies(), build_distinct_groups(), build_mss(), build_sorted_items(), data, fb(), MCVItem::frequency, get_mincount_for_mcv_list(), i, MCVItem::isnull, items, j, memcpy(), multi_sort_compare(), MultiSortSupportData::ndims, nitems, palloc(), palloc0(), palloc0_array, palloc_array, pfree(), MultiSortSupportData::ssup, STATS_MCV_MAGIC, STATS_MCV_TYPE_BASIC, and MCVItem::values.

Referenced by BuildRelationExtStatistics().

◆ statext_mcv_deserialize()

MCVList * statext_mcv_deserialize ( bytea data)
extern

Definition at line 993 of file mcv.c.

994{
995 int dim,
996 i;
999 char *raw;
1000 char *ptr;
1001 char *endptr PG_USED_FOR_ASSERTS_ONLY;
1002
1003 int ndims,
1004 nitems;
1005 DimensionInfo *info = NULL;
1006
1007 /* local allocation buffer (used only for deserialization) */
1008 Datum **map = NULL;
1009
1010 /* MCV list */
1011 Size mcvlen;
1012
1013 /* buffer used for the result */
1014 Size datalen;
1015 char *dataptr;
1016 char *valuesptr;
1017 char *isnullptr;
1018
1019 if (data == NULL)
1020 return NULL;
1021
1022 /*
1023 * We can't possibly deserialize a MCV list if there's not even a complete
1024 * header. We need an explicit formula here, because we serialize the
1025 * header fields one by one, so we need to ignore struct alignment.
1026 */
1028 elog(ERROR, "invalid MCV size %zu (expected at least %zu)",
1030
1031 /* read the MCV list header */
1033
1034 /* pointer to the data part (skip the varlena header) */
1035 raw = (char *) data;
1036 ptr = VARDATA_ANY(raw);
1037 endptr = raw + VARSIZE_ANY(data);
1038
1039 /* get the header and perform further sanity checks */
1040 memcpy(&mcvlist->magic, ptr, sizeof(uint32));
1041 ptr += sizeof(uint32);
1042
1043 memcpy(&mcvlist->type, ptr, sizeof(uint32));
1044 ptr += sizeof(uint32);
1045
1046 memcpy(&mcvlist->nitems, ptr, sizeof(uint32));
1047 ptr += sizeof(uint32);
1048
1049 memcpy(&mcvlist->ndimensions, ptr, sizeof(AttrNumber));
1050 ptr += sizeof(AttrNumber);
1051
1052 if (mcvlist->magic != STATS_MCV_MAGIC)
1053 elog(ERROR, "invalid MCV magic %u (expected %u)",
1054 mcvlist->magic, STATS_MCV_MAGIC);
1055
1056 if (mcvlist->type != STATS_MCV_TYPE_BASIC)
1057 elog(ERROR, "invalid MCV type %u (expected %u)",
1059
1060 if (mcvlist->ndimensions == 0)
1061 elog(ERROR, "invalid zero-length dimension array in MCVList");
1062 else if ((mcvlist->ndimensions > STATS_MAX_DIMENSIONS) ||
1063 (mcvlist->ndimensions < 0))
1064 elog(ERROR, "invalid length (%d) dimension array in MCVList",
1065 mcvlist->ndimensions);
1066
1067 if (mcvlist->nitems == 0)
1068 elog(ERROR, "invalid zero-length item array in MCVList");
1069 else if (mcvlist->nitems > STATS_MCVLIST_MAX_ITEMS)
1070 elog(ERROR, "invalid length (%u) item array in MCVList",
1071 mcvlist->nitems);
1072
1073 nitems = mcvlist->nitems;
1074 ndims = mcvlist->ndimensions;
1075
1076 /*
1077 * Check amount of data including DimensionInfo for all dimensions and
1078 * also the serialized items (including uint16 indexes). Also, walk
1079 * through the dimension information and add it to the sum.
1080 */
1082
1083 /*
1084 * Check that we have at least the dimension and info records, along with
1085 * the items. We don't know the size of the serialized values yet. We need
1086 * to do this check first, before accessing the dimension info.
1087 */
1089 elog(ERROR, "invalid MCV size %zu (expected %zu)",
1091
1092 /* Now copy the array of type Oids. */
1093 memcpy(mcvlist->types, ptr, sizeof(Oid) * ndims);
1094 ptr += (sizeof(Oid) * ndims);
1095
1096 /* Now it's safe to access the dimension info. */
1097 info = palloc(ndims * sizeof(DimensionInfo));
1098
1099 memcpy(info, ptr, ndims * sizeof(DimensionInfo));
1100 ptr += (ndims * sizeof(DimensionInfo));
1101
1102 /* account for the value arrays */
1103 for (dim = 0; dim < ndims; dim++)
1104 {
1105 /*
1106 * XXX I wonder if we can/should rely on asserts here. Maybe those
1107 * checks should be done every time?
1108 */
1109 Assert(info[dim].nvalues >= 0);
1110 Assert(info[dim].nbytes >= 0);
1111
1112 expected_size += info[dim].nbytes;
1113 }
1114
1115 /*
1116 * Now we know the total expected MCV size, including all the pieces
1117 * (header, dimension info. items and deduplicated data). So do the final
1118 * check on size.
1119 */
1121 elog(ERROR, "invalid MCV size %zu (expected %zu)",
1123
1124 /*
1125 * We need an array of Datum values for each dimension, so that we can
1126 * easily translate the uint16 indexes later. We also need a top-level
1127 * array of pointers to those per-dimension arrays.
1128 *
1129 * While allocating the arrays for dimensions, compute how much space we
1130 * need for a copy of the by-ref data, as we can't simply point to the
1131 * original values (it might go away).
1132 */
1133 datalen = 0; /* space for by-ref data */
1134 map = palloc_array(Datum *, ndims);
1135
1136 for (dim = 0; dim < ndims; dim++)
1137 {
1138 map[dim] = palloc_array(Datum, info[dim].nvalues);
1139
1140 /* space needed for a copy of data for by-ref types */
1141 datalen += info[dim].nbytes_aligned;
1142 }
1143
1144 /*
1145 * Now resize the MCV list so that the allocation includes all the data.
1146 *
1147 * Allocate space for a copy of the data, as we can't simply reference the
1148 * serialized data - it's not aligned properly, and it may disappear while
1149 * we're still using the MCV list, e.g. due to catcache release.
1150 *
1151 * We do care about alignment here, because we will allocate all the
1152 * pieces at once, but then use pointers to different parts.
1153 */
1154 mcvlen = MAXALIGN(offsetof(MCVList, items) + (sizeof(MCVItem) * nitems));
1155
1156 /* arrays of values and isnull flags for all MCV items */
1157 mcvlen += nitems * MAXALIGN(sizeof(Datum) * ndims);
1158 mcvlen += nitems * MAXALIGN(sizeof(bool) * ndims);
1159
1160 /* we don't quite need to align this, but it makes some asserts easier */
1161 mcvlen += MAXALIGN(datalen);
1162
1163 /* now resize the deserialized MCV list, and compute pointers to parts */
1165
1166 /* pointer to the beginning of values/isnull arrays */
1167 valuesptr = (char *) mcvlist
1168 + MAXALIGN(offsetof(MCVList, items) + (sizeof(MCVItem) * nitems));
1169
1170 isnullptr = valuesptr + (nitems * MAXALIGN(sizeof(Datum) * ndims));
1171
1172 dataptr = isnullptr + (nitems * MAXALIGN(sizeof(bool) * ndims));
1173
1174 /*
1175 * Build mapping (index => value) for translating the serialized data into
1176 * the in-memory representation.
1177 */
1178 for (dim = 0; dim < ndims; dim++)
1179 {
1180 /* remember start position in the input array */
1181 char *start PG_USED_FOR_ASSERTS_ONLY = ptr;
1182
1183 if (info[dim].typbyval)
1184 {
1185 /* for by-val types we simply copy data into the mapping */
1186 for (i = 0; i < info[dim].nvalues; i++)
1187 {
1188 Datum v = 0;
1189
1190 memcpy(&v, ptr, info[dim].typlen);
1191 ptr += info[dim].typlen;
1192
1193 map[dim][i] = fetch_att(&v, true, info[dim].typlen);
1194
1195 /* no under/overflow of input array */
1196 Assert(ptr <= (start + info[dim].nbytes));
1197 }
1198 }
1199 else
1200 {
1201 /* for by-ref types we need to also make a copy of the data */
1202
1203 /* passed by reference, but fixed length (name, tid, ...) */
1204 if (info[dim].typlen > 0)
1205 {
1206 for (i = 0; i < info[dim].nvalues; i++)
1207 {
1208 memcpy(dataptr, ptr, info[dim].typlen);
1209 ptr += info[dim].typlen;
1210
1211 /* just point into the array */
1212 map[dim][i] = PointerGetDatum(dataptr);
1213 dataptr += MAXALIGN(info[dim].typlen);
1214 }
1215 }
1216 else if (info[dim].typlen == -1)
1217 {
1218 /* varlena */
1219 for (i = 0; i < info[dim].nvalues; i++)
1220 {
1221 uint32 len;
1222
1223 /* read the uint32 length */
1224 memcpy(&len, ptr, sizeof(uint32));
1225 ptr += sizeof(uint32);
1226
1227 /* the length is data-only */
1228 SET_VARSIZE(dataptr, len + VARHDRSZ);
1229 memcpy(VARDATA(dataptr), ptr, len);
1230 ptr += len;
1231
1232 /* just point into the array */
1233 map[dim][i] = PointerGetDatum(dataptr);
1234
1235 /* skip to place of the next deserialized value */
1236 dataptr += MAXALIGN(len + VARHDRSZ);
1237 }
1238 }
1239 else if (info[dim].typlen == -2)
1240 {
1241 /* cstring */
1242 for (i = 0; i < info[dim].nvalues; i++)
1243 {
1244 uint32 len;
1245
1246 memcpy(&len, ptr, sizeof(uint32));
1247 ptr += sizeof(uint32);
1248
1249 memcpy(dataptr, ptr, len);
1250 ptr += len;
1251
1252 /* just point into the array */
1253 map[dim][i] = PointerGetDatum(dataptr);
1254 dataptr += MAXALIGN(len);
1255 }
1256 }
1257
1258 /* no under/overflow of input array */
1259 Assert(ptr <= (start + info[dim].nbytes));
1260
1261 /* no overflow of the output mcv value */
1262 Assert(dataptr <= ((char *) mcvlist + mcvlen));
1263 }
1264
1265 /* check we consumed input data for this dimension exactly */
1266 Assert(ptr == (start + info[dim].nbytes));
1267 }
1268
1269 /* we should have also filled the MCV list exactly */
1270 Assert(dataptr == ((char *) mcvlist + mcvlen));
1271
1272 /* deserialize the MCV items and translate the indexes to Datums */
1273 for (i = 0; i < nitems; i++)
1274 {
1275 MCVItem *item = &mcvlist->items[i];
1276
1277 item->values = (Datum *) valuesptr;
1278 valuesptr += MAXALIGN(sizeof(Datum) * ndims);
1279
1280 item->isnull = (bool *) isnullptr;
1281 isnullptr += MAXALIGN(sizeof(bool) * ndims);
1282
1283 memcpy(item->isnull, ptr, sizeof(bool) * ndims);
1284 ptr += sizeof(bool) * ndims;
1285
1286 memcpy(&item->frequency, ptr, sizeof(double));
1287 ptr += sizeof(double);
1288
1289 memcpy(&item->base_frequency, ptr, sizeof(double));
1290 ptr += sizeof(double);
1291
1292 /* finally translate the indexes (for non-NULL only) */
1293 for (dim = 0; dim < ndims; dim++)
1294 {
1295 uint16 index;
1296
1297 memcpy(&index, ptr, sizeof(uint16));
1298 ptr += sizeof(uint16);
1299
1300 if (item->isnull[dim])
1301 continue;
1302
1303 item->values[dim] = map[dim][index];
1304 }
1305
1306 /* check we're not overflowing the input */
1307 Assert(ptr <= endptr);
1308 }
1309
1310 /* check that we processed all the data */
1311 Assert(ptr == endptr);
1312
1313 /* release the buffers used for mapping */
1314 for (dim = 0; dim < ndims; dim++)
1315 pfree(map[dim]);
1316
1317 pfree(map);
1318
1319 return mcvlist;
1320}
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:308
uint16_t uint16
Definition c.h:682
#define MinSizeOfMCVList
Definition mcv.c:57
#define SizeOfMCVList(ndims, nitems)
Definition mcv.c:66
unsigned int Oid
#define STATS_MCVLIST_MAX_ITEMS
Definition statistics.h:70
Definition type.h:97
static Datum fetch_att(const void *T, bool attbyval, int attlen)
Definition tupmacs.h:108

References Assert, MCVItem::base_frequency, data, elog, ERROR, fb(), fetch_att(), MCVItem::frequency, i, MCVItem::isnull, items, len, MAXALIGN, memcpy(), MinSizeOfMCVList, DimensionInfo::nbytes, DimensionInfo::nbytes_aligned, nitems, DimensionInfo::nvalues, palloc(), palloc0(), palloc_array, pfree(), PG_USED_FOR_ASSERTS_ONLY, PointerGetDatum, repalloc(), SET_VARSIZE(), SizeOfMCVList, start, STATS_MAX_DIMENSIONS, STATS_MCV_MAGIC, STATS_MCV_TYPE_BASIC, STATS_MCVLIST_MAX_ITEMS, DimensionInfo::typlen, MCVItem::values, VARDATA(), VARDATA_ANY(), VARHDRSZ, and VARSIZE_ANY().

Referenced by pg_stats_ext_mcvlist_items(), and statext_mcv_load().

◆ statext_mcv_free()

void statext_mcv_free ( MCVList mcvlist)
extern

Definition at line 2174 of file mcv.c.

2175{
2176 for (uint32 i = 0; i < mcvlist->nitems; i++)
2177 {
2178 MCVItem *item = &mcvlist->items[i];
2179
2180 pfree(item->values);
2181 pfree(item->isnull);
2182 }
2183 pfree(mcvlist);
2184}

References fb(), i, MCVItem::isnull, pfree(), and MCVItem::values.

Referenced by statext_mcv_import().

◆ statext_mcv_import()

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 
)
extern

Definition at line 2199 of file mcv.c.

2203{
2205 bytea *bytes;
2207
2208 /*
2209 * Allocate the MCV list structure, set the global parameters.
2210 */
2212 (sizeof(MCVItem) * nitems));
2213
2214 mcvlist->magic = STATS_MCV_MAGIC;
2216 mcvlist->ndimensions = numattrs;
2217 mcvlist->nitems = nitems;
2218
2219 /* Set the values for the 1-D arrays and allocate space for the 2-D arrays */
2220 for (int i = 0; i < nitems; i++)
2221 {
2222 MCVItem *item = &mcvlist->items[i];
2223
2224 item->frequency = freqs[i];
2225 item->base_frequency = base_freqs[i];
2226 item->values = (Datum *) palloc0_array(Datum, numattrs);
2227 item->isnull = (bool *) palloc0_array(bool, numattrs);
2228 }
2229
2230 /*
2231 * Walk through each dimension, determine the input function for that
2232 * type, and then attempt to convert all values in that column via that
2233 * function. We approach this column-wise because it is simpler to deal
2234 * with one input function at time, and possibly more cache-friendly.
2235 */
2236 for (int j = 0; j < numattrs; j++)
2237 {
2238 FmgrInfo finfo;
2239 Oid ioparam;
2240 Oid infunc;
2241 int index = j;
2242
2244 fmgr_info(infunc, &finfo);
2245
2246 /* store info about data type OIDs */
2247 mcvlist->types[j] = atttypids[j];
2248
2249 for (int i = 0; i < nitems; i++)
2250 {
2251 MCVItem *item = &mcvlist->items[i];
2252
2253 if (mcv_nulls[index])
2254 {
2255 /* NULL value detected, hence no input to process */
2256 item->values[j] = (Datum) 0;
2257 item->isnull[j] = true;
2258 }
2259 else
2260 {
2263
2264 if (!InputFunctionCallSafe(&finfo, s, ioparam, atttypmods[j],
2265 (Node *) &escontext, &item->values[j]))
2266 {
2267 ereport(elevel,
2269 errmsg("could not parse MCV element \"%s\": incorrect value", s)));
2270 pfree(s);
2271 goto error;
2272 }
2273
2274 pfree(s);
2275 }
2276
2277 index += numattrs;
2278 }
2279 }
2280
2281 /*
2282 * The function statext_mcv_serialize() requires an array of pointers to
2283 * VacAttrStats records, but only a few fields within those records have
2284 * to be filled out.
2285 */
2287
2288 for (int i = 0; i < numattrs; i++)
2289 {
2290 Oid typid = atttypids[i];
2292
2294
2296 elog(ERROR, "cache lookup failed for type %u", typid);
2297
2299
2300 vastats[i]->attrtype = (Form_pg_type) GETSTRUCT(typtuple);
2301 vastats[i]->attrtypid = typid;
2302 vastats[i]->attrcollid = atttypcolls[i];
2303 }
2304
2306
2307 for (int i = 0; i < numattrs; i++)
2308 {
2309 pfree(vastats[i]);
2310 }
2311 pfree((void *) vastats);
2312
2315
2316 if (bytes == NULL)
2317 {
2318 ereport(elevel,
2320 errmsg("could not import MCV list")));
2321 goto error;
2322 }
2323
2324 return PointerGetDatum(bytes);
2325
2326error:
2328 return (Datum) 0;
2329}
#define TextDatumGetCString(d)
Definition builtins.h:99
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition fmgr.c:129
bool InputFunctionCallSafe(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod, Node *escontext, Datum *result)
Definition fmgr.c:1586
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition lsyscache.c:3190
void statext_mcv_free(MCVList *mcvlist)
Definition mcv.c:2174
bytea * statext_mcv_serialize(MCVList *mcvlist, VacAttrStats **stats)
Definition mcv.c:619
END_CATALOG_STRUCT typedef FormData_pg_type * Form_pg_type
Definition pg_type.h:265
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
static void error(void)
#define SearchSysCacheCopy1(cacheId, key1)
Definition syscache.h:91

References MCVItem::base_frequency, elog, ereport, errcode(), errmsg, ERROR, error(), fb(), fmgr_info(), Form_pg_type, MCVItem::frequency, GETSTRUCT(), getTypeInputInfo(), HeapTupleIsValid, i, InputFunctionCallSafe(), MCVItem::isnull, items, j, nitems, ObjectIdGetDatum(), palloc0(), palloc0_array, palloc0_object, pfree(), PointerGetDatum, SearchSysCacheCopy1, statext_mcv_free(), statext_mcv_serialize(), STATS_MCV_MAGIC, STATS_MCV_TYPE_BASIC, TextDatumGetCString, and MCVItem::values.

Referenced by import_mcv().

◆ statext_mcv_serialize()

bytea * statext_mcv_serialize ( MCVList mcvlist,
VacAttrStats **  stats 
)
extern

Definition at line 619 of file mcv.c.

620{
621 int dim;
622 int ndims = mcvlist->ndimensions;
623
624 SortSupport ssup;
625 DimensionInfo *info;
626
628
629 /* serialized items (indexes into arrays, etc.) */
630 bytea *raw;
631 char *ptr;
632 char *endptr PG_USED_FOR_ASSERTS_ONLY;
633
634 /* values per dimension (and number of non-NULL values) */
635 Datum **values = palloc0_array(Datum *, ndims);
636 int *counts = palloc0_array(int, ndims);
637
638 /*
639 * We'll include some rudimentary information about the attribute types
640 * (length, by-val flag), so that we don't have to look them up while
641 * deserializing the MCV list (we already have the type OID in the
642 * header). This is safe because when changing the type of the attribute
643 * the statistics gets dropped automatically. We need to store the info
644 * about the arrays of deduplicated values anyway.
645 */
646 info = palloc0_array(DimensionInfo, ndims);
647
648 /* sort support data for all attributes included in the MCV list */
649 ssup = palloc0_array(SortSupportData, ndims);
650
651 /* collect and deduplicate values for each dimension (attribute) */
652 for (dim = 0; dim < ndims; dim++)
653 {
654 int ndistinct;
655 TypeCacheEntry *typentry;
656
657 /*
658 * Lookup the LT operator (can't get it from stats extra_data, as we
659 * don't know how to interpret that - scalar vs. array etc.).
660 */
661 typentry = lookup_type_cache(stats[dim]->attrtypid, TYPECACHE_LT_OPR);
662
663 /* copy important info about the data type (length, by-value) */
664 info[dim].typlen = stats[dim]->attrtype->typlen;
665 info[dim].typbyval = stats[dim]->attrtype->typbyval;
666
667 /* allocate space for values in the attribute and collect them */
668 values[dim] = palloc0_array(Datum, mcvlist->nitems);
669
670 for (uint32 i = 0; i < mcvlist->nitems; i++)
671 {
672 /* skip NULL values - we don't need to deduplicate those */
673 if (mcvlist->items[i].isnull[dim])
674 continue;
675
676 /* append the value at the end */
677 values[dim][counts[dim]] = mcvlist->items[i].values[dim];
678 counts[dim] += 1;
679 }
680
681 /* if there are just NULL values in this dimension, we're done */
682 if (counts[dim] == 0)
683 continue;
684
685 /* sort and deduplicate the data */
686 ssup[dim].ssup_cxt = CurrentMemoryContext;
687 ssup[dim].ssup_collation = stats[dim]->attrcollid;
688 ssup[dim].ssup_nulls_first = false;
689
690 PrepareSortSupportFromOrderingOp(typentry->lt_opr, &ssup[dim]);
691
692 qsort_interruptible(values[dim], counts[dim], sizeof(Datum),
693 compare_scalars_simple, &ssup[dim]);
694
695 /*
696 * Walk through the array and eliminate duplicate values, but keep the
697 * ordering (so that we can do a binary search later). We know there's
698 * at least one item as (counts[dim] != 0), so we can skip the first
699 * element.
700 */
701 ndistinct = 1; /* number of distinct values */
702 for (int i = 1; i < counts[dim]; i++)
703 {
704 /* expect sorted array */
705 Assert(compare_datums_simple(values[dim][i - 1], values[dim][i], &ssup[dim]) <= 0);
706
707 /* if the value is the same as the previous one, we can skip it */
708 if (!compare_datums_simple(values[dim][i - 1], values[dim][i], &ssup[dim]))
709 continue;
710
711 values[dim][ndistinct] = values[dim][i];
712 ndistinct += 1;
713 }
714
715 /* we must not exceed PG_UINT16_MAX, as we use uint16 indexes */
716 Assert(ndistinct <= PG_UINT16_MAX);
717
718 /*
719 * Store additional info about the attribute - number of deduplicated
720 * values, and also size of the serialized data. For fixed-length data
721 * types this is trivial to compute, for varwidth types we need to
722 * actually walk the array and sum the sizes.
723 */
724 info[dim].nvalues = ndistinct;
725
726 if (info[dim].typbyval) /* by-value data types */
727 {
728 info[dim].nbytes = info[dim].nvalues * info[dim].typlen;
729
730 /*
731 * We copy the data into the MCV item during deserialization, so
732 * we don't need to allocate any extra space.
733 */
734 info[dim].nbytes_aligned = 0;
735 }
736 else if (info[dim].typlen > 0) /* fixed-length by-ref */
737 {
738 /*
739 * We don't care about alignment in the serialized data, so we
740 * pack the data as much as possible. But we also track how much
741 * data will be needed after deserialization, and in that case we
742 * need to account for alignment of each item.
743 *
744 * Note: As the items are fixed-length, we could easily compute
745 * this during deserialization, but we do it here anyway.
746 */
747 info[dim].nbytes = info[dim].nvalues * info[dim].typlen;
748 info[dim].nbytes_aligned = info[dim].nvalues * MAXALIGN(info[dim].typlen);
749 }
750 else if (info[dim].typlen == -1) /* varlena */
751 {
752 info[dim].nbytes = 0;
753 info[dim].nbytes_aligned = 0;
754 for (int i = 0; i < info[dim].nvalues; i++)
755 {
756 Size len;
757
758 /*
759 * For varlena values, we detoast the values and store the
760 * length and data separately. We don't bother with alignment
761 * here, which means that during deserialization we need to
762 * copy the fields and only access the copies.
763 */
765
766 /* serialized length (uint32 length + data) */
768 info[dim].nbytes += sizeof(uint32); /* length */
769 info[dim].nbytes += len; /* value (no header) */
770
771 /*
772 * During deserialization we'll build regular varlena values
773 * with full headers, and we need to align them properly.
774 */
775 info[dim].nbytes_aligned += MAXALIGN(VARHDRSZ + len);
776 }
777 }
778 else if (info[dim].typlen == -2) /* cstring */
779 {
780 info[dim].nbytes = 0;
781 info[dim].nbytes_aligned = 0;
782 for (int i = 0; i < info[dim].nvalues; i++)
783 {
784 Size len;
785
786 /*
787 * cstring is handled similar to varlena - first we store the
788 * length as uint32 and then the data. We don't care about
789 * alignment, which means that during deserialization we need
790 * to copy the fields and only access the copies.
791 */
792
793 /* c-strings include terminator, so +1 byte */
794 len = strlen(DatumGetCString(values[dim][i])) + 1;
795 info[dim].nbytes += sizeof(uint32); /* length */
796 info[dim].nbytes += len; /* value */
797
798 /* space needed for properly aligned deserialized copies */
799 info[dim].nbytes_aligned += MAXALIGN(len);
800 }
801 }
802
803 /* we know (count>0) so there must be some data */
804 Assert(info[dim].nbytes > 0);
805 }
806
807 /*
808 * Now we can finally compute how much space we'll actually need for the
809 * whole serialized MCV list (varlena header, MCV header, dimension info
810 * for each attribute, deduplicated values and items).
811 */
812 total_length = (3 * sizeof(uint32)) /* magic + type + nitems */
813 + sizeof(AttrNumber) /* ndimensions */
814 + (ndims * sizeof(Oid)); /* attribute types */
815
816 /* dimension info */
817 total_length += ndims * sizeof(DimensionInfo);
818
819 /* add space for the arrays of deduplicated values */
820 for (int i = 0; i < ndims; i++)
821 total_length += info[i].nbytes;
822
823 /*
824 * And finally account for the items (those are fixed-length, thanks to
825 * replacing values with uint16 indexes into the deduplicated arrays).
826 */
827 total_length += mcvlist->nitems * ITEM_SIZE(dim);
828
829 /*
830 * Allocate space for the whole serialized MCV list (we'll skip bytes, so
831 * we set them to zero to make the result more compressible).
832 */
835
836 ptr = VARDATA(raw);
837 endptr = ptr + total_length;
838
839 /* copy the MCV list header fields, one by one */
840 memcpy(ptr, &mcvlist->magic, sizeof(uint32));
841 ptr += sizeof(uint32);
842
843 memcpy(ptr, &mcvlist->type, sizeof(uint32));
844 ptr += sizeof(uint32);
845
846 memcpy(ptr, &mcvlist->nitems, sizeof(uint32));
847 ptr += sizeof(uint32);
848
849 memcpy(ptr, &mcvlist->ndimensions, sizeof(AttrNumber));
850 ptr += sizeof(AttrNumber);
851
852 memcpy(ptr, mcvlist->types, sizeof(Oid) * ndims);
853 ptr += (sizeof(Oid) * ndims);
854
855 /* store information about the attributes (data amounts, ...) */
856 memcpy(ptr, info, sizeof(DimensionInfo) * ndims);
857 ptr += sizeof(DimensionInfo) * ndims;
858
859 /* Copy the deduplicated values for all attributes to the output. */
860 for (dim = 0; dim < ndims; dim++)
861 {
862 /* remember the starting point for Asserts later */
864
865 for (int i = 0; i < info[dim].nvalues; i++)
866 {
867 Datum value = values[dim][i];
868
869 if (info[dim].typbyval) /* passed by value */
870 {
871 Datum tmp;
872
873 /*
874 * For byval types, we need to copy just the significant bytes
875 * - we can't use memcpy directly, as that assumes
876 * little-endian behavior. store_att_byval does almost what
877 * we need, but it requires a properly aligned buffer - the
878 * output buffer does not guarantee that. So we simply use a
879 * local Datum variable (which guarantees proper alignment),
880 * and then copy the value from it.
881 */
882 store_att_byval(&tmp, value, info[dim].typlen);
883
884 memcpy(ptr, &tmp, info[dim].typlen);
885 ptr += info[dim].typlen;
886 }
887 else if (info[dim].typlen > 0) /* passed by reference */
888 {
889 /* no special alignment needed, treated as char array */
890 memcpy(ptr, DatumGetPointer(value), info[dim].typlen);
891 ptr += info[dim].typlen;
892 }
893 else if (info[dim].typlen == -1) /* varlena */
894 {
896
897 /* copy the length */
898 memcpy(ptr, &len, sizeof(uint32));
899 ptr += sizeof(uint32);
900
901 /* data from the varlena value (without the header) */
903 ptr += len;
904 }
905 else if (info[dim].typlen == -2) /* cstring */
906 {
908
909 /* copy the length */
910 memcpy(ptr, &len, sizeof(uint32));
911 ptr += sizeof(uint32);
912
913 /* value */
915 ptr += len;
916 }
917
918 /* no underflows or overflows */
919 Assert((ptr > start) && ((ptr - start) <= info[dim].nbytes));
920 }
921
922 /* we should get exactly nbytes of data for this dimension */
923 Assert((ptr - start) == info[dim].nbytes);
924 }
925
926 /* Serialize the items, with uint16 indexes instead of the values. */
927 for (uint32 i = 0; i < mcvlist->nitems; i++)
928 {
929 MCVItem *mcvitem = &mcvlist->items[i];
930
931 /* don't write beyond the allocated space */
932 Assert(ptr <= (endptr - ITEM_SIZE(dim)));
933
934 /* copy NULL and frequency flags into the serialized MCV */
935 memcpy(ptr, mcvitem->isnull, sizeof(bool) * ndims);
936 ptr += sizeof(bool) * ndims;
937
938 memcpy(ptr, &mcvitem->frequency, sizeof(double));
939 ptr += sizeof(double);
940
941 memcpy(ptr, &mcvitem->base_frequency, sizeof(double));
942 ptr += sizeof(double);
943
944 /* store the indexes last */
945 for (dim = 0; dim < ndims; dim++)
946 {
947 uint16 index = 0;
948 Datum *value;
949
950 /* do the lookup only for non-NULL values */
951 if (!mcvitem->isnull[dim])
952 {
953 value = (Datum *) bsearch_arg(&mcvitem->values[dim], values[dim],
954 info[dim].nvalues, sizeof(Datum),
955 compare_scalars_simple, &ssup[dim]);
956
957 Assert(value != NULL); /* serialization or deduplication
958 * error */
959
960 /* compute index within the deduplicated array */
961 index = (uint16) (value - values[dim]);
962
963 /* check the index is within expected bounds */
964 Assert(index < info[dim].nvalues);
965 }
966
967 /* copy the index into the serialized MCV */
968 memcpy(ptr, &index, sizeof(uint16));
969 ptr += sizeof(uint16);
970 }
971
972 /* make sure we don't overflow the allocated value */
973 Assert(ptr <= endptr);
974 }
975
976 /* at this point we expect to match the total_length exactly */
977 Assert(ptr == endptr);
978
979 pfree(values);
980 pfree(counts);
981
982 return raw;
983}
#define PG_UINT16_MAX
Definition c.h:730
int compare_scalars_simple(const void *a, const void *b, void *arg)
#define ITEM_SIZE(ndims)
Definition mcv.c:51
static char * DatumGetCString(Datum X)
Definition postgres.h:365
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
Form_pg_type attrtype
Definition vacuum.h:127
Oid attrcollid
Definition vacuum.h:128
static void store_att_byval(void *T, Datum newdatum, int attlen)
Definition tupmacs.h:457
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:389
#define TYPECACHE_LT_OPR
Definition typcache.h:139

References Assert, VacAttrStats::attrcollid, VacAttrStats::attrtype, bsearch_arg(), compare_datums_simple(), compare_scalars_simple(), CurrentMemoryContext, DatumGetCString(), DatumGetPointer(), fb(), i, ITEM_SIZE, len, lookup_type_cache(), TypeCacheEntry::lt_opr, MAXALIGN, memcpy(), DimensionInfo::nbytes, DimensionInfo::nbytes_aligned, DimensionInfo::nvalues, palloc0(), palloc0_array, pfree(), PG_DETOAST_DATUM, PG_UINT16_MAX, PG_USED_FOR_ASSERTS_ONLY, PointerGetDatum, PrepareSortSupportFromOrderingOp(), qsort_interruptible(), SET_VARSIZE(), SortSupportData::ssup_collation, SortSupportData::ssup_cxt, SortSupportData::ssup_nulls_first, start, store_att_byval(), DimensionInfo::typbyval, TYPECACHE_LT_OPR, DimensionInfo::typlen, value, values, VARDATA(), VARDATA_ANY(), VARHDRSZ, and VARSIZE_ANY_EXHDR().

Referenced by statext_mcv_import(), and statext_store().

◆ statext_ndistinct_build()

MVNDistinct * statext_ndistinct_build ( double  totalrows,
StatsBuildData data 
)
extern

Definition at line 85 of file mvdistinct.c.

86{
88 int k;
90 int numattrs = data->nattnums;
92
94 numcombs * sizeof(MVNDistinctItem));
97 result->nitems = numcombs;
98
99 itemcnt = 0;
100 for (k = 2; k <= numattrs; k++)
101 {
102 int *combination;
104
105 /* generate combinations of K out of N elements */
107
109 {
110 MVNDistinctItem *item = &result->items[itemcnt];
111 int j;
112
114 item->nattributes = k;
115
116 /* translate the indexes to attnums */
117 for (j = 0; j < k; j++)
118 {
119 item->attributes[j] = data->attnums[combination[j]];
120
122 }
123
124 item->ndistinct =
126
127 itemcnt++;
129 }
130
132 }
133
134 /* must consume exactly the whole output array */
135 Assert(itemcnt == result->nitems);
136
137 return result;
138}
uint32 result
static double ndistinct_for_combination(double totalrows, StatsBuildData *data, int k, int *combination)
Definition mvdistinct.c:414
static int num_combinations(int n)
Definition mvdistinct.c:564
static void generator_free(CombinationGenerator *state)
Definition mvdistinct.c:631
static CombinationGenerator * generator_init(int n, int k)
Definition mvdistinct.c:578
static int * generator_next(CombinationGenerator *state)
Definition mvdistinct.c:616
#define STATS_NDISTINCT_MAGIC
Definition statistics.h:22
#define STATS_NDISTINCT_TYPE_BASIC
Definition statistics.h:23
AttrNumber * attributes
Definition statistics.h:30

References Assert, AttributeNumberIsValid, MVNDistinctItem::attributes, data, fb(), generator_free(), generator_init(), generator_next(), items, j, MVNDistinctItem::nattributes, MVNDistinctItem::ndistinct, ndistinct_for_combination(), nitems, num_combinations(), palloc(), palloc_array, result, STATS_NDISTINCT_MAGIC, and STATS_NDISTINCT_TYPE_BASIC.

Referenced by BuildRelationExtStatistics().

◆ statext_ndistinct_deserialize()

MVNDistinct * statext_ndistinct_deserialize ( bytea data)
extern

Definition at line 246 of file mvdistinct.c.

247{
250 MVNDistinct *ndistinct;
251 char *tmp;
252
253 if (data == NULL)
254 return NULL;
255
256 /* we expect at least the basic fields of MVNDistinct struct */
258 elog(ERROR, "invalid MVNDistinct size %zu (expected at least %zu)",
260
261 /* initialize pointer to the data part (skip the varlena header) */
262 tmp = VARDATA_ANY(data);
263
264 /* read the header fields and perform basic sanity checks */
265 memcpy(&ndist.magic, tmp, sizeof(uint32));
266 tmp += sizeof(uint32);
267 memcpy(&ndist.type, tmp, sizeof(uint32));
268 tmp += sizeof(uint32);
269 memcpy(&ndist.nitems, tmp, sizeof(uint32));
270 tmp += sizeof(uint32);
271
272 if (ndist.magic != STATS_NDISTINCT_MAGIC)
273 elog(ERROR, "invalid ndistinct magic %08x (expected %08x)",
276 elog(ERROR, "invalid ndistinct type %d (expected %d)",
278 if (ndist.nitems == 0)
279 elog(ERROR, "invalid zero-length item array in MVNDistinct");
280
281 /* what minimum bytea size do we expect for those parameters */
284 elog(ERROR, "invalid MVNDistinct size %zu (expected at least %zu)",
286
287 /*
288 * Allocate space for the ndistinct items (no space for each item's
289 * attnos: those live in bitmapsets allocated separately)
290 */
291 ndistinct = palloc0(MAXALIGN(offsetof(MVNDistinct, items)) +
292 (ndist.nitems * sizeof(MVNDistinctItem)));
293 ndistinct->magic = ndist.magic;
294 ndistinct->type = ndist.type;
295 ndistinct->nitems = ndist.nitems;
296
297 for (uint32 i = 0; i < ndistinct->nitems; i++)
298 {
299 MVNDistinctItem *item = &ndistinct->items[i];
300
301 /* ndistinct value */
302 memcpy(&item->ndistinct, tmp, sizeof(double));
303 tmp += sizeof(double);
304
305 /* number of attributes */
306 memcpy(&item->nattributes, tmp, sizeof(int));
307 tmp += sizeof(int);
308 Assert((item->nattributes >= 2) && (item->nattributes <= STATS_MAX_DIMENSIONS));
309
310 item->attributes
311 = (AttrNumber *) palloc(item->nattributes * sizeof(AttrNumber));
312
313 memcpy(item->attributes, tmp, sizeof(AttrNumber) * item->nattributes);
314 tmp += sizeof(AttrNumber) * item->nattributes;
315
316 /* still within the bytea */
317 Assert(tmp <= ((char *) data + VARSIZE_ANY(data)));
318 }
319
320 /* we should have consumed the whole bytea exactly */
321 Assert(tmp == ((char *) data + VARSIZE_ANY(data)));
322
323 return ndistinct;
324}
#define SizeOfHeader
Definition mvdistinct.c:42
#define MinSizeOfItems(nitems)
Definition mvdistinct.c:52
uint32 nitems
Definition statistics.h:38
uint32 type
Definition statistics.h:37
uint32 magic
Definition statistics.h:36
MVNDistinctItem items[FLEXIBLE_ARRAY_MEMBER]
Definition statistics.h:39

References Assert, MVNDistinctItem::attributes, data, elog, ERROR, fb(), i, MVNDistinct::items, items, MVNDistinct::magic, MAXALIGN, memcpy(), MinSizeOfItems, MVNDistinctItem::nattributes, MVNDistinctItem::ndistinct, MVNDistinct::nitems, palloc(), palloc0(), SizeOfHeader, STATS_MAX_DIMENSIONS, STATS_NDISTINCT_MAGIC, STATS_NDISTINCT_TYPE_BASIC, MVNDistinct::type, VARDATA_ANY(), VARSIZE_ANY(), and VARSIZE_ANY_EXHDR().

Referenced by extended_statistics_update(), pg_ndistinct_out(), and statext_ndistinct_load().

◆ statext_ndistinct_free()

void statext_ndistinct_free ( MVNDistinct ndistinct)
extern

Definition at line 330 of file mvdistinct.c.

331{
332 for (uint32 i = 0; i < ndistinct->nitems; i++)
333 pfree(ndistinct->items[i].attributes);
334 pfree(ndistinct);
335}

References MVNDistinctItem::attributes, i, MVNDistinct::items, MVNDistinct::nitems, and pfree().

Referenced by extended_statistics_update().

◆ statext_ndistinct_serialize()

bytea * statext_ndistinct_serialize ( MVNDistinct ndistinct)
extern

Definition at line 176 of file mvdistinct.c.

177{
178 bytea *output;
179 char *tmp;
180 Size len;
181
182 Assert(ndistinct->magic == STATS_NDISTINCT_MAGIC);
184
185 /*
186 * Base size is size of scalar fields in the struct, plus one base struct
187 * for each item, including number of items for each.
188 */
190
191 /* and also include space for the actual attribute numbers */
192 for (uint32 i = 0; i < ndistinct->nitems; i++)
193 {
194 int nmembers;
195
196 nmembers = ndistinct->items[i].nattributes;
197 Assert(nmembers >= 2);
198
199 len += SizeOfItem(nmembers);
200 }
201
202 output = (bytea *) palloc(len);
204
205 tmp = VARDATA(output);
206
207 /* Store the base struct values (magic, type, nitems) */
208 memcpy(tmp, &ndistinct->magic, sizeof(uint32));
209 tmp += sizeof(uint32);
210 memcpy(tmp, &ndistinct->type, sizeof(uint32));
211 tmp += sizeof(uint32);
212 memcpy(tmp, &ndistinct->nitems, sizeof(uint32));
213 tmp += sizeof(uint32);
214
215 /*
216 * store number of attributes and attribute numbers for each entry
217 */
218 for (uint32 i = 0; i < ndistinct->nitems; i++)
219 {
220 MVNDistinctItem item = ndistinct->items[i];
221 int nmembers = item.nattributes;
222
223 memcpy(tmp, &item.ndistinct, sizeof(double));
224 tmp += sizeof(double);
225 memcpy(tmp, &nmembers, sizeof(int));
226 tmp += sizeof(int);
227
228 memcpy(tmp, item.attributes, sizeof(AttrNumber) * nmembers);
229 tmp += nmembers * sizeof(AttrNumber);
230
231 /* protect against overflows */
232 Assert(tmp <= ((char *) output + len));
233 }
234
235 /* check we used exactly the expected space */
236 Assert(tmp == ((char *) output + len));
237
238 return output;
239}
#define SizeOfItem(natts)
Definition mvdistinct.c:45

References Assert, MVNDistinctItem::attributes, fb(), i, MVNDistinct::items, len, MVNDistinct::magic, memcpy(), MVNDistinctItem::nattributes, MVNDistinctItem::ndistinct, MVNDistinct::nitems, output, palloc(), SET_VARSIZE(), SizeOfHeader, SizeOfItem, STATS_NDISTINCT_MAGIC, STATS_NDISTINCT_TYPE_BASIC, MVNDistinct::type, VARDATA(), and VARHDRSZ.

Referenced by build_mvndistinct(), and statext_store().

◆ statext_ndistinct_validate()

bool statext_ndistinct_validate ( const MVNDistinct ndistinct,
const int2vector stxkeys,
int  numexprs,
int  elevel 
)
extern

Definition at line 350 of file mvdistinct.c.

353{
355
356 /* Scan through each MVNDistinct entry */
357 for (uint32 i = 0; i < ndistinct->nitems; i++)
358 {
359 MVNDistinctItem item = ndistinct->items[i];
360
361 /*
362 * Cross-check each attribute in a MVNDistinct entry with the extended
363 * stats object definition.
364 */
365 for (int j = 0; j < item.nattributes; j++)
366 {
368 bool ok = false;
369
370 if (attnum > 0)
371 {
372 /* attribute number in stxkeys */
373 for (int k = 0; k < stxkeys->dim1; k++)
374 {
375 if (attnum == stxkeys->values[k])
376 {
377 ok = true;
378 break;
379 }
380 }
381 }
382 else if ((attnum < 0) && (attnum >= attnum_expr_lowbound))
383 {
384 /* attribute number for an expression */
385 ok = true;
386 }
387
388 if (!ok)
389 {
390 ereport(elevel,
392 errmsg("could not validate \"%s\" object: invalid attribute number %d found",
393 "pg_ndistinct", attnum)));
394 return false;
395 }
396 }
397 }
398
399 return true;
400}

References attnum, MVNDistinctItem::attributes, ereport, errcode(), errmsg, fb(), i, MVNDistinct::items, j, MVNDistinctItem::nattributes, and MVNDistinct::nitems.

Referenced by extended_statistics_update().