arrayfuncs.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,367 行 · 第 1/5 页
C
2,367 行
* OK, get the element */ offset = ArrayGetOffset(nSubscripts, dim, lb, indx); retptr = array_seek(arraydataptr, offset, elmlen, elmbyval, elmalign); *isNull = false; return ArrayCast(retptr, elmbyval, elmlen);}/*----------------------------------------------------------------------------- * array_get_slice : * This routine takes an array and a range of indices (upperIndex and * lowerIndx), creates a new array structure for the referred elements * and returns a pointer to it. * * NOTE: we assume it is OK to scribble on the provided index arrays * lowerIndx[] and upperIndx[]. These are generally just temporaries. *----------------------------------------------------------------------------- */ArrayType *array_get_slice(ArrayType *array, int nSubscripts, int *upperIndx, int *lowerIndx, int arraylen, int elmlen, bool elmbyval, char elmalign, bool *isNull){ int i, ndim, *dim, *lb, *newlb; int fixedDim[1], fixedLb[1]; char *arraydataptr; ArrayType *newarray; int bytes, span[MAXDIM]; if (array == (ArrayType *) NULL) RETURN_NULL(ArrayType *); if (arraylen > 0) { /* * fixed-length arrays -- currently, cannot slice these because * parser labels output as being of the fixed-length array type! * Code below shows how we could support it if the parser were * changed to label output as a suitable varlena array type. */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("slices of fixed-length arrays not implemented"))); /* * fixed-length arrays -- these are assumed to be 1-d, 0-based XXX * where would we get the correct ELEMTYPE from? */ ndim = 1; fixedDim[0] = arraylen / elmlen; fixedLb[0] = 0; dim = fixedDim; lb = fixedLb; arraydataptr = (char *) array; } else { /* detoast input array if necessary */ array = DatumGetArrayTypeP(PointerGetDatum(array)); ndim = ARR_NDIM(array); dim = ARR_DIMS(array); lb = ARR_LBOUND(array); arraydataptr = ARR_DATA_PTR(array); } /* * Check provided subscripts. A slice exceeding the current array * limits is silently truncated to the array limits. If we end up * with an empty slice, return NULL (should it be an empty array * instead?) */ if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM) RETURN_NULL(ArrayType *); for (i = 0; i < nSubscripts; i++) { if (lowerIndx[i] < lb[i]) lowerIndx[i] = lb[i]; if (upperIndx[i] >= (dim[i] + lb[i])) upperIndx[i] = dim[i] + lb[i] - 1; if (lowerIndx[i] > upperIndx[i]) RETURN_NULL(ArrayType *); } /* 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]) RETURN_NULL(ArrayType *); } mda_get_range(ndim, span, lowerIndx, upperIndx); bytes = array_slice_size(ndim, dim, lb, arraydataptr, lowerIndx, upperIndx, elmlen, elmbyval, elmalign); bytes += ARR_OVERHEAD(ndim); newarray = (ArrayType *) palloc(bytes); newarray->size = bytes; newarray->ndim = ndim; newarray->flags = 0; newarray->elemtype = ARR_ELEMTYPE(array); memcpy(ARR_DIMS(newarray), span, ndim * sizeof(int)); /* * Lower bounds of the new array are set to 1. Formerly (before 7.3) * we copied the given lowerIndx values ... but that seems confusing. */ newlb = ARR_LBOUND(newarray); for (i = 0; i < ndim; i++) newlb[i] = 1; array_extract_slice(ndim, dim, lb, arraydataptr, lowerIndx, upperIndx, ARR_DATA_PTR(newarray), elmlen, elmbyval, elmalign); return newarray;}/*----------------------------------------------------------------------------- * array_set : * This routine sets the value of an array location (specified by * an index array) to a new value specified by "dataValue". * result : * A new array is returned, just like the old except for the one * modified entry. * * For one-dimensional arrays only, we allow the array to be extended * by assigning to the position one above or one below the existing range. * (We could be more flexible if we had a way to represent NULL elements.) * * NOTE: For assignments, we throw an error for invalid 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(ArrayType *array, int nSubscripts, int *indx, Datum dataValue, int arraylen, int elmlen, bool elmbyval, char elmalign, bool *isNull){ int i, ndim, dim[MAXDIM], lb[MAXDIM], offset; ArrayType *newarray; char *elt_ptr; bool extendbefore = false; bool extendafter = false; int olddatasize, newsize, olditemlen, newitemlen, overheadlen, lenbefore, lenafter; if (array == (ArrayType *) NULL) RETURN_NULL(ArrayType *); if (arraylen > 0) { /* * fixed-length arrays -- these are assumed to be 1-d, 0-based. We * cannot extend them, either. */ if (nSubscripts != 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("invalid array subscripts"))); if (indx[0] < 0 || indx[0] * elmlen >= arraylen) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("invalid array subscripts"))); newarray = (ArrayType *) palloc(arraylen); memcpy(newarray, array, arraylen); elt_ptr = (char *) newarray + indx[0] * elmlen; ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, elt_ptr); return newarray; } /* make sure item to be inserted is not toasted */ if (elmlen == -1) dataValue = PointerGetDatum(PG_DETOAST_DATUM(dataValue)); /* detoast input array if necessary */ array = DatumGetArrayTypeP(PointerGetDatum(array)); ndim = ARR_NDIM(array); /* * if number of dims is zero, i.e. an empty array, create an array * with nSubscripts dimensions, and set the lower bounds to the * supplied subscripts */ if (ndim == 0) { Oid elmtype = ARR_ELEMTYPE(array); for (i = 0; i < nSubscripts; i++) { dim[i] = 1; lb[i] = indx[i]; } return construct_md_array(&dataValue, 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 subscripts */ for (i = 0; i < ndim; i++) { if (indx[i] < lb[i]) { if (ndim == 1 && indx[i] == lb[i] - 1) { dim[i]++; lb[i]--; extendbefore = true; } else ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("invalid array subscripts"))); } if (indx[i] >= (dim[i] + lb[i])) { if (ndim == 1 && indx[i] == (dim[i] + lb[i])) { dim[i]++; extendafter = true; } else ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("invalid array subscripts"))); } } /* * Compute sizes of items and areas to copy */ overheadlen = ARR_OVERHEAD(ndim); olddatasize = ARR_SIZE(array) - overheadlen; if (extendbefore) { lenbefore = 0; olditemlen = 0; lenafter = olddatasize; } else if (extendafter) { lenbefore = olddatasize; olditemlen = 0; lenafter = 0; } else { offset = ArrayGetOffset(nSubscripts, dim, lb, indx); elt_ptr = array_seek(ARR_DATA_PTR(array), offset, 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 == (ArrayType *) NULL) RETURN_NULL(ArrayType *); if (srcArray == (ArrayType *) 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"))); } }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?