/* * cmsketch_merge_agg transition function - * * returns the merge of the transition state and the given cmsketch */ Datum cmsketch_merge_agg_trans(PG_FUNCTION_ARGS) { MemoryContext old; MemoryContext context; CountMinSketch *state; CountMinSketch *incoming = (CountMinSketch *) PG_GETARG_VARLENA_P(1); if (!AggCheckCallContext(fcinfo, &context)) elog(ERROR, "cmsketch_merge_agg_trans called in non-aggregate context"); old = MemoryContextSwitchTo(context); if (PG_ARGISNULL(0)) { state = CountMinSketchCopy(incoming); PG_RETURN_POINTER(state); } state = (CountMinSketch *) PG_GETARG_VARLENA_P(0); state = CountMinSketchMerge(state, incoming); MemoryContextSwitchTo(old); PG_RETURN_POINTER(state); }
/* * bloom_intersection_agg transition function - * * returns the intersection of the transition state and the given Bloom filter */ Datum bloom_intersection_agg_trans(PG_FUNCTION_ARGS) { MemoryContext old; MemoryContext context; BloomFilter *state; BloomFilter *incoming = (BloomFilter *) PG_GETARG_VARLENA_P(1); if (!AggCheckCallContext(fcinfo, &context)) elog(ERROR, "bloom_union_agg_trans called in non-aggregate context"); old = MemoryContextSwitchTo(context); if (PG_ARGISNULL(0)) { state = BloomFilterCopy(incoming); PG_RETURN_POINTER(state); } state = (BloomFilter *) PG_GETARG_VARLENA_P(0); state = BloomFilterIntersection(state, incoming); MemoryContextSwitchTo(old); PG_RETURN_POINTER(state); }
Datum fss_merge_agg_trans(PG_FUNCTION_ARGS) { MemoryContext old; MemoryContext context; FSS *state; FSS *incoming = fss_fix_ptrs(PG_GETARG_VARLENA_P(1)); if (!AggCheckCallContext(fcinfo, &context)) elog(ERROR, "fss_merge_agg_trans called in non-aggregate context"); old = MemoryContextSwitchTo(context); if (PG_ARGISNULL(0)) { state = FSSCopy(incoming); PG_RETURN_POINTER(state); } state = fss_fix_ptrs(PG_GETARG_VARLENA_P(0)); state = FSSMerge(state, incoming); MemoryContextSwitchTo(old); PG_RETURN_POINTER(state); }
/* * hll_union_agg transition function - * * returns the union of the transition state and the given HLL */ Datum hll_union_agg_trans(PG_FUNCTION_ARGS) { MemoryContext old; MemoryContext context; HyperLogLog *state; HyperLogLog *incoming = (HyperLogLog *) PG_GETARG_VARLENA_P(1); if (!AggCheckCallContext(fcinfo, &context)) elog(ERROR, "hll_union_agg_trans called in non-aggregate context"); old = MemoryContextSwitchTo(context); if (PG_ARGISNULL(0)) state = hll_startup(fcinfo, incoming->p); else state = (HyperLogLog *) PG_GETARG_VARLENA_P(0); state = HLLUnion(state, incoming); MemoryContextSwitchTo(old); SET_VARSIZE(state, HLLSize(state)); PG_RETURN_POINTER(state); }
/* * keyed_min_max_combine_internal */ static Datum keyed_min_max_combine_internal(FunctionCallInfo fcinfo, int sign) { KeyedAggState *kas; KeyValue *state; KeyValue *incoming = (KeyValue *) PG_GETARG_VARLENA_P(1); MemoryContext old; MemoryContext context; int cmp; bool isnull; if (!AggCheckCallContext(fcinfo, &context)) elog(ERROR, "keyed_min_combine_internal called in non-aggregate context"); if (PG_ARGISNULL(0)) { /* * We can't use the startup function that the aggregate uses because * the combiner Aggref doesn't have all of the original arguments. */ old = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); kas = palloc0(sizeof(KeyedAggState)); kas->key_type = lookup_type_cache(incoming->key_type, TYPECACHE_CMP_PROC_FINFO); kas->value_type = lookup_type_cache(incoming->value_type, 0); fcinfo->flinfo->fn_extra = kas; MemoryContextSwitchTo(old); old = MemoryContextSwitchTo(context); state = copy_kv(kas, incoming); MemoryContextSwitchTo(old); PG_RETURN_POINTER(state); } old = MemoryContextSwitchTo(context); state = (KeyValue *) PG_GETARG_VARLENA_P(0); kas = (KeyedAggState *) fcinfo->flinfo->fn_extra; incoming = point_to_self(kas, (struct varlena *) incoming); cmp = sign * compare_keys(kas, state, incoming->key, KV_KEY_IS_NULL(incoming), state->key_collation, &isnull); if (!isnull && cmp <= 0) state = copy_kv(kas, incoming); MemoryContextSwitchTo(old); PG_RETURN_POINTER(state); }
/* * cmsketch_agg transition function - * * adds the given element to the transition cmsketch using the given value for p and n */ Datum cmsketch_agg_transp(PG_FUNCTION_ARGS) { MemoryContext old; MemoryContext context; CountMinSketch *state; Datum incoming = PG_GETARG_DATUM(1); float8 eps = PG_GETARG_FLOAT8(2); float8 p = PG_GETARG_FLOAT8(3); if (!AggCheckCallContext(fcinfo, &context)) elog(ERROR, "cmsketch_agg_transp called in non-aggregate context"); old = MemoryContextSwitchTo(context); if (PG_ARGISNULL(0)) state = cmsketch_startup(fcinfo, eps, p); else state = (CountMinSketch *) PG_GETARG_VARLENA_P(0); state = cmsketch_add_datum(fcinfo, state, incoming, 1); MemoryContextSwitchTo(old); PG_RETURN_POINTER(state); }
/* * Returns the estimate normalized frequency of the item */ Datum cmsketch_norm_frequency(PG_FUNCTION_ARGS) { CountMinSketch *cms; Datum elem = PG_GETARG_DATUM(1); float8 freq = 0; Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 1); TypeCacheEntry *typ; StringInfo buf; if (val_type == InvalidOid) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data type"))); if (PG_ARGISNULL(0)) PG_RETURN_FLOAT8(freq); cms = (CountMinSketch *) PG_GETARG_VARLENA_P(0); typ = lookup_type_cache(val_type, 0); buf = makeStringInfo(); DatumToBytes(elem, typ, buf); freq = CountMinSketchEstimateNormFrequency(cms, buf->data, buf->len); pfree(buf->data); pfree(buf); PG_RETURN_FLOAT8(freq); }
/* * txid_snapshot_xip(txid_snapshot) returns setof int8 * * return in-progress TXIDs in snapshot. */ Datum txid_snapshot_xip(PG_FUNCTION_ARGS) { FuncCallContext *fctx; TxidSnapshot *snap; txid value; /* on first call initialize snap_state and get copy of snapshot */ if (SRF_IS_FIRSTCALL()) { TxidSnapshot *arg = (TxidSnapshot *) PG_GETARG_VARLENA_P(0); fctx = SRF_FIRSTCALL_INIT(); /* make a copy of user snapshot */ snap = MemoryContextAlloc(fctx->multi_call_memory_ctx, VARSIZE(arg)); memcpy(snap, arg, VARSIZE(arg)); fctx->user_fctx = snap; } /* return values one-by-one */ fctx = SRF_PERCALL_SETUP(); snap = fctx->user_fctx; if (fctx->call_cntr < snap->nxip) { value = snap->xip[fctx->call_cntr]; SRF_RETURN_NEXT(fctx, Int64GetDatum(value)); } else { SRF_RETURN_DONE(fctx); } }
static BloomFilter * bloom_operation(FunctionCallInfo fcinfo, bool intersection) { Oid bf_type = LookupTypeNameOid(NULL, SystemTypeName("bloom"), false); BloomFilter *result = NULL; int i; for (i = 0; i < PG_NARGS(); i++) { BloomFilter *bf; if (PG_ARGISNULL(i)) continue; if (get_fn_expr_argtype(fcinfo->flinfo, i) != bf_type) elog(ERROR, "argument %d is not of type \"bloom\"", i + 1); bf = (BloomFilter *) PG_GETARG_VARLENA_P(i); if (result) { if (bf->m != result->m) elog(ERROR, "bloom filters must have the same p"); else if (bf->k != result->k) elog(ERROR, "bloom filters must have the same n"); } if (result == NULL) result = bf; else if (intersection) result = BloomFilterIntersection(result, bf); else result = BloomFilterUnion(result, bf); } return result; }
Datum fss_agg_trans(PG_FUNCTION_ARGS) { MemoryContext old; MemoryContext context; FSS *state; Datum incoming = PG_GETARG_DATUM(1); if (!AggCheckCallContext(fcinfo, &context)) elog(ERROR, "fss_agg_trans called in non-aggregate context"); old = MemoryContextSwitchTo(context); if (PG_ARGISNULL(0)) { uint16_t k = PG_GETARG_INT64(2); Oid type = AggGetInitialArgType(fcinfo); TypeCacheEntry *typ = lookup_type_cache(type, 0); fcinfo->flinfo->fn_extra = typ; state = FSSCreate(k, typ); } else state = fss_fix_ptrs(PG_GETARG_VARLENA_P(0)); FSSIncrement(state, incoming); MemoryContextSwitchTo(old); PG_RETURN_POINTER(state); }
/* * Returns the estimate count of the item */ Datum cmsketch_count(PG_FUNCTION_ARGS) { CountMinSketch *cms; Datum elem = PG_GETARG_DATUM(1); uint32_t count = false; Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 1); TypeCacheEntry *typ; Size size; if (val_type == InvalidOid) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data type"))); if (PG_ARGISNULL(0)) PG_RETURN_INT32(count); cms = (CountMinSketch *) PG_GETARG_VARLENA_P(0); typ = lookup_type_cache(val_type, 0); size = datumGetSize(elem, typ->typbyval, typ->typlen); if (typ->typbyval) count = CountMinSketchEstimateCount(cms, (char *) &elem, size); else count = CountMinSketchEstimateCount(cms, DatumGetPointer(elem), size); PG_RETURN_INT32(count); }
/* * txid_snapshot_xmax(txid_snapshot) returns int8 * * return snapshot's xmax */ Datum txid_snapshot_xmax(PG_FUNCTION_ARGS) { TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0); PG_RETURN_INT64(snap->xmax); }
/* * hll_agg transition function - * * adds the given element to the transition HLL using the given value for p */ Datum hll_agg_transp(PG_FUNCTION_ARGS) { MemoryContext old; MemoryContext context; HyperLogLog *state; Datum incoming = PG_GETARG_DATUM(1); int p = PG_GETARG_INT32(2); if (!AggCheckCallContext(fcinfo, &context)) elog(ERROR, "hll_agg_transp called in non-aggregate context"); old = MemoryContextSwitchTo(context); if (PG_ARGISNULL(0)) state = hll_startup(fcinfo, p); else state = (HyperLogLog *) PG_GETARG_VARLENA_P(0); state = hll_add_datum(fcinfo, state, incoming); MemoryContextSwitchTo(old); PG_RETURN_POINTER(state); }
/* * bloom_agg transition function - * * adds the given element to the transition Bloom Filter using the given value for p and n */ Datum bloom_agg_transp(PG_FUNCTION_ARGS) { MemoryContext old; MemoryContext context; BloomFilter *state; float8 p = PG_GETARG_FLOAT8(2); uint64_t n = PG_GETARG_INT64(3); if (!AggCheckCallContext(fcinfo, &context)) elog(ERROR, "bloom_agg_transp called in non-aggregate context"); old = MemoryContextSwitchTo(context); if (PG_ARGISNULL(0)) state = bloom_startup(fcinfo, p, n); else state = (BloomFilter *) PG_GETARG_VARLENA_P(0); if (!PG_ARGISNULL(1)) state = bloom_add_datum(fcinfo, state, PG_GETARG_DATUM(1)); MemoryContextSwitchTo(old); PG_RETURN_POINTER(state); }
/* * Returns whether the Bloom filter contains the item or not */ Datum bloom_contains(PG_FUNCTION_ARGS) { BloomFilter *bloom; Datum elem = PG_GETARG_DATUM(1); bool contains = false; Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 1); TypeCacheEntry *typ; StringInfo buf; if (val_type == InvalidOid) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data type"))); if (PG_ARGISNULL(0)) PG_RETURN_BOOL(contains); bloom = (BloomFilter *) PG_GETARG_VARLENA_P(0); typ = lookup_type_cache(val_type, 0); buf = makeStringInfo(); DatumToBytes(elem, typ, buf); contains = BloomFilterContains(bloom, buf->data, buf->len); pfree(buf->data); pfree(buf); PG_RETURN_BOOL(contains); }
/* * cms_topn_frequency is a user-facing UDF which returns the estimated frequency * of an item. The first parameter is for CmsTopn and second is for the item to * return the frequency. */ Datum cms_topn_frequency(PG_FUNCTION_ARGS) { CmsTopn *cmsTopn = (CmsTopn *) PG_GETARG_VARLENA_P(0); ArrayType *topnArray = TopnArray(cmsTopn); Datum item = PG_GETARG_DATUM(1); Oid itemType = get_fn_expr_argtype(fcinfo->flinfo, 1); TypeCacheEntry *itemTypeCacheEntry = NULL; Frequency frequency = 0; if (itemType == InvalidOid) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data types"))); } if (topnArray != NULL && itemType != ARR_ELEMTYPE(topnArray)) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Not proper type for this cms_topn"))); } itemTypeCacheEntry = lookup_type_cache(itemType, 0); frequency = CmsTopnEstimateItemFrequency(cmsTopn, item, itemTypeCacheEntry); PG_RETURN_INT32(frequency); }
/* ** Allows the construction of a cube from 2 float[]'s */ Datum cube_a_f8_f8(PG_FUNCTION_ARGS) { int i; int dim; int size; NDBOX *result; ArrayType *ur, *ll; double *dur, *dll; ur = (ArrayType *) PG_GETARG_VARLENA_P(0); ll = (ArrayType *) PG_GETARG_VARLENA_P(1); if (ARR_HASNULL(ur) || ARR_HASNULL(ll)) { ereport(ERROR, (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("Cannot work with NULL arrays"))); } dim = ARRNELEMS(ur); if (ARRNELEMS(ll) != dim) { ereport(ERROR, (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("UR and LL arrays must be of same length"))); } dur = ARRPTR(ur); dll = ARRPTR(ll); size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim; result = (NDBOX *) palloc(size); memset(result, 0, size); result->size = size; result->dim = dim; for (i = 0; i < dim; i++) { result->x[i] = dur[i]; result->x[i + dim] = dll[i]; } PG_RETURN_NDBOX(result); }
Datum cmsketch_add(PG_FUNCTION_ARGS) { CountMinSketch *cms = (CountMinSketch *) PG_GETARG_VARLENA_P(0); fcinfo->flinfo->fn_extra = lookup_type_cache(get_fn_expr_argtype(fcinfo->flinfo, 1), 0); cms = cmsketch_add_datum(fcinfo, cms, PG_GETARG_DATUM(1)); PG_RETURN_POINTER(cms); }
/* * txid_visible_in_snapshot(int8, txid_snapshot) returns bool * * is txid visible in snapshot ? */ Datum txid_visible_in_snapshot(PG_FUNCTION_ARGS) { txid value = PG_GETARG_INT64(0); TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(1); PG_RETURN_BOOL(is_visible_txid(value, snap)); }
Datum xmlnode_kind(PG_FUNCTION_ARGS) { xmlnode nodeRaw = (xmlnode) PG_GETARG_VARLENA_P(0); XMLNodeHdr node = XNODE_ROOT(nodeRaw); char *kindStr = getXMLNodeKindStr(node->kind); PG_RETURN_TEXT_P(cstring_to_text(kindStr)); }
Datum xmldoc_out(PG_FUNCTION_ARGS) { xmldoc doc = (xmldoc) PG_GETARG_VARLENA_P(0); char *data = (char *) VARDATA(doc); XMLNodeOffset rootNdOff = XNODE_ROOT_OFFSET(doc); PG_RETURN_CSTRING(dumpXMLNode(data, rootNdOff)); }
/* * cms_topn_union is a user-facing UDF which takes two cms_topn and returns * their union. */ Datum cms_topn_union(PG_FUNCTION_ARGS) { CmsTopn *firstCmsTopn = NULL; CmsTopn *secondCmsTopn = NULL; CmsTopn *newCmsTopn = NULL; ArrayType *firstTopnArray = NULL; Size firstTopnArrayLength = 0; TypeCacheEntry *itemTypeCacheEntry = NULL; /* * If both cms_topn is null, it returns null. If one of the cms_topn's is * null, it returns other cms_topn. */ if (PG_ARGISNULL(0) && PG_ARGISNULL(1)) { PG_RETURN_NULL(); } else if (PG_ARGISNULL(0)) { secondCmsTopn = (CmsTopn *) PG_GETARG_VARLENA_P(1); PG_RETURN_POINTER(secondCmsTopn); } else if (PG_ARGISNULL(1)) { firstCmsTopn = (CmsTopn *) PG_GETARG_VARLENA_P(0); PG_RETURN_POINTER(firstCmsTopn); } firstCmsTopn = (CmsTopn *) PG_GETARG_VARLENA_P(0); secondCmsTopn = (CmsTopn *) PG_GETARG_VARLENA_P(1); firstTopnArray = TopnArray(firstCmsTopn); firstTopnArrayLength = ARR_DIMS(firstTopnArray)[0]; if (firstTopnArrayLength != 0) { Oid itemType = firstTopnArray->elemtype; itemTypeCacheEntry = lookup_type_cache(itemType, 0); } newCmsTopn = CmsTopnUnion(firstCmsTopn, secondCmsTopn, itemTypeCacheEntry); PG_RETURN_POINTER(newCmsTopn); }
Datum xmlnode_children(PG_FUNCTION_ARGS) { xmlnode nodeRaw = (xmlnode) PG_GETARG_VARLENA_P(0); char *data = (char *) VARDATA(nodeRaw); XMLNodeOffset rootNdOff = XNODE_ROOT_OFFSET(nodeRaw); XMLNodeHdr node = (XMLNodeHdr) (data + rootNdOff); TypeInfo nodeType; ArrayType *result; /* * Unfortunately the type info has to be retrieved every time again. If * the backend used global variable to remember the values, all backends * would have to invalidate the values whenever the extension gets dropped * / created. */ Assert(fcinfo->flinfo != NULL); initXNodeTypeInfo(fcinfo->flinfo->fn_oid, 0, &nodeType); if (node->kind == XMLNODE_DOC || node->kind == XMLNODE_ELEMENT || node->kind == XMLNODE_DOC_FRAGMENT) { XMLCompNodeHdr root = (XMLCompNodeHdr) node; unsigned short children = root->children; Datum *elems; char *childOffPtr; unsigned short i; if (children == 0) { result = construct_empty_array(nodeType.oid); PG_RETURN_POINTER(result); } elems = (Datum *) palloc(children * sizeof(Datum)); childOffPtr = XNODE_FIRST_REF(root); for (i = 0; i < children; i++) { XMLNodeOffset childOff = readXMLNodeOffset(&childOffPtr, XNODE_GET_REF_BWIDTH(root), true); XMLNodeHdr childNode = (XMLNodeHdr) (data + rootNdOff - childOff); char *childNodeCopy = copyXMLNode(childNode, NULL, true, NULL); elems[i] = PointerGetDatum(childNodeCopy); } result = construct_array(elems, children, nodeType.oid, nodeType.elmlen, nodeType.elmbyval, nodeType.elmalign); PG_RETURN_POINTER(result); } else { result = construct_empty_array(nodeType.oid); PG_RETURN_POINTER(result); } }
Datum xmlnode_debug_print(PG_FUNCTION_ARGS) { xmlnode nodeRaw = (xmlnode) PG_GETARG_VARLENA_P(0); char *data = (char *) VARDATA(nodeRaw); StringInfo output = makeStringInfo(); dumpXMLNodeDebug(output, data, XNODE_ROOT_OFFSET(nodeRaw)); PG_RETURN_TEXT_P(cstring_to_text(output->data)); }
/* * cms_topn_add_agg_with_parameters is a aggregate function to add items. It * allows to specify parameters of created CmsTopn structure. In addition to * cms_topn_add_agg function, it takes error bound and confidence interval * parameters as the forth and fifth parameters. */ Datum cms_topn_add_agg_with_parameters(PG_FUNCTION_ARGS) { CmsTopn *currentCmsTopn = NULL; CmsTopn *updatedCmsTopn = NULL; uint32 topnItemCount = PG_GETARG_UINT32(2); float8 errorBound = PG_GETARG_FLOAT8(3); float8 confidenceInterval = PG_GETARG_FLOAT8(4); Datum newItem = 0; TypeCacheEntry *newItemTypeCacheEntry = NULL; Oid newItemType = InvalidOid; if (!AggCheckCallContext(fcinfo, NULL)) { ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("cms_topn_add_agg_with_parameters called in " "non-aggregate context"))); } /* check whether cms_topn is null and create if it is */ if (PG_ARGISNULL(0)) { currentCmsTopn = CreateCmsTopn(topnItemCount, errorBound, confidenceInterval); } else { currentCmsTopn = (CmsTopn *) PG_GETARG_VARLENA_P(0); } /* if new item is null, return current CmsTopn */ if (PG_ARGISNULL(1)) { PG_RETURN_POINTER(currentCmsTopn); } /* * Keep type cache entry between subsequent calls in order to get rid of * cache lookup overhead. */ newItem = PG_GETARG_DATUM(1); if (fcinfo->flinfo->fn_extra == NULL) { newItemType = get_fn_expr_argtype(fcinfo->flinfo, 1); newItemTypeCacheEntry = lookup_type_cache(newItemType, 0); fcinfo->flinfo->fn_extra = newItemTypeCacheEntry; } else { newItemTypeCacheEntry = fcinfo->flinfo->fn_extra; } updatedCmsTopn = UpdateCmsTopn(currentCmsTopn, newItem, newItemTypeCacheEntry); PG_RETURN_POINTER(updatedCmsTopn); }
Datum cmsketch_out(PG_FUNCTION_ARGS) { StringInfoData buf; CountMinSketch *cms = (CountMinSketch *) PG_GETARG_VARLENA_P(0); initStringInfo(&buf); appendStringInfo(&buf, "{ d = %d, w = %d, count = %d, size = %ldkB }", cms->d, cms->w, cms->count, CountMinSketchSize(cms) / 1024); PG_RETURN_CSTRING(buf.data); }
Datum hll_out(PG_FUNCTION_ARGS) { StringInfoData buf; HyperLogLog *hll = (HyperLogLog *) PG_GETARG_VARLENA_P(0); initStringInfo(&buf); appendStringInfo(&buf, "{ p = %d, cardinality = %ld, size = %dkB }", hll->p, HLLCardinality(hll), hll->mlen / 1024); PG_RETURN_CSTRING(buf.data); }
/* * Returns the estimate frequency of the item */ Datum cmsketch_total(PG_FUNCTION_ARGS) { CountMinSketch *cms; if (PG_ARGISNULL(0)) PG_RETURN_INT64(0); cms = (CountMinSketch *) PG_GETARG_VARLENA_P(0); PG_RETURN_INT64(cms->count); }
/* * Returns the cardinality of the given Bloom filter */ Datum bloom_cardinality(PG_FUNCTION_ARGS) { BloomFilter *bloom; if (PG_ARGISNULL(0)) PG_RETURN_INT64(0); bloom = (BloomFilter *) PG_GETARG_VARLENA_P(0); PG_RETURN_INT64(BloomFilterCardinality(bloom)); }
/* * Returns the cardinality of the given HLL */ Datum hll_cardinality(PG_FUNCTION_ARGS) { HyperLogLog *hll; if (PG_ARGISNULL(0)) PG_RETURN_INT64(0); hll = (HyperLogLog *) PG_GETARG_VARLENA_P(0); PG_RETURN_INT64(HLLCardinality(hll)); }