Datum _lca(PG_FUNCTION_ARGS) { ArrayType *la = PG_GETARG_ARRAYTYPE_P(0); int num = ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la)); ltree *item = (ltree *) ARR_DATA_PTR(la); ltree **a, *res; if (ARR_NDIM(la) > 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array must be one-dimensional"))); if (ARR_HASNULL(la)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("array must not contain nulls"))); a = (ltree **) palloc(sizeof(ltree *) * num); while (num > 0) { num--; a[num] = item; item = NEXTVAL(item); } res = lca_inner(a, ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la))); pfree(a); PG_FREE_IF_COPY(la, 0); if (res) PG_RETURN_POINTER(res); else PG_RETURN_NULL(); }
/* * Equality */ static bool float8arr_equals_internal(ArrayType *left, ArrayType *right) { int dimleft = ARR_NDIM(left), dimright = ARR_NDIM(right); int *dimsleft = ARR_DIMS(left), *dimsright = ARR_DIMS(right); int numleft = ArrayGetNItems(dimleft,dimsleft); int numright = ArrayGetNItems(dimright,dimsright); double *vals_left=(double *)ARR_DATA_PTR(left), *vals_right=(double *)ARR_DATA_PTR(right); bits8 *bitmap_left=ARR_NULLBITMAP(left), *bitmap_right=ARR_NULLBITMAP(right); int bitmask=1; if ((dimsleft!=dimsright) || (numleft!=numright)) { return(false); } /* * Note that we are only defined for FLOAT8OID */ //get_typlenbyvalalign(ARR_ELEMTYPE(array), // &typlen, &typbyval, &typalign); /* * First we'll check to see if the null bitmaps are equivalent */ if (bitmap_left) if (! bitmap_right) return(false); if (bitmap_right) if (! bitmap_left) return(false); if (bitmap_left) { for (int i=0; i<numleft; i++) { if ((*bitmap_left & bitmask) == 0) if ((*bitmap_left & bitmask) != 0) return(false); bitmask <<= 1; if (bitmask == 0x100) { bitmap_left++; bitmask = 1; } } } /* * Now we check for equality of all array values */ for (int i=0; i<numleft; i++) if (vals_left[i] != vals_right[i]) return(false); return(true); }
static jvalue _doubleArray_coerceDatum(Type self, Datum arg) { jvalue result; ArrayType* v = DatumGetArrayTypeP(arg); jsize nElems = (jsize)ArrayGetNItems(ARR_NDIM(v), ARR_DIMS(v)); jdoubleArray doubleArray = JNI_newDoubleArray(nElems); #if (PGSQL_MAJOR_VER == 8 && PGSQL_MINOR_VER < 2) JNI_setDoubleArrayRegion(doubleArray, 0, nElems, (jdouble*)ARR_DATA_PTR(v)); #else if(ARR_HASNULL(v)) { jsize idx; jboolean isCopy = JNI_FALSE; bits8* nullBitMap = ARR_NULLBITMAP(v); jdouble* values = (jdouble*)ARR_DATA_PTR(v); jdouble* elems = JNI_getDoubleArrayElements(doubleArray, &isCopy); for(idx = 0; idx < nElems; ++idx) { if(arrayIsNull(nullBitMap, idx)) elems[idx] = 0; else elems[idx] = *values++; } JNI_releaseDoubleArrayElements(doubleArray, elems, JNI_COMMIT); } else JNI_setDoubleArrayRegion(doubleArray, 0, nElems, (jdouble*)ARR_DATA_PTR(v)); #endif result.l = (jobject)doubleArray; return result; }
static jvalue _booleanArray_coerceDatum(Type self, Datum arg) { jvalue result; ArrayType* v = DatumGetArrayTypeP(arg); jsize nElems = (jsize)ArrayGetNItems(ARR_NDIM(v), ARR_DIMS(v)); jbooleanArray booleanArray = JNI_newBooleanArray(nElems); if(ARR_HASNULL(v)) { jsize idx; jboolean isCopy = JNI_FALSE; bits8* nullBitMap = ARR_NULLBITMAP(v); jboolean* values = (jboolean*)ARR_DATA_PTR(v); jboolean* elems = JNI_getBooleanArrayElements(booleanArray, &isCopy); for(idx = 0; idx < nElems; ++idx) { if(arrayIsNull(nullBitMap, idx)) elems[idx] = 0; else elems[idx] = *values++; } JNI_releaseBooleanArrayElements(booleanArray, elems, JNI_COMMIT); } else JNI_setBooleanArrayRegion(booleanArray, 0, nElems, (jboolean*)ARR_DATA_PTR(v)); result.l = (jobject)booleanArray; return result; }
static jvalue _Array_coerceDatum(Type self, Datum arg) { jvalue result; jsize idx; Type elemType = Type_getElementType(self); int16 elemLength = Type_getLength(elemType); char elemAlign = Type_getAlign(elemType); bool elemByValue = Type_isByValue(elemType); ArrayType* v = DatumGetArrayTypeP(arg); jsize nElems = (jsize)ArrayGetNItems(ARR_NDIM(v), ARR_DIMS(v)); jobjectArray objArray = JNI_newObjectArray(nElems, Type_getJavaClass(elemType), 0); const char* values = ARR_DATA_PTR(v); bits8* nullBitMap = ARR_NULLBITMAP(v); for(idx = 0; idx < nElems; ++idx) { if(arrayIsNull(nullBitMap, idx)) JNI_setObjectArrayElement(objArray, idx, 0); else { Datum value = fetch_att(values, elemByValue, elemLength); jvalue obj = Type_coerceDatum(elemType, value); JNI_setObjectArrayElement(objArray, idx, obj.l); JNI_deleteLocalRef(obj.l); values = att_addlength_datum(values, elemLength, PointerGetDatum(values)); values = (char*)att_align_nominal(values, elemAlign); } } result.l = (jobject)objArray; return result; }
/* * Returns a SparseData formed from a dense float8[] in uncompressed format. * This is useful for creating a SparseData without processing that can be * used by the SparseData processing routines. */ static SparseData sdata_uncompressed_from_float8arr_internal(ArrayType *array) { int dim = ARR_NDIM(array); int *dims = ARR_DIMS(array); int num = ArrayGetNItems(dim,dims); double *vals =(double *)ARR_DATA_PTR(array); bits8 *bitmap = ARR_NULLBITMAP(array); int bitmask=1; SparseData result = makeInplaceSparseData( (char *)vals,NULL, num*sizeof(float8),0,FLOAT8OID, num,num); /* * Convert null items into zeros */ if (bitmap) { for (int i=0; i<num; i++) { if ((*bitmap& bitmask) == 0) vals[i] = 0.; bitmask <<= 1; if (bitmask == 0x100) { bitmap++; bitmask = 1; } } } return(result); }
static ArrayType * intArrayInit(int ndims, int const * dims, int const * lbs) { ArrayType * res; int size; int nbytes; if (ndims < 0) /* we do allow zero-dimension arrays */ ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid number of dimensions: %d", ndims))); if (ndims > MAXDIM) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", ndims, MAXDIM))); /* fast track for empty array */ if (ndims == 0) return construct_empty_array(INT4OID); size = ArrayGetNItems(ndims, dims); nbytes = ARR_OVERHEAD_NONULLS(ndims); nbytes += size * 4; res = palloc0(nbytes); SET_VARSIZE(res, nbytes); res->ndim = ndims; res->elemtype = INT4OID; res->dataoffset = 0; memcpy(ARR_DIMS(res), dims, ndims * sizeof(int)); memcpy(ARR_LBOUND(res), lbs, ndims * sizeof(int)); return res; }
static bool array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree **found) { int num = ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la)); ltree *item = (ltree *) ARR_DATA_PTR(la); if (ARR_NDIM(la) > 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array must be one-dimensional"))); if (ARR_HASNULL(la)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("array must not contain nulls"))); if (found) *found = NULL; while (num > 0) { if (DatumGetBool(DirectFunctionCall2(callback, PointerGetDatum(item), PointerGetDatum(param)))) { if (found) *found = item; return true; } num--; item = NEXTVAL(item); } return false; }
void dump_bvf1_inputs(ArrayType *broker_list_p, text *sector_name_p) { int ndim, nitems; int *dim; int16 typlen; bool typbyval; char typalign; int i; char *broker_list; ndim = ARR_NDIM(broker_list_p); dim = ARR_DIMS(broker_list_p); nitems = ArrayGetNItems(ndim, dim); get_typlenbyvalalign(ARR_ELEMTYPE(broker_list_p), &typlen, &typbyval, &typalign); broker_list = ARR_DATA_PTR(broker_list_p); elog(NOTICE, "BVF1: INPUTS START"); for (i = 0; i < nitems; i++) { elog(NOTICE, "BVF1: broker_list[%d] %s", i, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(broker_list)))); broker_list = att_addlength_pointer(broker_list, typlen, broker_list); broker_list = (char *) att_align_nominal(broker_list, typalign); } elog(NOTICE, "BVF1: sector_name %s", DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(sector_name_p)))); elog(NOTICE, "BVF1: INPUTS END"); }
Datum _lt_q_regex(PG_FUNCTION_ARGS) { ArrayType *_tree = PG_GETARG_ARRAYTYPE_P(0); ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1); lquery *query = (lquery *) ARR_DATA_PTR(_query); bool res = false; int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query)); if (ARR_NDIM(_query) > 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array must be one-dimensional"))); if (ARR_HASNULL(_query)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("array must not contain nulls"))); while (num > 0) { if (array_iterator(_tree, ltq_regex, (void *) query, NULL)) { res = true; break; } num--; query = (lquery *) NEXTVAL(query); } PG_FREE_IF_COPY(_tree, 0); PG_FREE_IF_COPY(_query, 1); PG_RETURN_BOOL(res); }
Datum findentropy(PG_FUNCTION_ARGS) { ArrayType *values = PG_GETARG_ARRAYTYPE_P(0); ArrayType *classes = PG_GETARG_ARRAYTYPE_P(1); int posvalues = PG_GETARG_INT32(2); int posclasses = PG_GETARG_INT32(3); int dimvalues = ARR_NDIM(values); int *dimsvalues = ARR_DIMS(values); int numvalues = ArrayGetNItems(dimvalues,dimsvalues); int32 *vals_values=(int32 *)ARR_DATA_PTR(values); int32 *vals_classes=(int32 *)ARR_DATA_PTR(classes); int *pre_entropy = (int*)palloc(sizeof(int)*posclasses); int i; int j; int sum = 0; float8 result = 0; for (i=0; i<posvalues; ++i){ memset(pre_entropy, 0, sizeof(int)*posclasses); for(j=0, sum=0; j<numvalues; ++j){ if(vals_values[j] == (i+1)){ pre_entropy[vals_classes[j]-1]++; sum++; } } result += entropyWeighted(pre_entropy, posclasses, (float)sum, (float)numvalues); } free(pre_entropy); PG_RETURN_FLOAT8((float8)result); }
Datum lt_q_regex(PG_FUNCTION_ARGS) { ltree *tree = PG_GETARG_LTREE(0); ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1); lquery *query = (lquery *) ARR_DATA_PTR(_query); bool res = false; int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query)); if (ARR_NDIM(_query) != 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array must be one-dimensional"))); while (num > 0) { if (DatumGetBool(DirectFunctionCall2(ltq_regex, PointerGetDatum(tree), PointerGetDatum(query)))) { res = true; break; } num--; query = NEXTVAL(query); } PG_FREE_IF_COPY(tree, 0); PG_FREE_IF_COPY(_query, 1); PG_RETURN_BOOL(res); }
/* * The final function for aggregating the class counts for REP. It takes the class * count array produced by the sfunc and produces a two-element array. The first * element is the ID of the class that has the maximum number of cases represented by * the root node of the subtree being processed. The second element is the number of * reduced misclassified cases if the leave nodes of the subtree are pruned. * * Parameters: * class_count_data: The array containing all the information for the * calculation of Reduced-Error pruning. * Return: * A two element array. */ Datum rep_aggr_class_count_ffunc(PG_FUNCTION_ARGS) { ArrayType *class_count_array = PG_GETARG_ARRAYTYPE_P(0); int array_dim = ARR_NDIM(class_count_array); check_error_value ( array_dim == 1, "invalid array dimension: %d. The dimension of class count array must be equal to 1", array_dim ); int *p_array_dim = ARR_DIMS(class_count_array); int array_length = ArrayGetNItems(array_dim,p_array_dim); int64 *class_count_data = (int64 *)ARR_DATA_PTR(class_count_array); int64 *result = palloc(sizeof(int64)*2); check_error ( result, "memory allocation failure" ); int64 max = class_count_data[1]; int64 sum = max; int maxid = 1; for(int i = 2; i < array_length; ++i) { if(max < class_count_data[i]) { max = class_count_data[i]; maxid = i; } sum += class_count_data[i]; } /* maxid is the id of the class, which has the most cases */ result[0] = maxid; /* * (sum - max) is the number of mis-classified cases represented by * the root node of the subtree being processed * class_count_data[0] the total number of mis-classified cases */ result[1] = class_count_data[0] - (sum - max); ArrayType* result_array = construct_array( (Datum *)result, 2, INT8OID, sizeof(int64), true, 'd' ); PG_RETURN_ARRAYTYPE_P(result_array); }
/* * get_flat_size method for expanded arrays */ static Size EA_get_flat_size(ExpandedObjectHeader *eohptr) { ExpandedArrayHeader *eah = (ExpandedArrayHeader *) eohptr; int nelems; int ndims; Datum *dvalues; bool *dnulls; Size nbytes; int i; Assert(eah->ea_magic == EA_MAGIC); /* Easy if we have a valid flattened value */ if (eah->fvalue) return ARR_SIZE(eah->fvalue); /* If we have a cached size value, believe that */ if (eah->flat_size) return eah->flat_size; /* * Compute space needed by examining dvalues/dnulls. Note that the result * array will have a nulls bitmap if dnulls isn't NULL, even if the array * doesn't actually contain any nulls now. */ nelems = eah->nelems; ndims = eah->ndims; Assert(nelems == ArrayGetNItems(ndims, eah->dims)); dvalues = eah->dvalues; dnulls = eah->dnulls; nbytes = 0; for (i = 0; i < nelems; i++) { if (dnulls && dnulls[i]) continue; nbytes = att_addlength_datum(nbytes, eah->typlen, dvalues[i]); nbytes = att_align_nominal(nbytes, eah->typalign); /* check for overflow of total request */ if (!AllocSizeIsValid(nbytes)) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("array size exceeds the maximum allowed (%d)", (int) MaxAllocSize))); } if (dnulls) nbytes += ARR_OVERHEAD_WITHNULLS(ndims, nelems); else nbytes += ARR_OVERHEAD_NONULLS(ndims); /* cache for next time */ eah->flat_size = nbytes; return nbytes; }
/* * Turn an array into JSON. */ static void array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds) { ArrayType *v = DatumGetArrayTypeP(array); Oid element_type = ARR_ELEMTYPE(v); int *dim; int ndim; int nitems; int count = 0; Datum *elements; bool *nulls; int16 typlen; bool typbyval; char typalign, typdelim; Oid typioparam; Oid typoutputfunc; TYPCATEGORY tcategory; ndim = ARR_NDIM(v); dim = ARR_DIMS(v); nitems = ArrayGetNItems(ndim, dim); if (nitems <= 0) { appendStringInfoString(result,"[]"); return; } get_type_io_data(element_type, IOFunc_output, &typlen, &typbyval, &typalign, &typdelim, &typioparam, &typoutputfunc); deconstruct_array(v, element_type, typlen, typbyval, typalign, &elements, &nulls, &nitems); if (element_type == RECORDOID) tcategory = TYPCATEGORY_COMPOSITE; else if (element_type == JSONOID) tcategory = TYPCATEGORY_JSON; else tcategory = TypeCategory(element_type); array_dim_to_json(result, 0, ndim, dim, elements, &count, tcategory, typoutputfunc, use_line_feeds); pfree(elements); pfree(nulls); }
Datum internal_kmeans_agg_centroid_merge(PG_FUNCTION_ARGS) { /* This function is declared as strict. No checking null here. */ ArrayType *array = NULL; ArrayType *array2 = NULL; if (fcinfo->context && IsA(fcinfo->context, AggState)) array = PG_GETARG_ARRAYTYPE_P(0); else array = PG_GETARG_ARRAYTYPE_P_COPY(0); int array_dim = ARR_NDIM(array); int *p_array_dim = ARR_DIMS(array); int array_length = ArrayGetNItems(array_dim, p_array_dim); array2 = PG_GETARG_ARRAYTYPE_P(1); array_dim = ARR_NDIM(array2); p_array_dim = ARR_DIMS(array2); int array2_length = ArrayGetNItems(array_dim, p_array_dim); if (array_length != array2_length) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Inconsistent array length. " "first: %d, second:%d", format_procedure(fcinfo->flinfo->fn_oid), array_length, array2_length))); } float8* c_array = (float8 *)ARR_DATA_PTR(array); float8* c_array2 = (float8 *)ARR_DATA_PTR(array2); for(int i=0; i<array_length; i++) { c_array[i]+= c_array2[i]; } PG_RETURN_ARRAYTYPE_P(array); }
Datum _ltree_compress(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *retval = entry; if (entry->leafkey) { /* ltree */ ltree_gist *key; ArrayType *val = DatumGetArrayTypeP(entry->key); int4 len = LTG_HDRSIZE + ASIGLEN; int num = ArrayGetNItems(ARR_NDIM(val), ARR_DIMS(val)); ltree *item = (ltree *) ARR_DATA_PTR(val); if (ARR_NDIM(val) != 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array must be one-dimensional"))); key = (ltree_gist *) palloc(len); key->len = len; key->flag = 0; MemSet(LTG_SIGN(key), 0, ASIGLEN); while (num > 0) { hashing(LTG_SIGN(key), item); num--; item = NEXTVAL(item); } retval = (GISTENTRY *) palloc(sizeof(GISTENTRY)); gistentryinit(*retval, PointerGetDatum(key), entry->rel, entry->page, entry->offset, key->len, FALSE); } else if (!LTG_ISALLTRUE(entry->key)) { int4 i, len; ltree_gist *key; BITVECP sign = LTG_SIGN(DatumGetPointer(entry->key)); ALOOPBYTE( if ((sign[i] & 0xff) != 0xff) PG_RETURN_POINTER(retval); );
/* * Turn an array into JSON. */ static void array_to_jsonb_internal(Datum array, JsonbInState *result) { ArrayType *v = DatumGetArrayTypeP(array); Oid element_type = ARR_ELEMTYPE(v); int *dim; int ndim; int nitems; int count = 0; Datum *elements; bool *nulls; int16 typlen; bool typbyval; char typalign; JsonbTypeCategory tcategory; Oid outfuncoid; ndim = ARR_NDIM(v); dim = ARR_DIMS(v); nitems = ArrayGetNItems(ndim, dim); if (nitems <= 0) { result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, NULL); result->res = pushJsonbValue(&result->parseState, WJB_END_ARRAY, NULL); return; } get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign); jsonb_categorize_type(element_type, &tcategory, &outfuncoid); deconstruct_array(v, element_type, typlen, typbyval, typalign, &elements, &nulls, &nitems); array_dim_to_jsonb(result, 0, ndim, dim, elements, nulls, &count, tcategory, outfuncoid); pfree(elements); pfree(nulls); }
Datum pc_typmod_in(PG_FUNCTION_ARGS) { uint32 typmod = 0; Datum *elem_values; int n = 0; int i = 0; ArrayType *arr = (ArrayType *) DatumGetPointer(PG_GETARG_DATUM(0)); if (ARR_ELEMTYPE(arr) != CSTRINGOID) ereport(ERROR, (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("typmod array must be type cstring[]"))); if (ARR_NDIM(arr) != 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("typmod array must be one-dimensional"))); if (ARR_HASNULL(arr)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("typmod array must not contain nulls"))); if (ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr)) > 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("typmod array must have one element"))); deconstruct_array(arr, CSTRINGOID, -2, false, 'c', /* hardwire cstring representation details */ &elem_values, NULL, &n); for (i = 0; i < n; i++) { if ( i == 0 ) /* PCID */ { char *s = DatumGetCString(elem_values[i]); typmod = pg_atoi(s, sizeof(int32), '\0'); } } PG_RETURN_INT32(typmod); }
Datum hash_array( PG_FUNCTION_ARGS) { ArrayType *state = PG_GETARG_ARRAYTYPE_P(0); int dimstate = ARR_NDIM(state); int *dimsstate = ARR_DIMS(state); int numstate = ArrayGetNItems(dimstate,dimsstate); int32 *vals_state=(int32 *)ARR_DATA_PTR(state); unsigned long hash = 65599; unsigned short c; int i = 0; for (;i<numstate;i++) { c = vals_state[i]; hash = c + (hash << 7) + (hash << 16) - hash; } PG_RETURN_INT32(hash); }
Datum ginarrayconsistent(PG_FUNCTION_ARGS) { bool *check = (bool *) PG_GETARG_POINTER(0); StrategyNumber strategy = PG_GETARG_UINT16(1); ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); int res, i, nentries; /* ARRAYCHECK was already done by previous ginarrayextract call */ switch (strategy) { case GinOverlapStrategy: case GinContainedStrategy: /* at least one element in check[] is true, so result = true */ res = TRUE; break; case GinContainsStrategy: case GinEqualStrategy: nentries = ArrayGetNItems(ARR_NDIM(query), ARR_DIMS(query)); res = TRUE; for (i = 0; i < nentries; i++) if (!check[i]) { res = FALSE; break; } break; default: elog(ERROR, "ginarrayconsistent: unknown strategy number: %d", strategy); res = FALSE; } PG_RETURN_BOOL(res); }
static float * getWeights(ArrayType *win) { static float ws[lengthof(weights)]; int i; float4 *arrdata; if (win == NULL) return weights; if (ARR_NDIM(win) != 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array of weight must be one-dimensional"))); if (ArrayGetNItems(ARR_NDIM(win), ARR_DIMS(win)) < lengthof(weights)) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array of weight is too short"))); if (array_contains_nulls(win)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("array of weight must not contain nulls"))); arrdata = (float4 *) ARR_DATA_PTR(win); for (i = 0; i < lengthof(weights); i++) { ws[i] = (arrdata[i] >= 0) ? arrdata[i] : weights[i]; if (ws[i] > 1.0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("weight out of range"))); } return ws; }
Datum aggr_InfoGain(PG_FUNCTION_ARGS) { ArrayType *state = PG_GETARG_ARRAYTYPE_P(0); int dimstate = ARR_NDIM(state); int *dimsstate = ARR_DIMS(state); int numstate = ArrayGetNItems(dimstate,dimsstate); float8 *vals_state=(float8 *)ARR_DATA_PTR(state); float8 truevalue = PG_GETARG_FLOAT8(1); float8 trueweight = PG_GETARG_FLOAT8(2); int32 posclasses = PG_GETARG_INT32(3); int32 trueclass = PG_GETARG_INT32(5); ArrayType *pgarray; vals_state[0] += trueweight; vals_state[trueclass] += trueweight; vals_state[(int)(truevalue*(posclasses+1))] += trueweight; vals_state[(int)(truevalue*(posclasses+1) + trueclass)] += trueweight; pgarray = construct_array((Datum *)vals_state, numstate,FLOAT8OID, sizeof(float8),true,'d'); PG_RETURN_ARRAYTYPE_P(pgarray); }
/*----------------------------------------------------------------------------- * array_cat : * concatenate two nD arrays to form an nD array, or * push an (n-1)D array onto the end of an nD array *---------------------------------------------------------------------------- */ Datum array_cat(PG_FUNCTION_ARGS) { ArrayType *v1, *v2; ArrayType *result; int *dims, *lbs, ndims, nitems, ndatabytes, nbytes; int *dims1, *lbs1, ndims1, nitems1, ndatabytes1; int *dims2, *lbs2, ndims2, nitems2, ndatabytes2; int i; char *dat1, *dat2; bits8 *bitmap1, *bitmap2; Oid element_type; Oid element_type1; Oid element_type2; int32 dataoffset; /* Concatenating a null array is a no-op, just return the other input */ if (PG_ARGISNULL(0)) { if (PG_ARGISNULL(1)) PG_RETURN_NULL(); result = PG_GETARG_ARRAYTYPE_P(1); PG_RETURN_ARRAYTYPE_P(result); } if (PG_ARGISNULL(1)) { result = PG_GETARG_ARRAYTYPE_P(0); PG_RETURN_ARRAYTYPE_P(result); } v1 = PG_GETARG_ARRAYTYPE_P(0); v2 = PG_GETARG_ARRAYTYPE_P(1); element_type1 = ARR_ELEMTYPE(v1); element_type2 = ARR_ELEMTYPE(v2); /* Check we have matching element types */ if (element_type1 != element_type2) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("cannot concatenate incompatible arrays"), errdetail("Arrays with element types %s and %s are not " "compatible for concatenation.", format_type_be(element_type1), format_type_be(element_type2)))); /* OK, use it */ element_type = element_type1; /*---------- * We must have one of the following combinations of inputs: * 1) one empty array, and one non-empty array * 2) both arrays empty * 3) two arrays with ndims1 == ndims2 * 4) ndims1 == ndims2 - 1 * 5) ndims1 == ndims2 + 1 *---------- */ ndims1 = ARR_NDIM(v1); ndims2 = ARR_NDIM(v2); /* * short circuit - if one input array is empty, and the other is not, we * return the non-empty one as the result * * if both are empty, return the first one */ if (ndims1 == 0 && ndims2 > 0) PG_RETURN_ARRAYTYPE_P(v2); if (ndims2 == 0) PG_RETURN_ARRAYTYPE_P(v1); /* the rest fall under rule 3, 4, or 5 */ if (ndims1 != ndims2 && ndims1 != ndims2 - 1 && ndims1 != ndims2 + 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("cannot concatenate incompatible arrays"), errdetail("Arrays of %d and %d dimensions are not " "compatible for concatenation.", ndims1, ndims2))); /* get argument array details */ lbs1 = ARR_LBOUND(v1); lbs2 = ARR_LBOUND(v2); dims1 = ARR_DIMS(v1); dims2 = ARR_DIMS(v2); dat1 = ARR_DATA_PTR(v1); dat2 = ARR_DATA_PTR(v2); bitmap1 = ARR_NULLBITMAP(v1); bitmap2 = ARR_NULLBITMAP(v2); nitems1 = ArrayGetNItems(ndims1, dims1); nitems2 = ArrayGetNItems(ndims2, dims2); ndatabytes1 = ARR_SIZE(v1) - ARR_DATA_OFFSET(v1); ndatabytes2 = ARR_SIZE(v2) - ARR_DATA_OFFSET(v2); if (ndims1 == ndims2) { /* * resulting array is made up of the elements (possibly arrays * themselves) of the input argument arrays */ ndims = ndims1; dims = (int *) palloc(ndims * sizeof(int)); lbs = (int *) palloc(ndims * sizeof(int)); dims[0] = dims1[0] + dims2[0]; lbs[0] = lbs1[0]; for (i = 1; i < ndims; i++) { if (dims1[i] != dims2[i] || lbs1[i] != lbs2[i]) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("cannot concatenate incompatible arrays"), errdetail("Arrays with differing element dimensions are " "not compatible for concatenation."))); dims[i] = dims1[i]; lbs[i] = lbs1[i]; } } else if (ndims1 == ndims2 - 1) { /* * resulting array has the second argument as the outer array, with * the first argument inserted at the front of the outer dimension */ ndims = ndims2; dims = (int *) palloc(ndims * sizeof(int)); lbs = (int *) palloc(ndims * sizeof(int)); memcpy(dims, dims2, ndims * sizeof(int)); memcpy(lbs, lbs2, ndims * sizeof(int)); /* increment number of elements in outer array */ dims[0] += 1; /* make sure the added element matches our existing elements */ for (i = 0; i < ndims1; i++) { if (dims1[i] != dims[i + 1] || lbs1[i] != lbs[i + 1]) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("cannot concatenate incompatible arrays"), errdetail("Arrays with differing dimensions are not " "compatible for concatenation."))); } } else { /* * (ndims1 == ndims2 + 1) * * resulting array has the first argument as the outer array, with the * second argument appended to the end of the outer dimension */ ndims = ndims1; dims = (int *) palloc(ndims * sizeof(int)); lbs = (int *) palloc(ndims * sizeof(int)); memcpy(dims, dims1, ndims * sizeof(int)); memcpy(lbs, lbs1, ndims * sizeof(int)); /* increment number of elements in outer array */ dims[0] += 1; /* make sure the added element matches our existing elements */ for (i = 0; i < ndims2; i++) { if (dims2[i] != dims[i + 1] || lbs2[i] != lbs[i + 1]) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("cannot concatenate incompatible arrays"), errdetail("Arrays with differing dimensions are not " "compatible for concatenation."))); } } /* Do this mainly for overflow checking */ nitems = ArrayGetNItems(ndims, dims); /* build the result array */ ndatabytes = ndatabytes1 + ndatabytes2; if (ARR_HASNULL(v1) || ARR_HASNULL(v2)) { dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems); nbytes = ndatabytes + dataoffset; } else { dataoffset = 0; /* marker for no null bitmap */ nbytes = ndatabytes + ARR_OVERHEAD_NONULLS(ndims); } result = (ArrayType *) palloc(nbytes); SET_VARSIZE(result, nbytes); result->ndim = ndims; result->dataoffset = dataoffset; result->elemtype = element_type; memcpy(ARR_DIMS(result), dims, ndims * sizeof(int)); memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int)); /* data area is arg1 then arg2 */ memcpy(ARR_DATA_PTR(result), dat1, ndatabytes1); memcpy(ARR_DATA_PTR(result) + ndatabytes1, dat2, ndatabytes2); /* handle the null bitmap if needed */ if (ARR_HASNULL(result)) { array_bitmap_copy(ARR_NULLBITMAP(result), 0, bitmap1, 0, nitems1); array_bitmap_copy(ARR_NULLBITMAP(result), nitems1, bitmap2, 0, nitems2); } PG_RETURN_ARRAYTYPE_P(result); }
Datum rewrite_accum(PG_FUNCTION_ARGS) { QUERYTYPE *acc = (QUERYTYPE *) PG_GETARG_POINTER(0); ArrayType *qa = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); QUERYTYPE *q; QTNode *qex, *subs = NULL, *acctree; bool isfind = false; Datum *elemsp; int nelemsp; AggregateContext = ((AggState *) fcinfo->context)->aggcontext; if (acc == NULL || PG_ARGISNULL(0)) { acc = (QUERYTYPE *) MEMALLOC(AggMemory, sizeof(QUERYTYPE)); acc->len = HDRSIZEQT; acc->size = 0; } if (qa == NULL || PG_ARGISNULL(1)) { PG_FREE_IF_COPY(qa, 1); PG_RETURN_POINTER(acc); } if (ARR_NDIM(qa) != 1) elog(ERROR, "array must be one-dimensional, not %d dimension", ARR_NDIM(qa)); if (ArrayGetNItems(ARR_NDIM(qa), ARR_DIMS(qa)) != 3) elog(ERROR, "array should have only three elements"); if (tsqOid == InvalidOid) { SPI_connect(); get_tsq_Oid(); SPI_finish(); } if (ARR_ELEMTYPE(qa) != tsqOid) elog(ERROR, "array should contain tsquery type"); deconstruct_array(qa, tsqOid, -1, false, 'i', &elemsp, NULL, &nelemsp); q = (QUERYTYPE *) DatumGetPointer(elemsp[0]); if (q->size == 0) { pfree(elemsp); PG_RETURN_POINTER(acc); } if (!acc->size) { if (acc->len > HDRSIZEQT) { pfree(elemsp); PG_RETURN_POINTER(acc); } else acctree = QT2QTN(GETQUERY(q), GETOPERAND(q)); } else acctree = QT2QTN(GETQUERY(acc), GETOPERAND(acc)); QTNTernary(acctree); QTNSort(acctree); q = (QUERYTYPE *) DatumGetPointer(elemsp[1]); if (q->size == 0) { pfree(elemsp); PG_RETURN_POINTER(acc); } qex = QT2QTN(GETQUERY(q), GETOPERAND(q)); QTNTernary(qex); QTNSort(qex); q = (QUERYTYPE *) DatumGetPointer(elemsp[2]); if (q->size) subs = QT2QTN(GETQUERY(q), GETOPERAND(q)); acctree = findsubquery(acctree, qex, PlainMemory, subs, &isfind); if (isfind || !acc->size) { /* pfree( acc ); do not pfree(p), because nodeAgg.c will */ if (acctree) { QTNBinary(acctree); acc = QTN2QT(acctree, AggMemory); } else { acc = (QUERYTYPE *) MEMALLOC(AggMemory, HDRSIZEQT * 2); acc->len = HDRSIZEQT * 2; acc->size = 0; } } pfree(elemsp); QTNFree(qex); QTNFree(subs); QTNFree(acctree); PG_RETURN_POINTER(acc); }
Datum internal_kmeans_agg_centroid_trans(PG_FUNCTION_ARGS) { ArrayType *array = NULL; ArrayType *cent_array = NULL; int32 dimension; int32 num_of_centroids; int32 centroid_index; bool rebuild_array = false; int32 expected_array_len; float8 *c_array = NULL; cent_array = PG_GETARG_ARRAYTYPE_P(verify_arg_nonnull(fcinfo, 1)); int array_dim = ARR_NDIM(cent_array); int *p_array_dim = ARR_DIMS(cent_array); int array_length = ArrayGetNItems(array_dim, p_array_dim); float8* c_cent_array = (float8 *)ARR_DATA_PTR(cent_array); dimension = PG_GETARG_INT32(verify_arg_nonnull(fcinfo, 2)); num_of_centroids = PG_GETARG_INT32(verify_arg_nonnull(fcinfo, 3)); centroid_index = PG_GETARG_INT32(verify_arg_nonnull(fcinfo, 4)); expected_array_len = num_of_centroids*dimension; if (dimension < 1) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid dimension:%d", format_procedure(fcinfo->flinfo->fn_oid), dimension))); } if (array_length != dimension) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Inconsistent Dimension. " "Expected:%d, Actual:%d", format_procedure(fcinfo->flinfo->fn_oid), dimension, array_length))); } if (num_of_centroids < 1) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid num_of_centroids:%d", format_procedure(fcinfo->flinfo->fn_oid), num_of_centroids))); } if (centroid_index < 1 || centroid_index>num_of_centroids) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid centroid_index:%d", format_procedure(fcinfo->flinfo->fn_oid), centroid_index))); } if (PG_ARGISNULL(0)) { c_array = palloc0(expected_array_len*sizeof(float8)); rebuild_array = true; } else { if (fcinfo->context && IsA(fcinfo->context, AggState)) array = PG_GETARG_ARRAYTYPE_P(0); else array = PG_GETARG_ARRAYTYPE_P_COPY(0); array_dim = ARR_NDIM(array); p_array_dim = ARR_DIMS(array); array_length = ArrayGetNItems(array_dim, p_array_dim); if (array_length != expected_array_len) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid array length. " "Expected: %d, Actual:%d", format_procedure(fcinfo->flinfo->fn_oid), expected_array_len, array_length))); } c_array = (float8 *)ARR_DATA_PTR(array); } float8 * data_ptr = c_array+(centroid_index-1)*dimension; for(int index=0; index<dimension; index++) { data_ptr[index] = c_cent_array[index]; } if (rebuild_array) { /* construct a new array to keep the aggr states. */ array = construct_array( (Datum *)c_array, expected_array_len, FLOAT8OID, sizeof(float8), true, 'd' ); } PG_RETURN_ARRAYTYPE_P(array); }
Datum internal_kmeans_closest_centroid(PG_FUNCTION_ARGS) { ArrayType *point_array; ArrayType *centroids_array; float8 distance, min_distance = INFINITY; int closest_centroid = 0; int cid; point_array = PG_GETARG_ARRAYTYPE_P(verify_arg_nonnull(fcinfo, 0)); float8* c_point_array = (float8 *)ARR_DATA_PTR(point_array); centroids_array = PG_GETARG_ARRAYTYPE_P(verify_arg_nonnull(fcinfo, 1)); float8* c_centroids_array = (float8 *)ARR_DATA_PTR(centroids_array); int dimension = PG_GETARG_INT32(verify_arg_nonnull(fcinfo, 2)); int num_of_centroids = PG_GETARG_INT32(verify_arg_nonnull(fcinfo, 3)); int centroids_array_len = num_of_centroids*dimension; int dist_metric = PG_GETARG_INT32(verify_arg_nonnull(fcinfo, 4)); ArrayType *canopy_ids_arr = NULL; int4 *canopy_ids = NULL; bool indirect; if (PG_ARGISNULL(5)) { indirect = false; } else { indirect = true; canopy_ids_arr = PG_GETARG_ARRAYTYPE_P(5); /* There should always be a close canopy, but let's be on the safe side. */ if (ARR_NDIM(canopy_ids_arr) == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("internal error: array of close canopies cannot be empty"))); canopy_ids = (int4*) ARR_DATA_PTR(canopy_ids_arr); num_of_centroids = ARR_DIMS(canopy_ids_arr)[0]; } if (dimension < 1) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid dimension:%d", format_procedure(fcinfo->flinfo->fn_oid), dimension))); } if (num_of_centroids < 1) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid num_of_centroids:%d", format_procedure(fcinfo->flinfo->fn_oid), num_of_centroids))); } int array_dim = ARR_NDIM(point_array); int *p_array_dim = ARR_DIMS(point_array); int array_length = ArrayGetNItems(array_dim, p_array_dim); if (array_length != dimension) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid point array length. " "Expected: %d, Actual:%d", format_procedure(fcinfo->flinfo->fn_oid), dimension, array_length))); } array_dim = ARR_NDIM(centroids_array); p_array_dim = ARR_DIMS(centroids_array); array_length = ArrayGetNItems(array_dim, p_array_dim); if (array_length != centroids_array_len) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid centroids array length. " "Expected: %d, Actual:%d", format_procedure(fcinfo->flinfo->fn_oid), centroids_array_len, array_length))); } for (int i = 0; i< num_of_centroids; i++) { cid = indirect ? canopy_ids[i] - ARR_LBOUND(canopy_ids_arr)[0] : i; double * centroid = c_centroids_array+cid*dimension; MetricFunc func = get_metric_fn_for_array(dist_metric); distance = (*func)(centroid, c_point_array, dimension); if (distance < min_distance) { closest_centroid = cid; min_distance = distance; } } PG_RETURN_INT32(closest_centroid+ARR_LBOUND(centroids_array)[0]); }
/* * Turn an array into JSON. */ static void array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds) { ArrayType *v = DatumGetArrayTypeP(array); Oid element_type = ARR_ELEMTYPE(v); int *dim; int ndim; int nitems; int count = 0; Datum *elements; bool *nulls; int16 typlen; bool typbyval; char typalign, typdelim; Oid typioparam; Oid typoutputfunc; TYPCATEGORY tcategory; Oid castfunc = InvalidOid; ndim = ARR_NDIM(v); dim = ARR_DIMS(v); nitems = ArrayGetNItems(ndim, dim); if (nitems <= 0) { appendStringInfoString(result, "[]"); return; } get_type_io_data(element_type, IOFunc_output, &typlen, &typbyval, &typalign, &typdelim, &typioparam, &typoutputfunc); if (element_type > FirstNormalObjectId) { HeapTuple tuple; Form_pg_cast castForm; tuple = SearchSysCache2(CASTSOURCETARGET, ObjectIdGetDatum(element_type), ObjectIdGetDatum(JSONOID)); if (HeapTupleIsValid(tuple)) { castForm = (Form_pg_cast) GETSTRUCT(tuple); if (castForm->castmethod == COERCION_METHOD_FUNCTION) castfunc = typoutputfunc = castForm->castfunc; ReleaseSysCache(tuple); } } deconstruct_array(v, element_type, typlen, typbyval, typalign, &elements, &nulls, &nitems); if (castfunc != InvalidOid) tcategory = TYPCATEGORY_JSON_CAST; else if (element_type == RECORDOID) tcategory = TYPCATEGORY_COMPOSITE; else if (element_type == JSONOID) tcategory = TYPCATEGORY_JSON; else tcategory = TypeCategory(element_type); array_dim_to_json(result, 0, ndim, dim, elements, nulls, &count, tcategory, typoutputfunc, use_line_feeds); pfree(elements); pfree(nulls); }
Datum tsa_rewrite_accum(PG_FUNCTION_ARGS) { TSQuery acc; ArrayType *qa; TSQuery q; QTNode *qex = NULL, *subs = NULL, *acctree = NULL; bool isfind = false; Datum *elemsp; int nelemsp; MemoryContext aggcontext; MemoryContext oldcontext; aggcontext = ((AggState *) fcinfo->context)->aggcontext; if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL) { acc = (TSQuery) MemoryContextAlloc(aggcontext, HDRSIZETQ); SET_VARSIZE(acc, HDRSIZETQ); acc->size = 0; } else acc = PG_GETARG_TSQUERY(0); if (PG_ARGISNULL(1) || PG_GETARG_POINTER(1) == NULL) PG_RETURN_TSQUERY(acc); else qa = PG_GETARG_ARRAYTYPE_P_COPY(1); if (ARR_NDIM(qa) != 1) elog(ERROR, "array must be one-dimensional, not %d dimensions", ARR_NDIM(qa)); if (ArrayGetNItems(ARR_NDIM(qa), ARR_DIMS(qa)) != 3) elog(ERROR, "array must have three elements"); if (ARR_ELEMTYPE(qa) != TSQUERYOID) elog(ERROR, "array must contain tsquery elements"); deconstruct_array(qa, TSQUERYOID, -1, false, 'i', &elemsp, NULL, &nelemsp); q = DatumGetTSQuery(elemsp[0]); if (q->size == 0) { pfree(elemsp); PG_RETURN_POINTER(acc); } if (!acc->size) { if (VARSIZE(acc) > HDRSIZETQ) { pfree(elemsp); PG_RETURN_POINTER(acc); } else acctree = QT2QTN(GETQUERY(q), GETOPERAND(q)); } else acctree = QT2QTN(GETQUERY(acc), GETOPERAND(acc)); QTNTernary(acctree); QTNSort(acctree); q = DatumGetTSQuery(elemsp[1]); if (q->size == 0) { pfree(elemsp); PG_RETURN_POINTER(acc); } qex = QT2QTN(GETQUERY(q), GETOPERAND(q)); QTNTernary(qex); QTNSort(qex); q = DatumGetTSQuery(elemsp[2]); if (q->size) subs = QT2QTN(GETQUERY(q), GETOPERAND(q)); acctree = findsubquery(acctree, qex, subs, &isfind); if (isfind || !acc->size) { /* pfree( acc ); do not pfree(p), because nodeAgg.c will */ if (acctree) { QTNBinary(acctree); oldcontext = MemoryContextSwitchTo(aggcontext); acc = QTN2QT(acctree); MemoryContextSwitchTo(oldcontext); } else { acc = (TSQuery) MemoryContextAlloc(aggcontext, HDRSIZETQ); SET_VARSIZE(acc, HDRSIZETQ); acc->size = 0; } } pfree(elemsp); QTNFree(qex); QTNFree(subs); QTNFree(acctree); PG_RETURN_TSQUERY(acc); }
/* * Common subroutine for num_nulls() and num_nonnulls(). * Returns TRUE if successful, FALSE if function should return NULL. * If successful, total argument count and number of nulls are * returned into *nargs and *nulls. */ static bool count_nulls(FunctionCallInfo fcinfo, int32 *nargs, int32 *nulls) { int32 count = 0; int i; /* Did we get a VARIADIC array argument, or separate arguments? */ if (get_fn_expr_variadic(fcinfo->flinfo)) { ArrayType *arr; int ndims, nitems, *dims; bits8 *bitmap; Assert(PG_NARGS() == 1); /* * If we get a null as VARIADIC array argument, we can't say anything * useful about the number of elements, so return NULL. This behavior * is consistent with other variadic functions - see concat_internal. */ if (PG_ARGISNULL(0)) return false; /* * Non-null argument had better be an array. We assume that any call * context that could let get_fn_expr_variadic return true will have * checked that a VARIADIC-labeled parameter actually is an array. So * it should be okay to just Assert that it's an array rather than * doing a full-fledged error check. */ Assert(OidIsValid(get_base_element_type(get_fn_expr_argtype(fcinfo->flinfo, 0)))); /* OK, safe to fetch the array value */ arr = PG_GETARG_ARRAYTYPE_P(0); /* Count the array elements */ ndims = ARR_NDIM(arr); dims = ARR_DIMS(arr); nitems = ArrayGetNItems(ndims, dims); /* Count those that are NULL */ bitmap = ARR_NULLBITMAP(arr); if (bitmap) { int bitmask = 1; for (i = 0; i < nitems; i++) { if ((*bitmap & bitmask) == 0) count++; bitmask <<= 1; if (bitmask == 0x100) { bitmap++; bitmask = 1; } } } *nargs = nitems; *nulls = count; } else { /* Separate arguments, so just count 'em */ for (i = 0; i < PG_NARGS(); i++) { if (PG_ARGISNULL(i)) count++; } *nargs = PG_NARGS(); *nulls = count; } return true; }