📄 arrayfuncs.c
字号:
elmlen, elmbyval, elmalign); lenbefore = (int) (elt_ptr - ARR_DATA_PTR(array)); olditemlen = att_addlength(0, elmlen, PointerGetDatum(elt_ptr)); olditemlen = att_align(olditemlen, elmalign); lenafter = (int) (olddatasize - lenbefore - olditemlen); } newitemlen = att_addlength(0, elmlen, dataValue); newitemlen = att_align(newitemlen, elmalign); newsize = overheadlen + lenbefore + newitemlen + lenafter; /* * OK, do the assignment */ newarray = (ArrayType *) palloc(newsize); newarray->size = newsize; newarray->ndim = ndim; newarray->flags = 0; newarray->elemtype = ARR_ELEMTYPE(array); memcpy(ARR_DIMS(newarray), dim, ndim * sizeof(int)); memcpy(ARR_LBOUND(newarray), lb, ndim * sizeof(int)); memcpy((char *) newarray + overheadlen, (char *) array + overheadlen, lenbefore); memcpy((char *) newarray + overheadlen + lenbefore + newitemlen, (char *) array + overheadlen + lenbefore + olditemlen, lenafter); ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, (char *) newarray + overheadlen + lenbefore); return newarray;}/*---------------------------------------------------------------------------- * array_set_slice : * This routine sets the value of a range of array locations (specified * by upper and lower index values ) to new values passed as * another array * result : * A new array is returned, just like the old except for the * modified range. * * NOTE: we assume it is OK to scribble on the provided index arrays * lowerIndx[] and upperIndx[]. These are generally just temporaries. * * NOTE: For assignments, we throw an error for silly subscripts etc, * rather than returning a NULL as the fetch operations do. The reasoning * is that returning a NULL would cause the user's whole array to be replaced * with NULL, which will probably not make him happy. *---------------------------------------------------------------------------- */ArrayType *array_set_slice(ArrayType *array, int nSubscripts, int *upperIndx, int *lowerIndx, ArrayType *srcArray, int arraylen, int elmlen, bool elmbyval, char elmalign, bool *isNull){ int i, ndim, dim[MAXDIM], lb[MAXDIM], span[MAXDIM]; ArrayType *newarray; int nsrcitems, olddatasize, newsize, olditemsize, newitemsize, overheadlen, lenbefore, lenafter; if (array == NULL) RETURN_NULL(ArrayType *); if (srcArray == NULL) return array; if (arraylen > 0) { /* * fixed-length arrays -- not got round to doing this... */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("updates on slices of fixed-length arrays not implemented"))); } /* detoast arrays if necessary */ array = DatumGetArrayTypeP(PointerGetDatum(array)); srcArray = DatumGetArrayTypeP(PointerGetDatum(srcArray)); /* note: we assume srcArray contains no toasted elements */ ndim = ARR_NDIM(array); /* * if number of dims is zero, i.e. an empty array, create an array with * nSubscripts dimensions, and set the upper and lower bounds to the * supplied subscripts */ if (ndim == 0) { Datum *dvalues; int nelems; Oid elmtype = ARR_ELEMTYPE(array); deconstruct_array(srcArray, elmtype, elmlen, elmbyval, elmalign, &dvalues, &nelems); for (i = 0; i < nSubscripts; i++) { dim[i] = 1 + upperIndx[i] - lowerIndx[i]; lb[i] = lowerIndx[i]; } /* complain if too few source items; we ignore extras, however */ if (nelems < ArrayGetNItems(nSubscripts, dim)) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("source array too small"))); return construct_md_array(dvalues, nSubscripts, dim, lb, elmtype, elmlen, elmbyval, elmalign); } if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("invalid array subscripts"))); /* copy dim/lb since we may modify them */ memcpy(dim, ARR_DIMS(array), ndim * sizeof(int)); memcpy(lb, ARR_LBOUND(array), ndim * sizeof(int)); /* * Check provided subscripts. A slice exceeding the current array limits * throws an error, *except* in the 1-D case where we will extend the * array as long as no hole is created. An empty slice is an error, too. */ for (i = 0; i < nSubscripts; i++) { if (lowerIndx[i] > upperIndx[i]) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("invalid array subscripts"))); if (lowerIndx[i] < lb[i]) { if (ndim == 1 && upperIndx[i] >= lb[i] - 1) { dim[i] += lb[i] - lowerIndx[i]; lb[i] = lowerIndx[i]; } else ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("invalid array subscripts"))); } if (upperIndx[i] >= (dim[i] + lb[i])) { if (ndim == 1 && lowerIndx[i] <= (dim[i] + lb[i])) dim[i] = upperIndx[i] - lb[i] + 1; else ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("invalid array subscripts"))); } } /* fill any missing subscript positions with full array range */ for (; i < ndim; i++) { lowerIndx[i] = lb[i]; upperIndx[i] = dim[i] + lb[i] - 1; if (lowerIndx[i] > upperIndx[i]) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("invalid array subscripts"))); } /* * Make sure source array has enough entries. Note we ignore the shape of * the source array and just read entries serially. */ mda_get_range(ndim, span, lowerIndx, upperIndx); nsrcitems = ArrayGetNItems(ndim, span); if (nsrcitems > ArrayGetNItems(ARR_NDIM(srcArray), ARR_DIMS(srcArray))) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("source array too small"))); /* * Compute space occupied by new entries, space occupied by replaced * entries, and required space for new array. */ newitemsize = array_nelems_size(ARR_DATA_PTR(srcArray), nsrcitems, elmlen, elmbyval, elmalign); overheadlen = ARR_OVERHEAD(ndim); olddatasize = ARR_SIZE(array) - overheadlen; if (ndim > 1) { /* * here we do not need to cope with extension of the array; it would * be a lot more complicated if we had to do so... */ olditemsize = array_slice_size(ndim, dim, lb, ARR_DATA_PTR(array), lowerIndx, upperIndx, elmlen, elmbyval, elmalign); lenbefore = lenafter = 0; /* keep compiler quiet */ } else { /* * here we must allow for possibility of slice larger than orig array */ int oldlb = ARR_LBOUND(array)[0]; int oldub = oldlb + ARR_DIMS(array)[0] - 1; int slicelb = Max(oldlb, lowerIndx[0]); int sliceub = Min(oldub, upperIndx[0]); char *oldarraydata = ARR_DATA_PTR(array); lenbefore = array_nelems_size(oldarraydata, slicelb - oldlb, elmlen, elmbyval, elmalign); if (slicelb > sliceub) olditemsize = 0; else olditemsize = array_nelems_size(oldarraydata + lenbefore, sliceub - slicelb + 1, elmlen, elmbyval, elmalign); lenafter = olddatasize - lenbefore - olditemsize; } newsize = overheadlen + olddatasize - olditemsize + newitemsize; newarray = (ArrayType *) palloc(newsize); newarray->size = newsize; newarray->ndim = ndim; newarray->flags = 0; newarray->elemtype = ARR_ELEMTYPE(array); memcpy(ARR_DIMS(newarray), dim, ndim * sizeof(int)); memcpy(ARR_LBOUND(newarray), lb, ndim * sizeof(int)); if (ndim > 1) { /* * here we do not need to cope with extension of the array; it would * be a lot more complicated if we had to do so... */ array_insert_slice(ndim, dim, lb, ARR_DATA_PTR(array), olddatasize, ARR_DATA_PTR(newarray), lowerIndx, upperIndx, ARR_DATA_PTR(srcArray), elmlen, elmbyval, elmalign); } else { memcpy((char *) newarray + overheadlen, (char *) array + overheadlen, lenbefore); memcpy((char *) newarray + overheadlen + lenbefore, ARR_DATA_PTR(srcArray), newitemsize); memcpy((char *) newarray + overheadlen + lenbefore + newitemsize, (char *) array + overheadlen + lenbefore + olditemsize, lenafter); } return newarray;}/* * array_map() * * Map an array through an arbitrary function. Return a new array with * same dimensions and each source element transformed by fn(). Each * source element is passed as the first argument to fn(); additional * arguments to be passed to fn() can be specified by the caller. * The output array can have a different element type than the input. * * Parameters are: * * fcinfo: a function-call data structure pre-constructed by the caller * to be ready to call the desired function, with everything except the * first argument position filled in. In particular, flinfo identifies * the function fn(), and if nargs > 1 then argument positions after the * first must be preset to the additional values to be passed. The * first argument position initially holds the input array value. * * inpType: OID of element type of input array. This must be the same as, * or binary-compatible with, the first argument type of fn(). * * retType: OID of element type of output array. This must be the same as, * or binary-compatible with, the result type of fn(). * * amstate: workspace for array_map. Must be zeroed by caller before * first call, and not touched after that. * * It is legitimate to pass a freshly-zeroed ArrayMapState on each call, * but better performance can be had if the state can be preserved across * a series of calls. * * NB: caller must assure that input array is not NULL. Currently, * any additional parameters passed to fn() may not be specified as NULL * either. */Datumarray_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType, ArrayMapState *amstate){ ArrayType *v; ArrayType *result; Datum *values; Datum elt; int *dim; int ndim; int nitems; int i; int nbytes = 0; int inp_typlen; bool inp_typbyval; char inp_typalign; int typlen; bool typbyval; char typalign; char *s; ArrayMetaState *inp_extra; ArrayMetaState *ret_extra; /* Get input array */ if (fcinfo->nargs < 1) elog(ERROR, "invalid nargs: %d", fcinfo->nargs); if (PG_ARGISNULL(0)) elog(ERROR, "null input array"); v = PG_GETARG_ARRAYTYPE_P(0); Assert(ARR_ELEMTYPE(v) == inpType); ndim = ARR_NDIM(v); dim = ARR_DIMS(v); nitems = ArrayGetNItems(ndim, dim); /* Check for empty array */ if (nitems <= 0) { /* Return empty array */ result = (ArrayType *) palloc0(sizeof(ArrayType)); result->size = sizeof(ArrayType); result->elemtype = retType; PG_RETURN_ARRAYTYPE_P(result); } /* * We arrange to look up info about input and return element types only * once per series of calls, assuming the element type doesn't change * underneath us. */ inp_extra = &amstate->inp_extra; ret_extra = &amstate->ret_extra; if (inp_extra->element_type != inpType) { get_typlenbyvalalign(inpType, &inp_extra->typlen, &inp_extra->typbyval, &inp_extra->typalign); inp_extra->element_type = inpType; } inp_typlen = inp_extra->typlen; inp_typbyval = inp_extra->typbyval; inp_typalign = inp_extra->typalign; if (ret_extra->element_type != retType) { get_typlenbyvalalign(retType, &ret_extra->typlen, &ret_extra->typbyval, &ret_extra->typalign); ret_extra->element_type = retType; } typlen = ret_extra->typlen; typbyval = ret_extra->typbyval; typalign = ret_extra->typalign; /* Allocate temporary array for new values */ values = (Datum *) palloc(nitems * sizeof(Datum)); /* Loop over source data */ s = (char *) ARR_DATA_PTR(v); for (i = 0; i < nitems; i++) { /* Get source element */ elt = fetch_att(s, inp_typbyval, inp_typlen); s = att_addlength(s, inp_typlen, PointerGetDatum(s)); s = (char *) att_align(s, inp_typalign); /* * Apply the given function to source elt and extra args. * * We assume the extra args are non-NULL, so need not check whether * fn() is strict. Would need to do more work here to support arrays * containing nulls, too. */ fcinfo->arg[0] = elt; fcinfo->argnull[0] = false; fcinfo->isnull = false; values[i] = FunctionCallInvoke(fcinfo); if (fcinfo->isnull) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("null array elements not supported"))); /* Ensure data is not toasted */ if (typlen == -1) values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i])); /* Update total result size */ nbytes = att_addlength(nbytes, typlen, values[i]); nbytes = att_align(nbytes, typalign); } /* Allocate and initialize the result array */ nbytes += ARR_OVERHEAD(ndim); result = (ArrayType *) palloc0(nbytes); result->size = nbytes; result->ndim = ndim; result->elemtype = retType; memcpy(ARR_DIMS(result), ARR_DIMS(v), 2 * ndim * sizeof(int)); /* * Note: do not risk trying to pfree the results of the called function */ CopyArrayEls(ARR_DATA_PTR(result), values, nitems, typlen, typbyval, typalign, false); pfree(values); PG_RETURN_ARRAYTYPE_P(result);}/*---------- * construct_array --- simple method for constructing an array object * * elems: array of Datum items to become the array contents * nelems: number of items * elmtype, elmlen, elmbyval, elmalign: info for the datatype of the items * * A palloc'd 1-D array object is constructed and returned. Note that * elem values will be copied into the object even if pass-by-ref type. * NULL element values are not supported. * * NOTE: it would be cleaner to look up the elmlen/elmbval/elmalign info * from the system catalogs, given the elmtype. However, the caller is * in a better position to cache this info across multiple uses, or even * to hard-wire values if the element type is hard-wired. *---------- */ArrayType *construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign){ int dims[1]; int lbs[1]; dims[0] = nelems; lbs[0] = 1; return construct_md_array(elems, 1, dims, lb
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -