/* store info about data type OIDs */ for (i = 0; i < numattrs; i++)
mcvlist->types[i] = data->stats[i]->attrtypid;
/* Copy the first chunk of groups into the result. */ for (i = 0; i < nitems; i++)
{ /* just point to the proper place in the list */
MCVItem *item = &mcvlist->items[i];
/* *build_mss *BuildaMultiSortSupportforthegivenStatsBuildData.
*/ static MultiSortSupport
build_mss(StatsBuildData *data)
{ int i; int numattrs = data->nattnums;
/* Sort by multiple columns (using array of SortSupport) */
MultiSortSupport mss = multi_sort_init(numattrs);
/* prepare the sort functions for all the attributes */ for (i = 0; i < numattrs; i++)
{
VacAttrStats *colstat = data->stats[i];
TypeCacheEntry *type;
type = lookup_type_cache(colstat->attrtypid, TYPECACHE_LT_OPR); if (type->lt_opr == InvalidOid) /* shouldn't happen */
elog(ERROR, "cache lookup failed for ordering operator for type %u",
colstat->attrtypid);
multi_sort_add_dimension(mss, i, type->lt_opr, colstat->attrcollid);
}
return mss;
}
/* *count_distinct_groups *CountdistinctcombinationsofSortItemsinthearray. * *ThearrayisassumedtobesortedaccordingtotheMultiSortSupport.
*/ staticint
count_distinct_groups(int numrows, SortItem *items, MultiSortSupport mss)
{ int i; int ndistinct;
ndistinct = 1; for (i = 1; i < numrows; i++)
{ /* make sure the array really is sorted */
Assert(multi_sort_compare(&items[i], &items[i - 1], mss) >= 0);
for (i = 1; i < numrows; i++)
{ /* Assume sorted in ascending order. */
Assert(multi_sort_compare(&items[i], &items[i - 1], mss) >= 0);
/* New distinct group detected. */ if (multi_sort_compare(&items[i], &items[i - 1], mss) != 0)
{
groups[++j] = items[i];
groups[j].count = 0;
}
groups[j].count++;
}
/* ensure we filled the expected number of distinct groups */
Assert(j + 1 == ngroups);
/* Sort the distinct groups by frequency (in descending order). */
qsort_interruptible(groups, ngroups, sizeof(SortItem),
compare_sort_item_count, NULL);
/* *build_column_frequencies *Computefrequenciesofvaluesineachcolumn. * *ThisreturnsanarrayofSortItemsforeachattributetheMCVisbuilt *on,withafrequency(numberofoccurrences)foreachvalue.Thisis *thenusedtocompute"base"frequencyofMCVitems. * *Allthememoryisallocatedinasinglechunk,sothatasinglepfree *isenoughtoreleaseit.Wedonotallocatespaceforvalues/isnull *arraysintheSortItems,becausewecansimplypointintotheinput *groupsdirectly.
*/ static SortItem **
build_column_frequencies(SortItem *groups, int ngroups,
MultiSortSupport mss, int *ncounts)
{ int i,
dim;
SortItem **result; char *ptr;
Assert(groups);
Assert(ncounts);
/* allocate arrays for all columns as a single chunk */
ptr = palloc(MAXALIGN(sizeof(SortItem *) * mss->ndims) +
mss->ndims * MAXALIGN(sizeof(SortItem) * ngroups));
/* initial array of pointers */
result = (SortItem **) ptr;
ptr += MAXALIGN(sizeof(SortItem *) * mss->ndims);
for (dim = 0; dim < mss->ndims; dim++)
{
SortSupport ssup = &mss->ssup[dim];
/* array of values for a single column */
result[dim] = (SortItem *) ptr;
ptr += MAXALIGN(sizeof(SortItem) * ngroups);
/* extract data for the dimension */ for (i = 0; i < ngroups; i++)
{ /* point into the input groups */
result[dim][i].values = &groups[i].values[dim];
result[dim][i].isnull = &groups[i].isnull[dim];
result[dim][i].count = groups[i].count;
}
/* copy important info about the data type (length, by-value) */
info[dim].typlen = stats[dim]->attrtype->typlen;
info[dim].typbyval = stats[dim]->attrtype->typbyval;
/* allocate space for values in the attribute and collect them */
values[dim] = (Datum *) palloc0(sizeof(Datum) * mcvlist->nitems);
for (i = 0; i < mcvlist->nitems; i++)
{ /* skip NULL values - we don't need to deduplicate those */ if (mcvlist->items[i].isnull[dim]) continue;
/* append the value at the end */
values[dim][counts[dim]] = mcvlist->items[i].values[dim];
counts[dim] += 1;
}
/* if there are just NULL values in this dimension, we're done */ if (counts[dim] == 0) continue;
/* sort and deduplicate the data */
ssup[dim].ssup_cxt = CurrentMemoryContext;
ssup[dim].ssup_collation = stats[dim]->attrcollid;
ssup[dim].ssup_nulls_first = false;
/* *Walkthroughthearrayandeliminateduplicatevalues,butkeepthe *ordering(sothatwecandoabinarysearchlater).Weknowthere's *atleastoneitemas(counts[dim]!=0),sowecanskipthefirst *element.
*/
ndistinct = 1; /* number of distinct values */ for (i = 1; i < counts[dim]; i++)
{ /* expect sorted array */
Assert(compare_datums_simple(values[dim][i - 1], values[dim][i], &ssup[dim]) <= 0);
/* if the value is the same as the previous one, we can skip it */ if (!compare_datums_simple(values[dim][i - 1], values[dim][i], &ssup[dim])) continue;
/* store information about the attributes (data amounts, ...) */
memcpy(ptr, info, sizeof(DimensionInfo) * ndims);
ptr += sizeof(DimensionInfo) * ndims;
/* Copy the deduplicated values for all attributes to the output. */ for (dim = 0; dim < ndims; dim++)
{ /* remember the starting point for Asserts later */ char *start PG_USED_FOR_ASSERTS_ONLY = ptr;
for (i = 0; i < info[dim].nvalues; i++)
{
Datum value = values[dim][i];
if (info[dim].typbyval) /* passed by value */
{
Datum tmp;
/* store the indexes last */ for (dim = 0; dim < ndims; dim++)
{
uint16 index = 0;
Datum *value;
/* do the lookup only for non-NULL values */ if (!mcvitem->isnull[dim])
{
value = (Datum *) bsearch_arg(&mcvitem->values[dim], values[dim],
info[dim].nvalues, sizeof(Datum),
compare_scalars_simple, &ssup[dim]);
Assert(value != NULL); /* serialization or deduplication
* error */
/* compute index within the deduplicated array */
index = (uint16) (value - values[dim]);
/* check the index is within expected bounds */
Assert(index < info[dim].nvalues);
}
/* copy the index into the serialized MCV */
memcpy(ptr, &index, sizeof(uint16));
ptr += sizeof(uint16);
}
/* make sure we don't overflow the allocated value */
Assert(ptr <= endptr);
}
/* at this point we expect to match the total_length exactly */
Assert(ptr == endptr);
/* no under/overflow of input array */
Assert(ptr <= (start + info[dim].nbytes));
}
} else
{ /* for by-ref types we need to also make a copy of the data */
/* passed by reference, but fixed length (name, tid, ...) */ if (info[dim].typlen > 0)
{ for (i = 0; i < info[dim].nvalues; i++)
{
memcpy(dataptr, ptr, info[dim].typlen);
ptr += info[dim].typlen;
/* just point into the array */
map[dim][i] = PointerGetDatum(dataptr);
dataptr += MAXALIGN(info[dim].typlen);
}
} elseif (info[dim].typlen == -1)
{ /* varlena */ for (i = 0; i < info[dim].nvalues; i++)
{
uint32 len;
/* the length is data-only */
SET_VARSIZE(dataptr, len + VARHDRSZ);
memcpy(VARDATA(dataptr), ptr, len);
ptr += len;
/* just point into the array */
map[dim][i] = PointerGetDatum(dataptr);
/* skip to place of the next deserialized value */
dataptr += MAXALIGN(len + VARHDRSZ);
}
} elseif (info[dim].typlen == -2)
{ /* cstring */ for (i = 0; i < info[dim].nvalues; i++)
{
uint32 len;
/* total number of tuples to be returned */
funcctx->max_calls = 0; if (funcctx->user_fctx != NULL)
funcctx->max_calls = mcvlist->nitems;
/* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("function returning record called in context " "that cannot accept type record")));
tupdesc = BlessTupleDesc(tupdesc);
/* stuff done on every call of the function */
funcctx = SRF_PERCALL_SETUP();
if (funcctx->call_cntr < funcctx->max_calls) /* do when there is more
* left to send */
{
Datum values[5]; bool nulls[5];
HeapTuple tuple;
Datum result;
ArrayBuildState *astate_values = NULL;
ArrayBuildState *astate_nulls = NULL;
/* no NULLs in the tuple */
memset(nulls, 0, sizeof(nulls));
/* build a tuple */
tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
/* make the tuple into a datum */
result = HeapTupleGetDatum(tuple);
SRF_RETURN_NEXT(funcctx, result);
} else/* do when there is no more left */
{
SRF_RETURN_DONE(funcctx);
}
}
/* *pg_mcv_list_in-inputroutinefortypepg_mcv_list. * *pg_mcv_listisrealenoughtobeatablecolumn,butithasnooperations *ofitsown,anddisallowsinputtoo
*/
Datum
pg_mcv_list_in(PG_FUNCTION_ARGS)
{ /* *pg_mcv_liststoresthedatainbinaryformandparsingtextinputis *notneeded,sodisallowthis.
*/
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot accept a value of type %s", "pg_mcv_list")));
/* *pg_mcv_list_recv-binaryinputroutinefortypepg_mcv_list.
*/
Datum
pg_mcv_list_recv(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot accept a value of type %s", "pg_mcv_list")));
/* valid only after examine_opclause_args returns true */
Node *clause_expr; Const *cst; bool expronleft; int idx;
Oid collid;
fmgr_info(get_opcode(expr->opno), &opproc);
/* extract the var/expr and const from the expression */ if (!examine_opclause_args(expr->args, &clause_expr, &cst, &expronleft))
elog(ERROR, "incompatible clause");
/* match the attribute/expression to a dimension of the statistic */
idx = mcv_match_expression(clause_expr, keys, exprs, &collid);
/* *WalkthroughtheMCVitemsandevaluatethecurrentclause.We *canskipitemsthatwerealreadyruledout,andterminateif *therearenoremainingMCVitemsthatmightpossiblymatch.
*/ for (int i = 0; i < mcvlist->nitems; i++)
{ bool match = true;
MCVItem *item = &mcvlist->items[i];
/* *SkipMCVitemsthatcan'tchangeresultinthebitmap.Once *thevaluegetsfalseforAND-lists,ortrueforOR-lists, *wedon'tneedtolookatmoreclauses.
*/ if (RESULT_IS_FINAL(matches[i], is_or)) continue;
/* *Firstcheckwhethertheconstantisbelowthelower *boundary(inthatcasewecanskipthebucket,because *there'snooverlap). * *Wedon'tstorecollationsusedtobuildthestatistics,but *wecanusethecollationfortheattributeitself,as *storedinvarcollid.Wedoresetthestatisticsaftera *typechange(includingcollationchange),sothisisOK. *Forexpressions,weusethecollationextractedfromthe *expressionitself.
*/ if (expronleft)
match = DatumGetBool(FunctionCall2Coll(&opproc,
collid,
item->values[idx],
cst->constvalue)); else
match = DatumGetBool(FunctionCall2Coll(&opproc,
collid,
cst->constvalue,
item->values[idx]));
/* update the match bitmap with the result */
matches[i] = RESULT_MERGE(matches[i], is_or, match);
}
} elseif (IsA(clause, ScalarArrayOpExpr))
{
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) clause;
FmgrInfo opproc;
/* valid only after examine_opclause_args returns true */
Node *clause_expr; Const *cst; bool expronleft;
Oid collid; int idx;
/* array evaluation */
ArrayType *arrayval;
int16 elmlen; bool elmbyval; char elmalign; int num_elems;
Datum *elem_values; bool *elem_nulls;
fmgr_info(get_opcode(expr->opno), &opproc);
/* extract the var/expr and const from the expression */ if (!examine_opclause_args(expr->args, &clause_expr, &cst, &expronleft))
elog(ERROR, "incompatible clause");
/* We expect Var on left */ if (!expronleft)
elog(ERROR, "incompatible clause");
/* match the attribute/expression to a dimension of the statistic */
idx = mcv_match_expression(clause_expr, keys, exprs, &collid);
/* *WalkthroughtheMCVitemsandevaluatethecurrentclause.We *canskipitemsthatwerealreadyruledout,andterminateif *therearenoremainingMCVitemsthatmightpossiblymatch.
*/ for (int i = 0; i < mcvlist->nitems; i++)
{ int j; bool match = !expr->useOr;
MCVItem *item = &mcvlist->items[i];
match = RESULT_MERGE(match, expr->useOr, elem_match);
}
/* update the match bitmap with the result */
matches[i] = RESULT_MERGE(matches[i], is_or, match);
}
} elseif (IsA(clause, NullTest))
{
NullTest *expr = (NullTest *) clause;
Node *clause_expr = (Node *) (expr->arg);
/* match the attribute/expression to a dimension of the statistic */ int idx = mcv_match_expression(clause_expr, keys, exprs, NULL);
/* *WalkthroughtheMCVitemsandevaluatethecurrentclause.We *canskipitemsthatwerealreadyruledout,andterminateif *therearenoremainingMCVitemsthatmightpossiblymatch.
*/ for (int i = 0; i < mcvlist->nitems; i++)
{ bool match = false; /* assume mismatch */
MCVItem *item = &mcvlist->items[i];
/* if the clause mismatches the MCV item, update the bitmap */ switch (expr->nulltesttype)
{ case IS_NULL:
match = (item->isnull[idx]) ? true : match; break;
case IS_NOT_NULL:
match = (!item->isnull[idx]) ? true : match; break;
}
/* now, update the match bitmap, depending on OR/AND type */
matches[i] = RESULT_MERGE(matches[i], is_or, match);
}
} elseif (is_orclause(clause) || is_andclause(clause))
{ /* AND/OR clause, with all subclauses being compatible */
int i;
BoolExpr *bool_clause = ((BoolExpr *) clause);
List *bool_clauses = bool_clause->args;
/* match/mismatch bitmap for each MCV item */ bool *bool_matches = NULL;
/* build the match bitmap for the NOT-clause */
not_matches = mcv_get_match_bitmap(root, not_args, keys, exprs,
mcvlist, false);
/* *Mergethebitmapproducedbymcv_get_match_bitmapintothe *currentone.We'rehandlingaNOTclause,soinverttheresult *beforemergingitintotheglobalbitmap.
*/ for (i = 0; i < mcvlist->nitems; i++)
matches[i] = RESULT_MERGE(matches[i], is_or, !not_matches[i]);
pfree(not_matches);
} elseif (IsA(clause, Var))
{ /* Var (has to be a boolean Var, possibly from below NOT) */
Var *var = (Var *) (clause);
/* match the attribute to a dimension of the statistic */ int idx = bms_member_index(keys, var->varattno);
Assert(var->vartype == BOOLOID);
/* *WalkthroughtheMCVitemsandevaluatethecurrentclause.We *canskipitemsthatwerealreadyruledout,andterminateif *therearenoremainingMCVitemsthatmightpossiblymatch.
*/ for (int i = 0; i < mcvlist->nitems; i++)
{
MCVItem *item = &mcvlist->items[i]; bool match = false;
/* if the item is NULL, it's a mismatch */ if (!item->isnull[idx] && DatumGetBool(item->values[idx]))
match = true;
/* update the result bitmap */
matches[i] = RESULT_MERGE(matches[i], is_or, match);
}
} else
{ /* Otherwise, it must be a bare boolean-returning expression */ int idx;
/* match the expression to a dimension of the statistic */
idx = mcv_match_expression(clause, keys, exprs, NULL);
/* *WalkthroughtheMCVitemsandevaluatethecurrentclause.We *canskipitemsthatwerealreadyruledout,andterminateif *therearenoremainingMCVitemsthatmightpossiblymatch.
*/ for (int i = 0; i < mcvlist->nitems; i++)
{ bool match;
MCVItem *item = &mcvlist->items[i];
/* "match" just means it's bool TRUE */
match = !item->isnull[idx] && DatumGetBool(item->values[idx]);
/* now, update the match bitmap, depending on OR/AND type */
matches[i] = RESULT_MERGE(matches[i], is_or, match);
}
}
}
/* match/mismatch bitmap for each MCV item */ bool *matches = NULL;
/* load the MCV list stored in the statistics object */
mcv = statext_mcv_load(stat->statOid, rte->inh);
/* build a match bitmap for the clauses */
matches = mcv_get_match_bitmap(root, clauses, stat->keys, stat->exprs,
mcv, false);
/* sum frequencies for all the matching MCV items */
*basesel = 0.0;
*totalsel = 0.0; for (i = 0; i < mcv->nitems; i++)
{
*totalsel += mcv->items[i].frequency;
if (matches[i] != false)
{
*basesel += mcv->items[i].base_frequency;
s += mcv->items[i].frequency;
}
}
/* update the OR-matches bitmap for the next clause */
(*or_matches)[i] = (*or_matches)[i] || new_matches[i];
}
pfree(new_matches);
return s;
}
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.62Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.