arrayfuncs.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,367 行 · 第 1/5 页
C
2,367 行
/* 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(). * * 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){ 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; typedef struct { ArrayMetaState inp_extra; ArrayMetaState ret_extra; } am_extra; am_extra *my_extra; 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) PG_RETURN_ARRAYTYPE_P(v); /* * 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. */ my_extra = (am_extra *) fcinfo->flinfo->fn_extra; if (my_extra == NULL) { fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(am_extra)); my_extra = (am_extra *) fcinfo->flinfo->fn_extra; inp_extra = &my_extra->inp_extra; inp_extra->element_type = InvalidOid; ret_extra = &my_extra->ret_extra; ret_extra->element_type = InvalidOid; } else { inp_extra = &my_extra->inp_extra; ret_extra = &my_extra->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, lbs, elmtype, elmlen, elmbyval, elmalign);}/*---------- * construct_md_array --- simple method for constructing an array object * with arbitrary dimensions * * elems: array of Datum items to become the array contents * ndims: number of dimensions * dims: integer array with size of each dimension * lbs: integer array with lower bound of each dimension * elmtype, elmlen, elmbyval, elmalign: info for the datatype of the items * * A palloc'd ndims-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_md_array(Datum *elems, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign){ ArrayType *result; int nbytes; int i; int nelems; 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) { /* Allocate and initialize 0-D result array */ nbytes = ARR_OVERHEAD(ndims); result = (ArrayType *) palloc(nbytes); result->size = nbytes; result->ndim = ndims; result->flags = 0; result->elemtype = elmtype; return result; } nelems = ArrayGetNItems(ndims, dims); /* compute required space */ if (elmlen > 0) nbytes = nelems * att_align(elmlen, elmalign); else { Assert(!elmbyval); nbytes = 0; for (i = 0; i < nelems; i++) { /* make sure data is not toasted */ if (elmlen == -1) elems[i] = PointerGetDatum(PG_DETOAST_DATUM(elems[i])); nbytes = att_addlength(nbytes, elmlen, elems[i]); nbytes = att_align(nbytes, elmalign); } } /* Allocate and initialize ndims-D result array */ nbytes += ARR_OVERHEAD(ndims); result = (ArrayType *) palloc(nbytes); result->size = nbytes; result->ndim = ndims; result->flags = 0; result->elemtype = elmtype; memcpy((char *) ARR_DIMS(result), (char *) dims, ndims * sizeof(int)); memcpy((char *) ARR_LBOUND(result), (char *) lbs, ndims * sizeof(int)); CopyArrayEls(ARR_DATA_PTR(result), elems, nelems, elmlen, elmbyval, elmalign, false); return result;}/*---------- * deconstruct_array --- simple method for extracting data from an array * * array: array object to examine (must not be NULL) * elmtype, elmlen, elmbyval, elmalign: info for the datatype of the items * elemsp: return value, set to point to palloc'd array of Datum values * nelemsp: return value, set to number of extracted values * * If array elements are pass-by-ref data type, the returned Datums will * be pointers into the array object. * * NOTE: it would be cleaner to look up the elmlen/elmbval/elmalign info * from the system catalogs, given the elmtype. However, in most current * uses the type is hard-wired into the caller and so we can save a lookup * cycle by hard-wiring the type info as well. *---------- */voiddeconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, int *nelemsp){ Datum *elems; int nelems; char *p; int i; Assert(ARR_ELEMTYPE(array) == elmtype); nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); if (nelems <= 0) { *elemsp = NULL; *nelemsp = 0; return; } *elemsp = elems = (Datum *) palloc(nelems * sizeof(Datum)); *nelemsp = nelems; p = ARR_DATA_PTR(array); for (i = 0; i < nelems; i++) { elems[i] = fetch_att(p, elmbyval, elmlen); p = att_addlength(p, elmlen, PointerGetDatum(p)); p = (char *) att_align(p, elmalign); }}/*----------------------------------------------------------------------------- * array_eq : * compares two arrays for equality * result : * returns true if the arrays are equal, false otherwise. * * Note: we do not use array_cmp here, since equality may be meaningful in * datatypes that don't have a total ordering (and hence no btree support). *----------------------------------------------------------------------------- */Datumarray_eq(PG_FUNCTION_ARGS){ ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0); ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1); char *p1 = (char *) ARR_DATA_PTR(array1); char *p2 = (char *) ARR_DATA_PTR(array2); int ndims1 = ARR_NDIM(array1); int ndims2 = ARR_NDIM(array2); int *dims1 = ARR_DIMS(array1); int *dims2 = ARR_DIMS(array2); int nitems1 = ArrayGetNItems(ndims1, dims1);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?