/* * 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); }
Datum svec_cast_float8arr(PG_FUNCTION_ARGS) { ArrayType *A_PG = PG_GETARG_ARRAYTYPE_P(0); SvecType *output_svec; if (ARR_ELEMTYPE(A_PG) != FLOAT8OID) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("svec_cast_float8arr only defined over float8[]"))); if (ARR_NDIM(A_PG) != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("svec_cast_float8arr only defined over 1 dimensional arrays")) ); if (ARR_NULLBITMAP(A_PG)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("svec_cast_float8arr does not allow null bitmaps on arrays")) ); /* Extract array */ { int dimension = ARR_DIMS(A_PG)[0]; float8 *array = (float8 *)ARR_DATA_PTR(A_PG); /* Create the output SVEC */ SparseData sdata = float8arr_to_sdata(array,dimension); output_svec = svec_from_sparsedata(sdata,true); } PG_RETURN_SVECTYPE_P(output_svec); }
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 _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; }
/* * 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 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; }
/* * Check that a valid state is passed to the aggregate's final function. * If we return false, the calling function should return NULL. */ static bool float8_mregr_get_state(FunctionCallInfo fcinfo, MRegrState *outState) { ArrayType *in; float8 *data; /* Input should be a single parameter, the aggregate state */ if (PG_NARGS() != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("final calculation function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)))); if (PG_ARGISNULL(0)) return false; /* Validate array type */ in = PG_GETARG_ARRAYTYPE_P(0); if (ARR_ELEMTYPE(in) != FLOAT8OID || ARR_NDIM(in) != 1 || ARR_NULLBITMAP(in)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("final calculation function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)))); /* Validate the correct size input */ if (ARR_DIMS(in)[0] < 2) return false; /* no input */ data = (float8*) ARR_DATA_PTR(in); outState->len = (int) data[0]; /* scalar: len(X[]) */ if ((uint64) ARR_DIMS(in)[0] != 4ULL + outState->len + outState->len * outState->len) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("final calculation function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)))); outState->count = data[1]; /* scalar: count(*) */ outState->sumy = data[2]; /* scalar: sum(y) */ outState->sumy2 = data[3]; /* scalar: sum(y*y) */ outState->Xty = &data[4]; /* vector: X^t * y */ outState->XtX = &data[4 + outState->len]; /* matrix: X^t * X */ return true; }
/* * Convert a SQL array to a Python list. */ static PyObject * PLyList_FromArray(PLyDatumToOb *arg, Datum d) { ArrayType *array = DatumGetArrayTypeP(d); PLyDatumToOb *elm = arg->u.array.elm; int ndim; int *dims; char *dataptr; bits8 *bitmap; int bitmask; if (ARR_NDIM(array) == 0) return PyList_New(0); /* Array dimensions and left bounds */ ndim = ARR_NDIM(array); dims = ARR_DIMS(array); Assert(ndim < MAXDIM); /* * We iterate the SQL array in the physical order it's stored in the * datum. For example, for a 3-dimensional array the order of iteration * would be the following: [0,0,0] elements through [0,0,k], then [0,1,0] * through [0,1,k] till [0,m,k], then [1,0,0] through [1,0,k] till * [1,m,k], and so on. * * In Python, there are no multi-dimensional lists as such, but they are * represented as a list of lists. So a 3-d array of [n,m,k] elements is a * list of n m-element arrays, each element of which is k-element array. * PLyList_FromArray_recurse() builds the Python list for a single * dimension, and recurses for the next inner dimension. */ dataptr = ARR_DATA_PTR(array); bitmap = ARR_NULLBITMAP(array); bitmask = 1; return PLyList_FromArray_recurse(elm, dims, ndim, 0, &dataptr, &bitmap, &bitmask); }
bool array_next(array_iter *iter, Datum *value, bool *isna) { bits8 *nulls; if (iter->index >= iter->max) { *value = (Datum) 0; *isna = true; return false; } if (iter->index < 0) { *value = (Datum) 0; *isna = true; iter->index++; return true; } nulls = ARR_NULLBITMAP(iter->array); if (nulls && !(nulls[iter->index / 8] & (1 << (iter->index % 8)))) { *value = (Datum) 0; *isna = true; iter->index++; return true; } *isna = false; if (iter->typlen > 0) { /* fixed length */ if (iter->typlen <= 8) { switch (iter->typlen) { case 1: *value = Int8GetDatum(*((int8*) iter->ptr)); break; case 2: *value = Int16GetDatum(*((int16*) iter->ptr)); break; case 4: *value = Int32GetDatum(*((int16*) iter->ptr)); break; case 8: *value = Int64GetDatum(*((int16*) iter->ptr)); break; default: elog(ERROR, "unexpected data type"); break; } } else { *value = PointerGetDatum(iter->ptr); } iter->ptr += iter->typlen; } else { /* variable length */ *value = PointerGetDatum(iter->ptr); iter->ptr += VARSIZE(iter->ptr); } iter->ptr = (char*) att_align(iter->ptr, iter->typalign); iter->index++; return true; }
static PCPATCH * pcpatch_from_point_array(ArrayType *array, FunctionCallInfoData *fcinfo) { int nelems; bits8 *bitmap; int bitmask; size_t offset = 0; int i; uint32 pcid = 0; PCPATCH *pa; PCPOINTLIST *pl; PCSCHEMA *schema = 0; /* How many things in our array? */ nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); /* PgSQL supplies a bitmap of which array entries are null */ bitmap = ARR_NULLBITMAP(array); /* Empty array? Null return */ if ( nelems == 0 ) return NULL; /* Make our holder */ pl = pc_pointlist_make(nelems); offset = 0; bitmap = ARR_NULLBITMAP(array); bitmask = 1; for ( i = 0; i < nelems; i++ ) { /* Only work on non-NULL entries in the array */ if ( ! array_get_isnull(bitmap, i) ) { SERIALIZED_POINT *serpt = (SERIALIZED_POINT *)(ARR_DATA_PTR(array)+offset); PCPOINT *pt; if ( ! schema ) { schema = pc_schema_from_pcid(serpt->pcid, fcinfo); } if ( ! pcid ) { pcid = serpt->pcid; } else if ( pcid != serpt->pcid ) { elog(ERROR, "pcpatch_from_point_array: pcid mismatch (%d != %d)", serpt->pcid, pcid); } pt = pc_point_deserialize(serpt, schema); if ( ! pt ) { elog(ERROR, "pcpatch_from_point_array: point deserialization failed"); } pc_pointlist_add_point(pl, pt); offset += INTALIGN(VARSIZE(serpt)); } } if ( pl->npoints == 0 ) return NULL; pa = pc_patch_from_pointlist(pl); pc_pointlist_free(pl); return pa; }
/* * 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; }
Datum serialize_array(PG_FUNCTION_ARGS) { ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); Oid element_type = ARR_ELEMTYPE(v); int16 typlen; bool typbyval; char typalign; char typdelim; char *p, *value; char type_category; bool needComma = false; bits8 *bitmap; int bitmask; int nitems, i; int ndim, *dims; Oid typioparam, typiofunc; HeapTuple type_tuple; FmgrInfo proc, flinfo; StringInfoData buf; // FILE* log; // log = fopen("/var/lib/postgresql/serializer.log", "a"); // fprintf(log, "Doing serialize_array\n"); // fflush(log); /* * Get info about element type, including its output conversion proc */ get_type_io_data(element_type, IOFunc_output, &typlen, &typbyval, &typalign, &typdelim, &typioparam, &typiofunc); fmgr_info_cxt( typiofunc, &proc, fcinfo->flinfo->fn_mcxt ); ndim = ARR_NDIM(v); dims = ARR_DIMS(v); nitems = ArrayGetNItems(ndim, dims); if( ndim > 1 ) elog( ERROR, "multidimensional arrays doesn't supported" ); p = ARR_DATA_PTR(v); bitmap = ARR_NULLBITMAP(v); bitmask = 1; /* obtain type information from pg_catalog */ type_tuple = SearchSysCache1( TYPEOID, ObjectIdGetDatum(element_type) ); if (!HeapTupleIsValid( type_tuple )) elog(ERROR, "cache lookup failed for relation %u", element_type); type_category = ((Form_pg_type) GETSTRUCT( type_tuple ))->typcategory; ReleaseSysCache( type_tuple ); /* Build the result string */ initStringInfo(&buf); appendStringInfoChar(&buf, '['); for (i = 0; i < nitems; i++) { if (needComma) appendStringInfoChar(&buf, ','); needComma = true; /* Get source element, checking for NULL */ if (bitmap && (*bitmap & bitmask) == 0) { // append null appendStringInfoString(&buf, "null"); } else { /* get item value and advance array data pointer */ Datum itemvalue = fetch_att(p, typbyval, typlen); p = att_addlength_pointer(p, typlen, p); p = (char *) att_align_nominal(p, typalign); //------------------------ switch( type_category ) { // http://www.postgresql.org/docs/current/static/catalog-pg-type.html#CATALOG-TYPCATEGORY-TABLE case 'A': //array - impossible case break; case 'C': //composite //call to serialize_record( ... ) MemSet( &flinfo, 0, sizeof( flinfo ) ); flinfo.fn_addr = serialize_record; flinfo.fn_nargs = 1; flinfo.fn_mcxt = fcinfo->flinfo->fn_mcxt; value = PG_TEXT_DATUM_GET_CSTR( FunctionCall1( &flinfo, itemvalue ) ); appendStringInfoString(&buf, value); break; case 'N': //numeric // get column text value value = OutputFunctionCall( &proc, itemvalue ); appendStringInfoString(&buf, value); break; default: //another // get column text value value = OutputFunctionCall( &proc, itemvalue ); appendStringInfoQuotedString(&buf, value); } } /* advance bitmap pointer if any */ if (bitmap) { bitmask <<= 1; if (bitmask == 0x100) { bitmap++; bitmask = 1; } } } appendStringInfoChar(&buf, ']'); // fclose(log); //PG_RETURN_CSTRING(retval); PG_RETURN_TEXT_P( PG_CSTR_GET_TEXT( buf.data ) ); }
Datum count_distinct_elements_append(PG_FUNCTION_ARGS) { int i; element_set_t *eset = NULL; /* info for anyarray */ Oid input_type; Oid element_type; /* array data */ ArrayType *input; int ndims; int *dims; int nitems; bits8 *null_bitmap; char *arr_ptr; Datum element; /* memory contexts */ MemoryContext oldcontext; MemoryContext aggcontext; /* * If the new value is NULL, we simply return the current aggregate state * (it might be NULL, so check it). In this case we don't really care about * the types etc. * * We may still get NULL elements in the array, but to check that we would * have to walk the array, which does not qualify as cheap check. Also we * assume that there's at least one non-NULL element, and we'll walk the * array just once. It's possible we'll get empty set this way. */ if (PG_ARGISNULL(1) && PG_ARGISNULL(0)) PG_RETURN_NULL(); else if (PG_ARGISNULL(1)) PG_RETURN_DATUM(PG_GETARG_DATUM(0)); /* from now on we know the new value is not NULL */ /* get the type of array elements */ input_type = get_fn_expr_argtype(fcinfo->flinfo, 1); element_type = get_element_type(input_type); /* * parse the array contents (we know we got non-NULL value) */ input = PG_GETARG_ARRAYTYPE_P(1); ndims = ARR_NDIM(input); dims = ARR_DIMS(input); nitems = ArrayGetNItems(ndims, dims); null_bitmap = ARR_NULLBITMAP(input); arr_ptr = ARR_DATA_PTR(input); /* make sure we're running as part of aggregate function */ GET_AGG_CONTEXT("count_distinct_elements_append", fcinfo, aggcontext); oldcontext = MemoryContextSwitchTo(aggcontext); /* add all array elements to the set */ for (i = 0; i < nitems; i++) { /* ignore nulls */ if (null_bitmap && !(null_bitmap[i / 8] & (1 << (i % 8)))) continue; /* init the hash table, if needed */ if (eset == NULL) { if (PG_ARGISNULL(0)) { int16 typlen; bool typbyval; char typalign; /* get type information for the second parameter (anyelement item) */ get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign); /* we can't handle varlena types yet or values passed by reference */ if ((typlen < 0) || (! typbyval)) elog(ERROR, "count_distinct_elements handles only arrays of fixed-length types passed by value"); eset = init_set(typlen, typalign, aggcontext); } else eset = (element_set_t *)PG_GETARG_POINTER(0); } element = fetch_att(arr_ptr, true, eset->item_size); add_element(eset, (char*)&element); /* advance array pointer */ arr_ptr = att_addlength_pointer(arr_ptr, eset->item_size, arr_ptr); arr_ptr = (char *) att_align_nominal(arr_ptr, eset->typalign); } MemoryContextSwitchTo(oldcontext); if (eset == NULL) PG_RETURN_NULL(); else PG_RETURN_POINTER(eset); }
Datum pseudoinverse(PG_FUNCTION_ARGS) { /* * A note on types: PostgreSQL array dimensions are of type int. See, e.g., * the macro definition ARR_DIMS */ int rows, columns; float8 *A, *Aplus; ArrayType *A_PG, *Aplus_PG; int lbs[2], dims[2]; /* * Perform all the error checking needed to ensure that no one is * trying to call this in some sort of crazy way. */ if (PG_NARGS() != 1) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("pseudoinverse called with %d arguments", PG_NARGS()))); } if (PG_ARGISNULL(0)) PG_RETURN_NULL(); A_PG = PG_GETARG_ARRAYTYPE_P(0); if (ARR_ELEMTYPE(A_PG) != FLOAT8OID) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("pseudoinverse only defined over float8[]"))); if (ARR_NDIM(A_PG) != 2) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("pseudoinverse only defined over 2 dimensional arrays")) ); if (ARR_NULLBITMAP(A_PG)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("null array element not allowed in this context"))); /* Extract rows, columns, and data */ rows = ARR_DIMS(A_PG)[0]; columns = ARR_DIMS(A_PG)[1]; A = (float8 *) ARR_DATA_PTR(A_PG); /* Allocate a PG array for the result, "Aplus" is A+, the pseudo inverse of A */ lbs[0] = 1; lbs[1] = 1; dims[0] = columns; dims[1] = rows; Aplus_PG = construct_md_array(NULL, NULL, 2, dims, lbs, FLOAT8OID, sizeof(float8), true, 'd'); Aplus = (float8 *) ARR_DATA_PTR(Aplus_PG); pinv(rows,columns,A,Aplus); PG_RETURN_ARRAYTYPE_P(Aplus_PG); }
static bool float8_mregr_accum_get_args(FunctionCallInfo fcinfo, MRegrAccumArgs *outArgs) { float8 *stateData; uint32 len, i; uint64 statelen; /* We should be strict, but it doesn't hurt to be paranoid */ if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2)) return false; outArgs->stateAsArray = PG_GETARG_ARRAYTYPE_P(0); outArgs->newY = PG_GETARG_FLOAT8(1); outArgs->newXAsArray = PG_GETARG_ARRAYTYPE_P(2); outArgs->newX = (float8*) ARR_DATA_PTR(outArgs->newXAsArray); /* Ensure that both arrays are single dimensional float8[] arrays */ if (ARR_NULLBITMAP(outArgs->stateAsArray) || ARR_NDIM(outArgs->stateAsArray) != 1 || ARR_ELEMTYPE(outArgs->stateAsArray) != FLOAT8OID || ARR_NDIM(outArgs->newXAsArray) != 1 || ARR_ELEMTYPE(outArgs->newXAsArray) != FLOAT8OID) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("transition function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)))); /* Only callable as a transition function */ if (!(fcinfo->context && IsA(fcinfo->context, AggState))) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("transition function \"%s\" not called from aggregate", format_procedure(fcinfo->flinfo->fn_oid)))); /* newXAsArray with nulls will be ignored */ if (ARR_NULLBITMAP(outArgs->newXAsArray)) return false; /* See MPP-14102. Avoid overflow while initializing len */ if (ARR_DIMS(outArgs->newXAsArray)[0] > UINT32_MAX) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("number of independent variables cannot exceed %lu", (unsigned long) UINT32_MAX))); len = ARR_DIMS(outArgs->newXAsArray)[0]; /* * See MPP-13580. At least on certain platforms and with certain versions, * LAPACK will run into an infinite loop if pinv() is called for non-finite * matrices. We extend the check also to the dependent variables. */ for (i = 0; i < len; i++) if (!isfinite(outArgs->newX[i])) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("design matrix is not finite"))); if (!isfinite(outArgs->newY)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("dependent variables are not finite"))); /* * See MPP-14102. We want to avoid (a) long int overflows and (b) making * oversized allocation requests. * We could compute the maximum number of variables so that the transition- * state length still fits into MaxAllocSize, but (assuming MaxAllocSize may * change in the future) this calculation requires taking the root out of a * 64-bit long int. Since there is no standard library function for that, and * displaying this number of merely of theoretical interest (the actual * limit is a lot lower), we simply report that the number of independent * variables is too large. * Precondition: * len < 2^32. */ statelen = STATE_LEN(len); if (!IS_FEASIBLE_STATE_LEN(statelen)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("number of independent variables is too large"))); /* * If length(outArgs->stateAsArray) == 1 then it is an unitialized state. * We extend as needed. */ if (ARR_DIMS(outArgs->stateAsArray)[0] == 1) { /* * Precondition: * IS_FEASIBLE_STATE_LEN(statelen) */ Size size = statelen * sizeof(float8) + ARR_OVERHEAD_NONULLS(1); outArgs->stateAsArray = (ArrayType *) palloc(size); SET_VARSIZE(outArgs->stateAsArray, size); outArgs->stateAsArray->ndim = 1; outArgs->stateAsArray->dataoffset = 0; outArgs->stateAsArray->elemtype = FLOAT8OID; ARR_DIMS(outArgs->stateAsArray)[0] = statelen; ARR_LBOUND(outArgs->stateAsArray)[0] = 1; stateData = (float8*) ARR_DATA_PTR(outArgs->stateAsArray); memset(stateData, 0, statelen * sizeof(float8)); stateData[0] = len; } /* * Contents of 'state' are as follows: * [0] = len(X[]) * [1] = count * [2] = sum(y) * [3] = sum(y*y) * [4:N] = sum(X'[] * y) * [N+1:M] = sum(X[] * X'[]) * N = 3 + len(X) * M = N + len(X)*len(X) */ outArgs->len = (float8*) ARR_DATA_PTR(outArgs->stateAsArray); outArgs->count = outArgs->len + 1; outArgs->sumy = outArgs->len + 2; outArgs->sumy2 = outArgs->len + 3; outArgs->Xty = outArgs->len + 4; outArgs->XtX = outArgs->len + 4 + len; /* It is an error if the number of indepent variables is not constant */ if (*outArgs->len != len) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("transition function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)), errdetail("The independent-variable array is not of constant width."))); } /* Something is seriously fishy if our state has the wrong length */ if ((uint64) ARR_DIMS(outArgs->stateAsArray)[0] != statelen) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("transition function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)))); } /* Okay... All's good now do the work */ return true; }
/* * Preliminary segment-level calculation function for multi-linear regression * aggregates. */ Datum float8_mregr_combine(PG_FUNCTION_ARGS) { ArrayType *state1, *state2, *result; float8 *state1Data, *state2Data, *resultData; uint32 len; uint64 statelen, i; Size size; /* We should be strict, but it doesn't hurt to be paranoid */ if (PG_ARGISNULL(0)) { if (PG_ARGISNULL(1)) PG_RETURN_NULL(); PG_RETURN_ARRAYTYPE_P(PG_GETARG_ARRAYTYPE_P(1)); } if (PG_ARGISNULL(1)) PG_RETURN_ARRAYTYPE_P(PG_GETARG_ARRAYTYPE_P(0)); state1 = PG_GETARG_ARRAYTYPE_P(0); state2 = PG_GETARG_ARRAYTYPE_P(1); /* Ensure that both arrays are single dimensional float8[] arrays */ if (ARR_NULLBITMAP(state1) || ARR_NULLBITMAP(state2) || ARR_NDIM(state1) != 1 || ARR_NDIM(state2) != 1 || ARR_ELEMTYPE(state1) != FLOAT8OID || ARR_ELEMTYPE(state2) != FLOAT8OID) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("preliminary segment-level calculation function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)))); } /* * Remember that we initialized to {0}, so if either array is still at * the initial value then just return the other one */ if (ARR_DIMS(state1)[0] == 1) PG_RETURN_ARRAYTYPE_P(state2); if (ARR_DIMS(state2)[0] == 1) PG_RETURN_ARRAYTYPE_P(state1); state1Data = (float8*) ARR_DATA_PTR(state1); state2Data = (float8*) ARR_DATA_PTR(state2); if (ARR_DIMS(state1)[0] != ARR_DIMS(state2)[0] || state1Data[0] != state2Data[0]) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("preliminary segment-level calculation function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)), errdetail("The independent-variable array is not of constant width."))); } len = state1Data[0]; statelen = STATE_LEN(len); /* * Violation of any of the following conditions indicates bogus inputs. */ if (state1Data[0] > UINT32_MAX || (uint64) ARR_DIMS(state1)[0] != statelen || !IS_FEASIBLE_STATE_LEN(statelen)) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("preliminary segment-level calculation function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)))); } /* Validations pass, allocate memory for result and do work */ /* * Precondition: * IS_FEASIBLE_STATE_LEN(statelen) */ size = statelen * sizeof(float8) + ARR_OVERHEAD_NONULLS(1); result = (ArrayType *) palloc(size); SET_VARSIZE(result, size); result->ndim = 1; result->dataoffset = 0; result->elemtype = FLOAT8OID; ARR_DIMS(result)[0] = statelen; ARR_LBOUND(result)[0] = 1; resultData = (float8*) ARR_DATA_PTR(result); memset(resultData, 0, statelen * sizeof(float8)); /* * Contents of 'state' are as follows: * [0] = len(X[]) * [1] = count * [2] = sum(y) * [3] = sum(y*y) * [4:N] = sum(X'[] * y) * [N+1:M] = sum(X[] * X'[]) * N = 3 + len(X) * M = N + len(X)*len(X) */ resultData[0] = len; for (i = 1; i < statelen; i++) resultData[i] = state1Data[i] + state2Data[i]; PG_RETURN_ARRAYTYPE_P(result); }
Datum sampleNewTopics(PG_FUNCTION_ARGS) { int32 i, widx, wtopic, rtopic; ArrayType * doc_arr = PG_GETARG_ARRAYTYPE_P(0); ArrayType * topics_arr = PG_GETARG_ARRAYTYPE_P(1); ArrayType * topic_d_arr = PG_GETARG_ARRAYTYPE_P(2); ArrayType * global_count_arr = PG_GETARG_ARRAYTYPE_P(3); ArrayType * topic_counts_arr = PG_GETARG_ARRAYTYPE_P(4); int32 num_topics = PG_GETARG_INT32(5); int32 dsize = PG_GETARG_INT32(6); float8 alpha = PG_GETARG_FLOAT8(7); float8 eta = PG_GETARG_FLOAT8(8); if (ARR_NULLBITMAP(doc_arr) || ARR_NDIM(doc_arr) != 1 || ARR_ELEMTYPE(doc_arr) != INT4OID || ARR_NDIM(topics_arr) != 1 || ARR_ELEMTYPE(topics_arr) != INT4OID || ARR_NULLBITMAP(topic_d_arr) || ARR_NDIM(topic_d_arr) != 1 || ARR_ELEMTYPE(topic_d_arr) != INT4OID || ARR_NULLBITMAP(global_count_arr) || ARR_NDIM(global_count_arr) != 1 || ARR_ELEMTYPE(global_count_arr) != INT4OID || ARR_NULLBITMAP(topic_counts_arr) || ARR_NDIM(topic_counts_arr) != 1 || ARR_ELEMTYPE(topic_counts_arr) != INT4OID) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)))); // the document array int32 * doc = (int32 *)ARR_DATA_PTR(doc_arr); int32 len = ARR_DIMS(doc_arr)[0]; // array giving topic assignment to each word in document int32 * topics = (int32 *)ARR_DATA_PTR(topics_arr); // distribution of topics in document int32 * topic_d = (int32 *)ARR_DATA_PTR(topic_d_arr); // the word-topic count matrix int32 * global_count = (int32 *)ARR_DATA_PTR(global_count_arr); // total number of words assigned to each topic in the whole corpus int32 * topic_counts = (int32 *)ARR_DATA_PTR(topic_counts_arr); ArrayType * ret_topics_arr, * ret_topic_d_arr; int32 * ret_topics, * ret_topic_d; Datum * arr1 = palloc0(len * sizeof(Datum)); ret_topics_arr = construct_array(arr1,len,INT4OID,4,true,'i'); ret_topics = (int32 *)ARR_DATA_PTR(ret_topics_arr); Datum * arr2 = palloc0(num_topics * sizeof(Datum)); ret_topic_d_arr = construct_array(arr2,num_topics,INT4OID,4,true,'i'); ret_topic_d = (int32 *)ARR_DATA_PTR(ret_topic_d_arr); for (i=0; i!=len; i++) { widx = doc[i]; if (widx < 1 || widx > dsize) ereport (ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)))); wtopic = topics[i]; rtopic = sampleTopic(num_topics,widx,wtopic,global_count, topic_d,topic_counts,alpha,eta); // <sampleNewTopics error checking> ret_topics[i] = rtopic; ret_topic_d[rtopic-1]++; } Datum values[2]; values[0] = PointerGetDatum(ret_topics_arr); values[1] = PointerGetDatum(ret_topic_d_arr); TupleDesc tuple; if (get_call_result_type(fcinfo, NULL, &tuple) != TYPEFUNC_COMPOSITE) ereport(ERROR, (errcode( ERRCODE_FEATURE_NOT_SUPPORTED ), errmsg( "function returning record called in context " "that cannot accept type record" ))); tuple = BlessTupleDesc(tuple); bool * isnulls = palloc0(2 * sizeof(bool)); HeapTuple ret = heap_form_tuple(tuple, values, isnulls); if (isnulls[0] || isnulls[1]) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\" produced null results", format_procedure(fcinfo->flinfo->fn_oid),i))); PG_RETURN_DATUM(HeapTupleGetDatum(ret)); }
SvecType * svec_in_internal(char * str) { char *values; ArrayType *pgarray_vals,*pgarray_ix; double *vals, *vals_temp; StringInfo index; int64 *u_index; int32_t num_values,total_value_count; SparseData sdata; SvecType *result; bits8 *bitmap; int bitmask; int i,j; /* Read in the two arrays defining the Sparse Vector, first is the array * of run lengths (the count array), the second is an array of the * unique values (the data array). * * The input format is a pair of standard Postgres arrays separated by * a colon, like this: * {1,10,1,5,1}:{4.3,0,0.2,0,7.4} * * For now, the data array must only have float8 elements. */ if ((values=strchr(str,':')) == NULL) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Invalid input string for svec"))); } else { *values = '\0'; values = values+1; } /* Get the count and data arrays */ pgarray_ix = DatumGetArrayTypeP( OidFunctionCall3(F_ARRAY_IN,CStringGetDatum(str), ObjectIdGetDatum(INT8OID),Int32GetDatum(-1))); pgarray_vals = DatumGetArrayTypeP( OidFunctionCall3(F_ARRAY_IN,CStringGetDatum(values), ObjectIdGetDatum(FLOAT8OID),Int32GetDatum(-1))); num_values = *(ARR_DIMS(pgarray_ix)); u_index = (int64 *)ARR_DATA_PTR(pgarray_ix); vals = (double *)ARR_DATA_PTR(pgarray_vals); /* The count and value arrays must be non-empty */ int size1 = ARR_NDIM(pgarray_ix); int size2 = ARR_NDIM(pgarray_vals); if (size1 == 0 || size2 == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("The count and value arrays must be non-empty"))); /* The count and value arrays must have the same dimension */ if (num_values != *(ARR_DIMS(pgarray_vals))) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Unique value count not equal to run length count %d != %d", num_values, *(ARR_DIMS(pgarray_vals))))); /* Count array cannot have NULLs */ if (ARR_HASNULL(pgarray_ix)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("NULL value in the count array."))); /* If the data array has NULLs, then we need to create an array to * store the NULL values as NVP values defined in float_specials.h. */ if (ARR_HASNULL(pgarray_vals)) { vals_temp = vals; vals = (double *)palloc(sizeof(float8) * num_values); bitmap = ARR_NULLBITMAP(pgarray_vals); bitmask = 1; j = 0; for (i=0; i<num_values; i++) { if (bitmap && (*bitmap & bitmask) == 0) // if NULL vals[i] = NVP; else { vals[i] = vals_temp[j]; j++; } if (bitmap) { // advance bitmap pointer bitmask <<= 1; if (bitmask == 0x100) { bitmap++; bitmask = 1; } } } } /* Make an empty StringInfo because we have the data array already */ index = makeStringInfo(); total_value_count = 0; for (int i=0;i<num_values;i++) { if (u_index[i] <= 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Non-positive run length in input"))); total_value_count+=u_index[i]; append_to_rle_index(index,u_index[i]); } sdata = makeInplaceSparseData((char *)vals,index->data, num_values*sizeof(double),index->len,FLOAT8OID, num_values,total_value_count); sdata->type_of_data = FLOAT8OID; result = svec_from_sparsedata(sdata,true); if (total_value_count == 1) result->dimension = -1; //Scalar if (ARR_HASNULL(pgarray_vals)) pfree(vals); pfree(str); /* str is allocated from a strdup */ pfree(pgarray_ix); pfree(pgarray_vals); return result; }
Datum alpine_miner_lr_combine(PG_FUNCTION_ARGS) { ArrayType *state1, *state2, *result; float8 *state1Data, *state2Data, *resultData; int i, size; int statelen; if (PG_ARGISNULL(0)) { if (PG_ARGISNULL(1)) PG_RETURN_NULL(); PG_RETURN_ARRAYTYPE_P(PG_GETARG_ARRAYTYPE_P(1)); } if (PG_ARGISNULL(1)) PG_RETURN_ARRAYTYPE_P(PG_GETARG_ARRAYTYPE_P(0)); state1 = PG_GETARG_ARRAYTYPE_P(0); state2 = PG_GETARG_ARRAYTYPE_P(1); if (ARR_NULLBITMAP(state1) || ARR_NULLBITMAP(state2) || ARR_NDIM(state1) != 1 || ARR_NDIM(state2) != 1 || ARR_ELEMTYPE(state1) != FLOAT8OID || ARR_ELEMTYPE(state2) != FLOAT8OID) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("preliminary segment-level calculation function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)))); } if (ARR_DIMS(state1)[0] == 1) PG_RETURN_ARRAYTYPE_P(state2); if (ARR_DIMS(state2)[0] == 1) PG_RETURN_ARRAYTYPE_P(state1); state1Data = (float8*) ARR_DATA_PTR(state1); state2Data = (float8*) ARR_DATA_PTR(state2); if (ARR_DIMS(state1)[0] != ARR_DIMS(state2)[0]) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("preliminary segment-level calculation function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)), errdetail("The independent-variable array is not of constant width."))); } statelen = ARR_DIMS(state1)[0]; size = statelen * sizeof(float8) + ARR_OVERHEAD_NONULLS(1); result = (ArrayType *) palloc(size); SET_VARSIZE(result, size); result->ndim = 1; result->dataoffset = 0; result->elemtype = FLOAT8OID; ARR_DIMS(result)[0] = statelen; ARR_LBOUND(result)[0] = 1; resultData = (float8*) ARR_DATA_PTR(result); memset(resultData, 0, statelen * sizeof(float8)); for (i = 0; i < statelen; i++){ resultData[i] = state1Data[i] + state2Data[i]; } PG_RETURN_ARRAYTYPE_P(result); }
static bool alpine_miner_float8_mregr_accum_get_state(PG_FUNCTION_ARGS, MRegrAccumState *outState) { float8 *stateData; int len, statelen; /* We should be strict, but it doesn't hurt to be paranoid */ if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2)) return false; outState->stateAsArray = PG_GETARG_ARRAYTYPE_P(0); outState->newX = PG_GETARG_ARRAYTYPE_P(2); /* Ensure that both arrays are single dimensional float8[] arrays */ if (ARR_NULLBITMAP(outState->stateAsArray) || ARR_NDIM(outState->stateAsArray) != 1 || ARR_ELEMTYPE(outState->stateAsArray) != FLOAT8OID || ARR_NDIM(outState->newX) != 1 || ARR_ELEMTYPE(outState->newX) != FLOAT8OID) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("transition function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)))); /* Only callable as a transition function */ if (!(fcinfo->context && IsA(fcinfo->context, AggState))) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("transition function \"%s\" not called from aggregate", format_procedure(fcinfo->flinfo->fn_oid)))); /* newX with nulls will be ignored */ if (ARR_NULLBITMAP(outState->newX)) return false; /* * If length(state) == 1 then it is an unitialized state, extend as * needed, we use this instead of NULL so that we can declare the * function as strict. */ len = ARR_DIMS(outState->newX)[0]; statelen = 1 + (3*len + len*len)/2; if (ARR_DIMS(outState->stateAsArray)[0] == 1) { int size = statelen * sizeof(float8) + ARR_OVERHEAD_NONULLS(1); outState->stateAsArray = (ArrayType *) palloc(size); SET_VARSIZE(outState->stateAsArray, size); outState->stateAsArray->ndim = 1; outState->stateAsArray->dataoffset = 0; outState->stateAsArray->elemtype = FLOAT8OID; ARR_DIMS(outState->stateAsArray)[0] = statelen; ARR_LBOUND(outState->stateAsArray)[0] = 1; stateData = (float8*) ARR_DATA_PTR(outState->stateAsArray); memset(stateData, 0, statelen * sizeof(float8)); stateData[0] = len; } /* * Contents of 'state' are as follows: * [0] = len(X[]) * [1] = count * [2] = sum(y) * [3] = sum(y*y) * [4:N] = sum(X'[] * y) * [N+1:M] = sum(X[] * X'[]) * N = 3 + len(X) * M = N + len(X)*len(X) */ outState->len = (float8*) ARR_DATA_PTR(outState->stateAsArray); outState->Xty = outState->len + 1; outState->XtX = outState->len + 1 + len; outState->newXData = (float8*) ARR_DATA_PTR(outState->newX); /* It is an error if the number of indepent variables is not constant */ if (*outState->len != len) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("transition function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)), errdetail("The independent-variable array is not of constant width."))); } /* Something is seriously fishy if our state has the wrong length */ if (ARR_DIMS(outState->stateAsArray)[0] != statelen) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("transition function \"%s\" called with invalid parameters", format_procedure(fcinfo->flinfo->fn_oid)))); } /* Okay... All's good now do the work */ return true; }
Datum hvault_table_count_step(PG_FUNCTION_ARGS) { MemoryContext aggmemctx, oldmemctx; ArrayType * ctx; ArrayType * idx_array; int i, pos_idx; int32_t * ctx_data; if (!AggCheckCallContext(fcinfo, &aggmemctx)) elog(ERROR, "hvault_table_group_step called in non-aggregate context"); ctx = PG_ARGISNULL(0) ? NULL : PG_GETARG_ARRAYTYPE_P(0); if (ctx == NULL) { int ndim; int32_t * bounds_data; int dims[MAXDIM]; int lbs[MAXDIM]; ArrayType * bounds_array; oldmemctx = MemoryContextSwitchTo(aggmemctx); if (PG_ARGISNULL(2)) elog(ERROR, "bounds array must not be null"); // if (!get_fn_expr_arg_stable(fcinfo->flinfo, 2)) // elog(ERROR, "bounds array must be const"); bounds_array = PG_GETARG_ARRAYTYPE_P(2); Assert(bounds_array != NULL); Assert(bounds_array->elemtype == INT4OID); if (bounds_array->ndim != 2 || ARR_DIMS(bounds_array)[1] != 2) elog(ERROR, "bounds array size is invalid"); if (ARR_HASNULL(bounds_array)) { int size = ARR_DIMS(bounds_array)[0] * ARR_DIMS(bounds_array)[1]; for (i = 0; i < (size + 7) / 8; i++) if (ARR_NULLBITMAP(bounds_array)[i] != 0) elog(ERROR, "bounds array must not contain NULLs"); } ndim = ARR_DIMS(bounds_array)[0]; if (ndim > MAXDIM) elog(ERROR, "too many dimensions, max supported is %d", MAXDIM); bounds_data = (int32_t *) ARR_DATA_PTR(bounds_array); for (i = 0; i < ndim; i++) { int ubs; lbs[i] = bounds_data[2*i]; ubs = bounds_data[2*i+1]; dims[i] = ubs - lbs[i]; } ctx = intArrayInit(ndim, dims, lbs); MemoryContextSwitchTo(oldmemctx); } Assert(!ARR_HASNULL(ctx)); Assert(ctx->elemtype == INT4OID); if (PG_ARGISNULL(1)) elog(ERROR, "group index array must not be null"); idx_array = PG_GETARG_ARRAYTYPE_P(1); Assert(idx_array != NULL); Assert(idx_array->elemtype == INT4OID); if (idx_array->ndim != 1) elog(ERROR, "group index array must have single dimension"); if (ARR_DIMS(idx_array)[0] != ctx->ndim) elog(ERROR, "group index array length is inconsistent"); if (ARR_HASNULL(idx_array)) { int size = ARR_DIMS(idx_array)[0]; for (i = 0; i < (size + 7) / 8; i++) /* Skip elements with nulls */ if (ARR_NULLBITMAP(idx_array)[i] != 0) { elog(WARNING, "index array contains NULL, skipping"); PG_RETURN_ARRAYTYPE_P(ctx); } } pos_idx = intArrayIdx(ctx, (int *) ARR_DATA_PTR(idx_array), true); if (pos_idx != -1) { Assert(pos_idx >= 0); if (ARR_SIZE(ctx) - ARR_DATA_OFFSET(ctx) <= pos_idx * 4) { elog(ERROR, "Array out of bounds access: %ld %d", ARR_SIZE(ctx) - ARR_DATA_OFFSET(ctx), pos_idx * 4); } ctx_data = (int32_t *) ARR_DATA_PTR(ctx); ctx_data[pos_idx]++; } PG_RETURN_ARRAYTYPE_P(ctx); }
static PCPATCH * pcpatch_from_patch_array(ArrayType *array, FunctionCallInfoData *fcinfo) { int nelems; bits8 *bitmap; int bitmask; size_t offset = 0; int i; uint32 pcid = 0; PCPATCH *pa; PCPATCH **palist; int numpatches = 0; PCSCHEMA *schema = 0; /* How many things in our array? */ nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); /* PgSQL supplies a bitmap of which array entries are null */ bitmap = ARR_NULLBITMAP(array); /* Empty array? Null return */ if ( nelems == 0 ) return NULL; /* Make our temporary list of patches */ palist = pcalloc(nelems*sizeof(PCPATCH*)); /* Read the patches out of the array and deserialize */ offset = 0; bitmap = ARR_NULLBITMAP(array); bitmask = 1; for ( i = 0; i < nelems; i++ ) { /* Only work on non-NULL entries in the array */ if ( ! array_get_isnull(bitmap, i) ) { SERIALIZED_PATCH *serpatch = (SERIALIZED_PATCH *)(ARR_DATA_PTR(array)+offset); if ( ! schema ) { schema = pc_schema_from_pcid(serpatch->pcid, fcinfo); } if ( ! pcid ) { pcid = serpatch->pcid; } else if ( pcid != serpatch->pcid ) { elog(ERROR, "pcpatch_from_patch_array: pcid mismatch (%d != %d)", serpatch->pcid, pcid); } pa = pc_patch_deserialize(serpatch, schema); if ( ! pa ) { elog(ERROR, "pcpatch_from_patch_array: patch deserialization failed"); } palist[numpatches++] = pa; offset += INTALIGN(VARSIZE(serpatch)); } } /* Can't do anything w/ NULL */ if ( numpatches == 0 ) return NULL; /* Pass to the lib to build the output patch from the list */ pa = pc_patch_from_patchlist(palist, numpatches); /* Free the temporary patch list */ for ( i = 0; i < numpatches; i++ ) { pc_patch_free(palist[i]); } pcfree(palist); return pa; }
/*----------------------------------------------------------------------------- * 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); }
static text* plvsubst_string(text *template_in, ArrayType *vals_in, text *c_subst, FunctionCallInfo fcinfo) { ArrayType *v = vals_in; int nitems, *dims, ndims; char *p; int16 typlen; bool typbyval; char typalign; char typdelim; Oid typelem; Oid typiofunc; FmgrInfo proc; int i = 0, items = 0; StringInfo sinfo; const char *template_str; int template_len; char *sizes; int *positions; int subst_mb_len; int subst_len; const bits8 *bitmap; int bitmask; if (v != NULL && (ndims = ARR_NDIM(v)) > 0) { if (ndims != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid parameter"), errdetail("Array of arguments has wrong dimension: %d", ndims))); p = ARR_DATA_PTR(v); dims = ARR_DIMS(v); nitems = ArrayGetNItems(ndims, dims); bitmap = ARR_NULLBITMAP(v); get_type_io_data(ARR_ELEMTYPE(v), IOFunc_output, &typlen, &typbyval, &typalign, &typdelim, &typelem, &typiofunc); fmgr_info_cxt(typiofunc, &proc, fcinfo->flinfo->fn_mcxt); } else { nitems = 0; p = NULL; bitmap = NULL; } template_str = VARDATA(template_in); template_len = ora_mb_strlen(template_in, &sizes, &positions); subst_mb_len = ora_mb_strlen1(c_subst); subst_len = VARSIZE_ANY_EXHDR(c_subst); sinfo = makeStringInfo(); bitmask = 1; for (i = 0; i < template_len; i++) { if (strncmp(&template_str[positions[i]], VARDATA(c_subst), subst_len) == 0) { Datum itemvalue; char *value; if (items++ < nitems) { if (bitmap && (*bitmap & bitmask) == 0) value = pstrdup("NULL"); else { itemvalue = fetch_att(p, typbyval, typlen); value = DatumGetCString(FunctionCall3(&proc, itemvalue, ObjectIdGetDatum(typelem), Int32GetDatum(-1))); p = att_addlength_pointer(p, typlen, p); p = (char *) att_align_nominal(p, typalign); } appendStringInfoString(sinfo, value); pfree(value); if (bitmap) { bitmask <<= 1; if (bitmask == 0x100) { bitmap++; bitmask = 1; } } } else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("too few parameters specified for template string"))); i += subst_mb_len - 1; } else appendBinaryStringInfo(sinfo, &template_str[positions[i]], sizes[i]); } return cstring_to_text(sinfo->data); }