/* *Usedinternallytorefertoanindividualstatisticsobject,i.e., *apg_statistic_extentry.
*/ typedefstruct StatExtEntry
{
Oid statOid; /* OID of pg_statistic_ext entry */ char *schema; /* statistics object's schema */ char *name; /* statistics object's name */
Bitmapset *columns; /* attribute numbers covered by the object */
List *types; /* 'char' list of enabled statistics kinds */ int stattarget; /* statistics target (-1 for default) */
List *exprs; /* expressions */
} StatExtEntry;
static List *fetch_statentries_for_relation(Relation pg_statext, Oid relid); static VacAttrStats **lookup_var_attr_stats(Bitmapset *attrs, List *exprs, int nvacatts, VacAttrStats **vacatts); staticvoid statext_store(Oid statOid, bool inh,
MVNDistinct *ndistinct, MVDependencies *dependencies,
MCVList *mcv, Datum exprs, VacAttrStats **stats); staticint statext_compute_stattarget(int stattarget, int nattrs, VacAttrStats **stats);
/* Information needed to analyze a single simple expression. */ typedefstruct AnlExprData
{
Node *expr; /* expression to analyze */
VacAttrStats *vacattrstat; /* statistics attrs to analyze */
} AnlExprData;
staticvoid compute_expr_stats(Relation onerel, AnlExprData *exprdata, int nexprs, HeapTuple *rows, int numrows); static Datum serialize_expr_stats(AnlExprData *exprdata, int nexprs); static Datum expr_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull); static AnlExprData *build_expr_data(List *exprs, int stattarget);
static StatsBuildData *make_build_data(Relation rel, StatExtEntry *stat, int numrows, HeapTuple *rows,
VacAttrStats **stats, int stattarget);
/* Do nothing if there are no columns to analyze. */ if (!natts) return;
/* the list of stats has to be allocated outside the memory context */
pg_stext = table_open(StatisticExtRelationId, RowExclusiveLock);
statslist = fetch_statentries_for_relation(pg_stext, RelationGetRelid(onerel));
/* memory context for building each statistics object */
cxt = AllocSetContextCreate(CurrentMemoryContext, "BuildRelationExtStatistics",
ALLOCSET_DEFAULT_SIZES);
oldcxt = MemoryContextSwitchTo(cxt);
/* should not happen, thanks to checks when defining stats */ if (!stat->exprs)
elog(ERROR, "requested expression stats, but there are no expressions");
/* *Ifthere'sstatisticstargetsetforthestatisticsobject,useit.It *maybesetto0whichdisablesbuildingofthatstatistic.
*/ if (stattarget >= 0) return stattarget;
/* *Thetargetforthestatisticsobjectissetto-1,inwhichcasewe *lookatthemaximumtargetsetforanyoftheattributestheobjectis *definedon.
*/ for (i = 0; i < nattrs; i++)
{ /* keep the maximum statistics target */ if (stats[i]->attstattarget > stattarget)
stattarget = stats[i]->attstattarget;
}
/* *Thefieldsdescribingthestats->stavalues[n]elementtypesdefaultto *thetypeofthedatabeinganalyzed,butthetype-specifictypanalyze *functioncanchangethemifitwantstostoresomethingelse.
*/ for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
{
stats->statypid[i] = stats->attrtypid;
stats->statyplen[i] = stats->attrtype->typlen;
stats->statypbyval[i] = stats->attrtype->typbyval;
stats->statypalign[i] = stats->attrtype->typalign;
}
/* *Callthetype-specifictypanalyzefunction.Ifnoneisspecified,use *std_typanalyze().
*/ if (OidIsValid(stats->attrtype->typanalyze))
ok = DatumGetBool(OidFunctionCall1(stats->attrtype->typanalyze,
PointerGetDatum(stats))); else
ok = std_typanalyze(stats);
typtuple = SearchSysCacheCopy1(TYPEOID,
ObjectIdGetDatum(stats->attrtypid)); if (!HeapTupleIsValid(typtuple))
elog(ERROR, "cache lookup failed for type %u", stats->attrtypid);
stats->attrtype = (Form_pg_type) GETSTRUCT(typtuple);
stats->anl_context = CurrentMemoryContext; /* XXX should be using
* something else? */
stats->tupattnum = InvalidAttrNumber;
/* *Thefieldsdescribingthestats->stavalues[n]elementtypesdefaultto *thetypeofthedatabeinganalyzed,butthetype-specifictypanalyze *functioncanchangethemifitwantstostoresomethingelse.
*/ for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
{
stats->statypid[i] = stats->attrtypid;
stats->statyplen[i] = stats->attrtype->typlen;
stats->statypbyval[i] = stats->attrtype->typbyval;
stats->statypalign[i] = stats->attrtype->typalign;
}
/* *Callthetype-specifictypanalyzefunction.Ifnoneisspecified,use *std_typanalyze().
*/ if (OidIsValid(stats->attrtype->typanalyze))
ok = DatumGetBool(OidFunctionCall1(stats->attrtype->typanalyze,
PointerGetDatum(stats))); else
ok = std_typanalyze(stats);
/* *Using'vacatts'ofsize'nvacatts'asinputdata,returnanewly-built *VacAttrStatsarraywhichincludesonlytheitemscorrespondingto *attributesindicatedby'attrs'.Ifwedon'thavealloftheper-column *statsavailabletocomputetheextendedstats,thenwereturnNULLto *indicatetothecallerthatthestatsshouldnotbebuilt.
*/ static VacAttrStats **
lookup_var_attr_stats(Bitmapset *attrs, List *exprs, int nvacatts, VacAttrStats **vacatts)
{ int i = 0; int x = -1; int natts;
VacAttrStats **stats;
ListCell *lc;
int
multi_sort_compare_dims(int start, int end, const SortItem *a, const SortItem *b,
MultiSortSupport mss)
{ int dim;
for (dim = start; dim <= end; dim++)
{ int r = ApplySortComparator(a->values[dim], a->isnull[dim],
b->values[dim], b->isnull[dim],
&mss->ssup[dim]);
if (r != 0) return r;
}
return0;
}
int
compare_scalars_simple(constvoid *a, constvoid *b, void *arg)
{ return compare_datums_simple(*(Datum *) a,
*(Datum *) b,
(SortSupport) arg);
}
int
compare_datums_simple(Datum a, Datum b, SortSupport ssup)
{ return ApplySortComparator(a, false, b, false, ssup);
}
/* *build_attnums_array *TransformsabitmapintoanarrayofAttrNumbervalues. * *Thisisusedforextendedstatisticsonly,soalltheattributesmustbe *user-defined.ThatmeansoffsettingbyFirstLowInvalidHeapAttributeNumber *isnotnecessaryhere(andwhenqueryingthebitmap).
*/
AttrNumber *
build_attnums_array(Bitmapset *attrs, int nexprs, int *numattrs)
{ int i,
j;
AttrNumber *attnums; int num = bms_num_members(attrs);
if (numattrs)
*numattrs = num;
/* build attnums from the bitmapset */
attnums = (AttrNumber *) palloc(sizeof(AttrNumber) * num);
i = 0;
j = -1; while ((j = bms_next_member(attrs, j)) >= 0)
{ int attnum = (j - nexprs);
/* protect against overflows */
Assert(i <= num);
}
return attnums;
}
/* *build_sorted_items *buildasortedarrayofSortItemwithvaluesfromrows * *Note:Allthememoryisallocatedinasinglechunk,sothatthecaller *cansimplypfreethereturnvaluetoreleaseallofit.
*/
SortItem *
build_sorted_items(StatsBuildData *data, int *nitems,
MultiSortSupport mss, int numattrs, AttrNumber *attnums)
{ int i,
j,
len,
nrows; int nvalues = data->numrows * numattrs;
SortItem *items;
Datum *values; bool *isnull; char *ptr; int *typlen;
/* Compute the total amount of memory we need (both items and values). */
len = data->numrows * sizeof(SortItem) + nvalues * (sizeof(Datum) + sizeof(bool));
/* Allocate the memory and split it into the pieces. */
ptr = palloc0(len);
/* make sure we consumed the whole buffer exactly */
Assert((ptr - (char *) items) == len);
/* fix the pointers to Datum and bool arrays */
nrows = 0; for (i = 0; i < data->numrows; i++)
{
items[nrows].values = &values[nrows * numattrs];
items[nrows].isnull = &isnull[nrows * numattrs];
nrows++;
}
/* build a local cache of typlen for all attributes */
typlen = (int *) palloc(sizeof(int) * data->nattnums); for (i = 0; i < data->nattnums; i++)
typlen[i] = get_typlen(data->stats[i]->attrtypid);
nrows = 0; for (i = 0; i < data->numrows; i++)
{ bool toowide = false;
/* load the values/null flags from sample rows */ for (j = 0; j < numattrs; j++)
{
Datum value; bool isnull; int attlen;
AttrNumber attnum = attnums[j];
int idx;
/* match attnum to the pre-calculated data */ for (idx = 0; idx < data->nattnums; idx++)
{ if (attnum == data->attnums[idx]) break;
}
Assert(idx < data->nattnums);
value = data->values[idx][i];
isnull = data->nulls[idx][i];
attlen = typlen[idx];
foreach(lc, stats)
{ int i;
StatisticExtInfo *info = (StatisticExtInfo *) lfirst(lc);
Bitmapset *matched_attnums = NULL;
Bitmapset *matched_exprs = NULL; int num_matched; int numkeys;
/* skip statistics that are not of the correct type */ if (info->kind != requiredkind) continue;
/* skip statistics with mismatching inheritance flag */ if (info->inherit != inh) continue;
/* *Collectattributesandexpressionsinremaining(unestimated) *clausesfullycoveredbythisstatisticobject. * *Weknowalreadyestimatedclauseshavebothclause_attnumsand *clause_exprssettoNULL.WeleavethepointersNULLifalready *estimated,orweresetthemtoNULLafterestimatingtheclause.
*/ for (i = 0; i < nclauses; i++)
{
Bitmapset *expr_idxs = NULL;
/* ignore incompatible/estimated clauses */ if (!clause_attnums[i] && !clause_exprs[i]) continue;
/* ignore clauses that are not covered by this object */ if (!bms_is_subset(clause_attnums[i], info->keys) ||
!stat_covers_expressions(info, clause_exprs[i], &expr_idxs)) continue;
/* record attnums and indexes of expressions covered */
matched_attnums = bms_add_members(matched_attnums, clause_attnums[i]);
matched_exprs = bms_add_members(matched_exprs, expr_idxs);
}
/* plain Var references (boolean Vars or recursive checks) */ if (IsA(clause, Var))
{
Var *var = (Var *) clause;
/* Ensure var is from the correct relation */ if (var->varno != relid) returnfalse;
/* we also better ensure the Var is from the current level */ if (var->varlevelsup > 0) returnfalse;
/* *Alsorejectsystemattributesandwhole-rowVars(wedon'tallow *statsonthose).
*/ if (!AttrNumberIsForUserDefinedAttr(var->varattno)) returnfalse;
/* OK, record the attnum for later permissions checks. */
*attnums = bms_add_member(*attnums, var->varattno);
returntrue;
}
/* (Var/Expr op Const) or (Const op Var/Expr) */ if (is_opclause(clause))
{
OpExpr *expr = (OpExpr *) clause;
Node *clause_expr;
/* Only expressions with two arguments are considered compatible. */ if (list_length(expr->args) != 2) returnfalse;
/* Check if the expression has the right shape */ if (!examine_opclause_args(expr->args, &clause_expr, NULL, NULL)) returnfalse;
/* *Ifit'snotoneofthesupportedoperators("=","<",">",etc.), *justignoretheclause,asit'snotcompatiblewithMCVlists. * *Thisusesthefunctionforestimatingselectivity,nottheoperator *directly(abitawkward,butwell...).
*/ switch (get_oprrest(expr->opno))
{ case F_EQSEL: case F_NEQSEL: case F_SCALARLTSEL: case F_SCALARLESEL: case F_SCALARGTSEL: case F_SCALARGESEL: /* supported, will continue with inspection of the Var/Expr */ break;
default: /* other estimators are considered unknown/unsupported */ returnfalse;
}
/* Check if the operator is leakproof */ if (*leakproof)
*leakproof = get_func_leakproof(get_opcode(expr->opno));
/* Check (Var op Const) or (Const op Var) clauses by recursing. */ if (IsA(clause_expr, Var)) return statext_is_compatible_clause_internal(root, clause_expr,
relid, attnums,
exprs, leakproof);
/* Otherwise we have (Expr op Const) or (Const op Expr). */
*exprs = lappend(*exprs, clause_expr); returntrue;
}
/* Var/Expr IN Array */ if (IsA(clause, ScalarArrayOpExpr))
{
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) clause;
Node *clause_expr; bool expronleft;
/* Only expressions with two arguments are considered compatible. */ if (list_length(expr->args) != 2) returnfalse;
/* Check if the expression has the right shape (one Var, one Const) */ if (!examine_opclause_args(expr->args, &clause_expr, NULL, &expronleft)) returnfalse;
/* We only support Var on left, Const on right */ if (!expronleft) returnfalse;
/* *Ifit'snotoneofthesupportedoperators("=","<",">",etc.), *justignoretheclause,asit'snotcompatiblewithMCVlists. * *Thisusesthefunctionforestimatingselectivity,nottheoperator *directly(abitawkward,butwell...).
*/ switch (get_oprrest(expr->opno))
{ case F_EQSEL: case F_NEQSEL: case F_SCALARLTSEL: case F_SCALARLESEL: case F_SCALARGTSEL: case F_SCALARGESEL: /* supported, will continue with inspection of the Var/Expr */ break;
default: /* other estimators are considered unknown/unsupported */ returnfalse;
}
/* Check if the operator is leakproof */ if (*leakproof)
*leakproof = get_func_leakproof(get_opcode(expr->opno));
/* Check Var IN Array clauses by recursing. */ if (IsA(clause_expr, Var)) return statext_is_compatible_clause_internal(root, clause_expr,
relid, attnums,
exprs, leakproof);
/* Otherwise we have Expr IN Array. */
*exprs = lappend(*exprs, clause_expr); returntrue;
}
/* apply as many extended statistics as possible */ while (true)
{
StatisticExtInfo *stat;
List *stat_clauses;
Bitmapset *simple_clauses;
/* find the best suited statistics object for these attnums */
stat = choose_best_statistics(rel->statlist, STATS_EXT_MCV, rte->inh,
list_attnums, list_exprs,
list_length(clauses));
/* *ifno(additional)matchingstatscouldbefoundthenwe'venothing *todo
*/ if (!stat) break;
/* Ensure choose_best_statistics produced an expected stats type. */
Assert(stat->kind == STATS_EXT_MCV);
/* now filter the clauses to be estimated using the selected MCV */
stat_clauses = NIL;
/* record which clauses are simple (single column or expression) */
simple_clauses = NULL;
listidx = -1;
foreach(l, clauses)
{ /* Increment the index before we decide if to skip the clause. */
listidx++;
/* record simple clauses (single column or expression) */ if ((list_attnums[listidx] == NULL &&
list_length(list_exprs[listidx]) == 1) ||
(list_exprs[listidx] == NIL &&
bms_membership(list_attnums[listidx]) == BMS_SINGLETON))
simple_clauses = bms_add_member(simple_clauses,
list_length(stat_clauses));
/* add clause to list and mark it as estimated */
stat_clauses = lappend(stat_clauses, (Node *) lfirst(l));
*estimatedclauses = bms_add_member(*estimatedclauses, listidx);
/* Set up for expression evaluation */
ExecStoreHeapTuple(rows[i], slot, false);
/* *Evaluatetheexpression.Wedothisintheper-tuplecontextso *asnottoleakmemory,andthencopytheresultintothe *contextcreatedatthebeginningofthisfunction.
*/
datum = ExecEvalExprSwitchContext(exprstate,
GetPerTupleExprContext(estate),
&isnull); if (isnull)
{
exprvals[tcnt] = (Datum) 0;
exprnulls[tcnt] = true;
} else
{ /* Make sure we copy the data into the context. */
Assert(CurrentMemoryContext == expr_context);
/* form an array of pg_statistic rows (per update_attstats) */ static Datum
serialize_expr_stats(AnlExprData *exprdata, int nexprs)
{ int exprno;
Oid typOid;
Relation sd;
/* lookup OID of composite type for pg_statistic */
typOid = get_rel_type_id(StatisticRelationId); if (!OidIsValid(typOid))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("relation \"%s\" does not have a composite type", "pg_statistic")));
for (exprno = 0; exprno < nexprs; exprno++)
{ int i,
k;
VacAttrStats *stats = exprdata[exprno].vacattrstat;
Datum values[Natts_pg_statistic]; bool nulls[Natts_pg_statistic];
HeapTuple stup;
htup = SearchSysCache2(STATEXTDATASTXOID,
ObjectIdGetDatum(stxoid), BoolGetDatum(inh)); if (!HeapTupleIsValid(htup))
elog(ERROR, "cache lookup failed for statistics object %u", stxoid);
value = SysCacheGetAttr(STATEXTDATASTXOID, htup,
Anum_pg_statistic_ext_data_stxdexpr, &isnull); if (isnull)
elog(ERROR, "requested statistics kind \"%c\" is not yet built for statistics object %u",
STATS_EXT_EXPRESSIONS, stxoid);
eah = DatumGetExpandedArray(value);
deconstruct_expanded_array(eah);
if (eah->dnulls && eah->dnulls[idx])
{ /* No data found for this expression, give up. */
ReleaseSysCache(htup); return NULL;
}
td = DatumGetHeapTupleHeader(eah->dvalues[idx]);
/* Build a temporary HeapTuple control structure */
tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
ItemPointerSetInvalid(&(tmptup.t_self));
tmptup.t_tableOid = InvalidOid;
tmptup.t_data = td;
int i; int k; int idx;
TupleTableSlot *slot;
EState *estate;
ExprContext *econtext;
List *exprstates = NIL; int nkeys = bms_num_members(stat->columns) + list_length(stat->exprs);
ListCell *lc;
/* allocate everything as a single chunk, so we can free it easily */
len = MAXALIGN(sizeof(StatsBuildData));
len += MAXALIGN(sizeof(AttrNumber) * nkeys); /* attnums */
len += MAXALIGN(sizeof(VacAttrStats *) * nkeys); /* stats */
/* values */
len += MAXALIGN(sizeof(Datum *) * nkeys);
len += nkeys * MAXALIGN(sizeof(Datum) * numrows);
/* nulls */
len += MAXALIGN(sizeof(bool *) * nkeys);
len += nkeys * MAXALIGN(sizeof(bool) * numrows);
ptr = palloc(len);
/* set the pointers */
result = (StatsBuildData *) ptr;
ptr += MAXALIGN(sizeof(StatsBuildData));
/* we have it allocated, so let's fill the values */
result->nattnums = nkeys;
result->numrows = numrows;
/* fill the attribute info - first attributes, then expressions */
idx = 0;
k = -1; while ((k = bms_next_member(stat->columns, k)) >= 0)
{
result->attnums[idx] = k;
result->stats[idx] = stats[idx];
/* first extract values for all the regular attributes */ for (i = 0; i < numrows; i++)
{
idx = 0;
k = -1; while ((k = bms_next_member(stat->columns, k)) >= 0)
{
result->values[idx][i] = heap_getattr(rows[i], k,
result->stats[idx]->tupDesc,
&result->nulls[idx][i]);
idx++;
}
}
/* Need an EState for evaluation expressions. */
estate = CreateExecutorState();
econtext = GetPerTupleExprContext(estate);
/* Need a slot to hold the current heap tuple, too */
slot = MakeSingleTupleTableSlot(RelationGetDescr(rel),
&TTSOpsHeapTuple);
/* Arrange for econtext's scan tuple to be the tuple under test */
econtext->ecxt_scantuple = slot;
/* Set up expression evaluation state */
exprstates = ExecPrepareExprList(stat->exprs, estate);
for (i = 0; i < numrows; i++)
{ /* *Resettheper-tuplecontexteachtime,toreclaimanycruftleft *behindbyevaluatingthestatisticsobjectexpressions.
*/
ResetExprContext(econtext);
/* Set up for expression evaluation */
ExecStoreHeapTuple(rows[i], slot, false);
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.