staticdouble ndistinct_for_combination(double totalrows, StatsBuildData *data, int k, int *combination); staticdouble estimate_ndistinct(double totalrows, int numrows, int d, int f1); staticint n_choose_k(int n, int k); staticint num_combinations(int n);
/* size of the struct header fields (magic, type, nitems) */ #define SizeOfHeader (3 * sizeof(uint32))
/* minimal size of a ndistinct item (with two attributes) */ #define MinSizeOfItem SizeOfItem(2)
/* minimal size of mvndistinct, when all items are minimal */ #define MinSizeOfItems(nitems) \
(SizeOfHeader + (nitems) * MinSizeOfItem)
/* Combination generator API */
/* internal state for generator of k-combinations of n elements */ typedefstruct CombinationGenerator
{ int k; /* size of the combination */ int n; /* total number of elements */ int current; /* index of the next combination to return */ int ncombinations; /* number of combinations (size of array) */ int *combinations; /* array of pre-built combinations */
} CombinationGenerator;
static CombinationGenerator *generator_init(int n, int k); staticvoid generator_free(CombinationGenerator *state); staticint *generator_next(CombinationGenerator *state); staticvoid generate_combinations(CombinationGenerator *state);
/* *statext_ndistinct_build *Computendistinctcoefficientforthecombinationofattributes. * *Thiscomputesthendistinctestimateusingthesameestimatorused *inanalyze.candthencomputesthecoefficient. * *Tohandleexpressionseasily,wetreatthemassystemattributeswith *negativeattnums,andoffseteverythingbynumberofexpressionsto *allowusingBitmapsets.
*/
MVNDistinct *
statext_ndistinct_build(double totalrows, StatsBuildData *data)
{
MVNDistinct *result; int k; int itemcnt; int numattrs = data->nattnums; int numcombs = num_combinations(numattrs);
htup = SearchSysCache2(STATEXTDATASTXOID,
ObjectIdGetDatum(mvoid), BoolGetDatum(inh)); if (!HeapTupleIsValid(htup))
elog(ERROR, "cache lookup failed for statistics object %u", mvoid);
ndist = SysCacheGetAttr(STATEXTDATASTXOID, htup,
Anum_pg_statistic_ext_data_stxdndistinct, &isnull); if (isnull)
elog(ERROR, "requested statistics kind \"%c\" is not yet built for statistics object %u",
STATS_EXT_NDISTINCT, mvoid);
result = statext_ndistinct_deserialize(DatumGetByteaPP(ndist));
/* Store the base struct values (magic, type, nitems) */
memcpy(tmp, &ndistinct->magic, sizeof(uint32));
tmp += sizeof(uint32);
memcpy(tmp, &ndistinct->type, sizeof(uint32));
tmp += sizeof(uint32);
memcpy(tmp, &ndistinct->nitems, sizeof(uint32));
tmp += sizeof(uint32);
/* *storenumberofattributesandattributenumbersforeachentry
*/ for (i = 0; i < ndistinct->nitems; i++)
{
MVNDistinctItem item = ndistinct->items[i]; int nmembers = item.nattributes;
/* we expect at least the basic fields of MVNDistinct struct */ if (VARSIZE_ANY_EXHDR(data) < SizeOfHeader)
elog(ERROR, "invalid MVNDistinct size %zu (expected at least %zu)",
VARSIZE_ANY_EXHDR(data), SizeOfHeader);
/* initialize pointer to the data part (skip the varlena header) */
tmp = VARDATA_ANY(data);
if (ndist.magic != STATS_NDISTINCT_MAGIC)
elog(ERROR, "invalid ndistinct magic %08x (expected %08x)",
ndist.magic, STATS_NDISTINCT_MAGIC); if (ndist.type != STATS_NDISTINCT_TYPE_BASIC)
elog(ERROR, "invalid ndistinct type %d (expected %d)",
ndist.type, STATS_NDISTINCT_TYPE_BASIC); if (ndist.nitems == 0)
elog(ERROR, "invalid zero-length item array in MVNDistinct");
/* what minimum bytea size do we expect for those parameters */
minimum_size = MinSizeOfItems(ndist.nitems); if (VARSIZE_ANY_EXHDR(data) < minimum_size)
elog(ERROR, "invalid MVNDistinct size %zu (expected at least %zu)",
VARSIZE_ANY_EXHDR(data), minimum_size);
/* still within the bytea */
Assert(tmp <= ((char *) data + VARSIZE_ANY(data)));
}
/* we should have consumed the whole bytea exactly */
Assert(tmp == ((char *) data + VARSIZE_ANY(data)));
return ndistinct;
}
/* *pg_ndistinct_in *inputroutinefortypepg_ndistinct * *pg_ndistinctisrealenoughtobeatablecolumn,butithasno *operationsofitsown,anddisallowsinput(justlikepg_node_tree).
*/
Datum
pg_ndistinct_in(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot accept a value of type %s", "pg_ndistinct")));
/* *pg_ndistinct_recv *binaryinputroutinefortypepg_ndistinct
*/
Datum
pg_ndistinct_recv(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot accept a value of type %s", "pg_ndistinct")));
type = lookup_type_cache(typid, TYPECACHE_LT_OPR); if (type->lt_opr == InvalidOid) /* shouldn't happen */
elog(ERROR, "cache lookup failed for ordering operator for type %u",
typid);
/* prepare the sort function for this dimension */
multi_sort_add_dimension(mss, i, type->lt_opr, collid);
/* accumulate all the data for this dimension into the arrays */ for (j = 0; j < numrows; j++)
{
items[j].values[i] = data->values[combination[i]][j];
items[j].isnull[i] = data->nulls[combination[i]][j];
}
}
/* We can sort the array now ... */
qsort_interruptible(items, numrows, sizeof(SortItem),
multi_sort_compare, mss);
/* ... and count the number of distinct combinations */
f1 = 0;
cnt = 1;
d = 1; for (i = 1; i < numrows; i++)
{ if (multi_sort_compare(&items[i], &items[i - 1], mss) != 0)
{ if (cnt == 1)
f1 += 1;
/* The Duj1 estimator (already used in analyze.c). */ staticdouble
estimate_ndistinct(double totalrows, int numrows, int d, int f1)
{ double numer,
denom,
ndistinct;
/* Clamp to sane range in case of roundoff error */ if (ndistinct < (double) d)
ndistinct = (double) d;
if (ndistinct > totalrows)
ndistinct = totalrows;
return floor(ndistinct + 0.5);
}
/* *n_choose_k *computesbinomialcoefficientsusinganalgorithmthatisboth *efficientandpreventsoverflows
*/ staticint
n_choose_k(int n, int k)
{ int d,
r;
Assert((k > 0) && (n >= k));
/* use symmetry of the binomial coefficients */
k = Min(k, n - k);
r = 1; for (d = 1; d <= k; ++d)
{
r *= n--;
r /= d;
}
/* *generate_combinations_recurse *givenaprefix,generateallpossiblecombinations * *Givenaprefix(firstfewelementsofthecombination),generatefollowing *elementsrecursively.Wegeneratethecombinationsinlexicographicorder, *whicheliminatespermutationsofthesamecombination.
*/ staticvoid
generate_combinations_recurse(CombinationGenerator *state, int index, int start, int *current)
{ /* If we haven't filled all the elements, simply recurse. */ if (index < state->k)
{ int i;
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.