/* Extra data for compute_array_stats function */ typedefstruct
{ /* Information about array element type */
Oid type_id; /* element type's OID */
Oid eq_opr; /* default equality operator's OID */
Oid coll_id; /* collation to use */ bool typbyval; /* physical properties of element type */
int16 typlen; char typalign;
/* A hash table entry for the Lossy Counting algorithm */ typedefstruct
{
Datum key; /* This is 'e' from the LC algorithm. */ int frequency; /* This is 'f'. */ int delta; /* And this is 'delta'. */ int last_container; /* For de-duplication of array elements. */
} TrackItem;
/* A hash table entry for distinct-elements counts */ typedefstruct
{ int count; /* Count of distinct elements in an array */ int frequency; /* Number of arrays seen with this count */
} DECountItem;
/* *array_typanalyze--typanalyzefunctionforarraycolumns
*/
Datum
array_typanalyze(PG_FUNCTION_ARGS)
{
VacAttrStats *stats = (VacAttrStats *) PG_GETARG_POINTER(0);
Oid element_typeid;
TypeCacheEntry *typentry;
ArrayAnalyzeExtraData *extra_data;
/* *Callthestandardtypanalyzefunction.Itmayfailtofindneeded *operators,inwhichcasewealsocan'tdoanything,sojustfail.
*/ if (!std_typanalyze(stats))
PG_RETURN_BOOL(false);
/* *Checkattributedatatypeisavarlenaarray(oradomainoverone).
*/
element_typeid = get_base_element_type(stats->attrtypid); if (!OidIsValid(element_typeid))
elog(ERROR, "array_typanalyze was invoked for non-array type %u",
stats->attrtypid);
if (!OidIsValid(typentry->eq_opr) ||
!OidIsValid(typentry->cmp_proc_finfo.fn_oid) ||
!OidIsValid(typentry->hash_proc_finfo.fn_oid))
PG_RETURN_BOOL(true);
/* Store our findings for use by compute_array_stats() */
extra_data = (ArrayAnalyzeExtraData *) palloc(sizeof(ArrayAnalyzeExtraData));
extra_data->type_id = typentry->type_id;
extra_data->eq_opr = typentry->eq_opr;
extra_data->coll_id = stats->attrcollid; /* collation we should use */
extra_data->typbyval = typentry->typbyval;
extra_data->typlen = typentry->typlen;
extra_data->typalign = typentry->typalign;
extra_data->cmp = &typentry->cmp_proc_finfo;
extra_data->hash = &typentry->hash_proc_finfo;
/* Save old compute_stats and extra_data for scalar statistics ... */
extra_data->std_compute_stats = stats->compute_stats;
extra_data->std_extra_data = stats->extra_data;
/* ... and replace with our info */
stats->compute_stats = compute_array_stats;
stats->extra_data = extra_data;
/* This is D from the LC algorithm. */
HTAB *elements_tab;
HASHCTL elem_hash_ctl;
HASH_SEQ_STATUS scan_status;
/* This is the current bucket number from the LC algorithm */ int b_current;
/* This is 'w' from the LC algorithm */ int bucket_width; int array_no;
int64 element_no;
TrackItem *item; int slot_idx;
HTAB *count_tab;
HASHCTL count_hash_ctl;
DECountItem *count_item;
/* Loop over the arrays. */ for (array_no = 0; array_no < samplerows; array_no++)
{
Datum value; bool isnull;
ArrayType *array; int num_elems;
Datum *elem_values; bool *elem_nulls; bool null_present; int j;
int64 prev_element_no = element_no; int distinct_count; bool count_item_found;
vacuum_delay_point(true);
value = fetchfunc(stats, array_no, &isnull); if (isnull)
{ /* ignore arrays that are null overall */ continue;
}
/* *Weloopthroughtheelementsinthearrayandaddthemtoour *trackinghashtable.
*/
null_present = false; for (j = 0; j < num_elems; j++)
{
Datum elem_value; bool found;
/* No null element processing other than flag setting here */ if (elem_nulls[j])
{
null_present = true; continue;
}
/* Lookup current element in hashtable, adding it if new */
elem_value = elem_values[j];
item = (TrackItem *) hash_search(elements_tab,
&elem_value,
HASH_ENTER, &found);
if (found)
{ /* The element value is already on the tracking list */
/* *Theoperatorsweassistignoreduplicatearrayelements,so *countagivendistinctelementonlyonceperarray.
*/ if (item->last_container == array_no) continue;
item->frequency++;
item->last_container = array_no;
} else
{ /* Initialize new tracking list element */
/* element_no is the number of elements processed (ie N) */
element_no++;
/* We prune the D structure after processing each bucket */ if (element_no % bucket_width == 0)
{
prune_element_hashtable(elements_tab, b_current);
b_current++;
}
}
/* Count null element presence once per array. */ if (null_present)
null_elem_cnt++;
/* Update frequency of the particular array distinct element count. */
distinct_count = (int) (element_no - prev_element_no);
count_item = (DECountItem *) hash_search(count_tab, &distinct_count,
HASH_ENTER,
&count_item_found);
if (count_item_found)
count_item->frequency++; else
count_item->frequency = 1;
/* Free memory allocated while detoasting. */ if (PointerGetDatum(array) != value)
pfree(array);
pfree(elem_values);
pfree(elem_nulls);
}
/* Skip pg_statistic slots occupied by standard statistics */
slot_idx = 0; while (slot_idx < STATISTIC_NUM_SLOTS && stats->stakind[slot_idx] != 0)
slot_idx++; if (slot_idx > STATISTIC_NUM_SLOTS - 2)
elog(ERROR, "insufficient pg_statistic slots for array stats");
/* We can only compute real stats if we found some non-null values. */ if (analyzed_rows > 0)
{ int nonnull_cnt = analyzed_rows; int count_items_count; int i;
TrackItem **sort_table; int track_len;
int64 cutoff_freq;
int64 minfreq,
maxfreq;
hash_seq_init(&scan_status, elements_tab); while ((item = (TrackItem *) hash_seq_search(&scan_status)) != NULL)
{ if (item->frequency + item->delta <= b_current)
{
Datum value = item->key;
if (hash_search(elements_tab, &item->key,
HASH_REMOVE, NULL) == NULL)
elog(ERROR, "hash table corrupted"); /* We should free memory if element is not passed by value */ if (!array_extra_data->typbyval)
pfree(DatumGetPointer(value));
}
}
}
/* *Hashfunctionforelements. * *Weusetheelementtype'sdefaulthashopclass,andthecolumncollation *ifthetypeiscollation-sensitive.
*/ static uint32
element_hash(constvoid *key, Size keysize)
{
Datum d = *((const Datum *) key);
Datum h;
h = FunctionCall1Coll(array_extra_data->hash,
array_extra_data->coll_id,
d); return DatumGetUInt32(h);
}
/* *Matchingfunctionforelements,tobeusedinhashtablelookups.
*/ staticint
element_match(constvoid *key1, constvoid *key2, Size keysize)
{ /* The keysize parameter is superfluous here */ return element_compare(key1, key2);
}
/* *Comparisonfunctionforelements. * *Weusetheelementtype'sdefaultbtreeopclass,andthecolumncollation *ifthetypeiscollation-sensitive. * *XXXconsiderusingSortSupportinfrastructure
*/ staticint
element_compare(constvoid *key1, constvoid *key2)
{
Datum d1 = *((const Datum *) key1);
Datum d2 = *((const Datum *) key2);
Datum c;
c = FunctionCall2Coll(array_extra_data->cmp,
array_extra_data->coll_id,
d1, d2); return DatumGetInt32(c);
}
¤ 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.0.21Bemerkung:
(vorverarbeitet am 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.