arrayfuncs.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,484 行 · 第 1/5 页
C
2,484 行
return newarray; } if (nSubscripts <= 0 || nSubscripts > MAXDIM) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts"))); /* make sure item to be inserted is not toasted */ if (elmlen == -1 && !isNull) 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, &isNull, nSubscripts, dim, lb, elmtype, elmlen, elmbyval, elmalign); } if (ndim != nSubscripts) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of 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)); newhasnulls = (ARR_HASNULL(array) || isNull); addedbefore = addedafter = 0; /* * Check subscripts */ if (ndim == 1) { if (indx[0] < lb[0]) { addedbefore = lb[0] - indx[0]; dim[0] += addedbefore; lb[0] = indx[0]; if (addedbefore > 1) newhasnulls = true; /* will insert nulls */ } if (indx[0] >= (dim[0] + lb[0])) { addedafter = indx[0] - (dim[0] + lb[0]) + 1; dim[0] += addedafter; if (addedafter > 1) newhasnulls = true; /* will insert nulls */ } } else { /* * XXX currently we do not support extending multi-dimensional arrays * during assignment */ for (i = 0; i < ndim; i++) { if (indx[i] < lb[i] || indx[i] >= (dim[i] + lb[i])) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array subscript out of range"))); } } /* * Compute sizes of items and areas to copy */ newnitems = ArrayGetNItems(ndim, dim); if (newhasnulls) overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, newnitems); else overheadlen = ARR_OVERHEAD_NONULLS(ndim); oldnitems = ArrayGetNItems(ndim, ARR_DIMS(array)); oldnullbitmap = ARR_NULLBITMAP(array); oldoverheadlen = ARR_DATA_OFFSET(array); olddatasize = ARR_SIZE(array) - oldoverheadlen; if (addedbefore) { offset = 0; lenbefore = 0; olditemlen = 0; lenafter = olddatasize; } else if (addedafter) { offset = oldnitems; lenbefore = olddatasize; olditemlen = 0; lenafter = 0; } else { offset = ArrayGetOffset(nSubscripts, dim, lb, indx); elt_ptr = array_seek(ARR_DATA_PTR(array), 0, oldnullbitmap, offset, elmlen, elmbyval, elmalign); lenbefore = (int) (elt_ptr - ARR_DATA_PTR(array)); if (array_get_isnull(oldnullbitmap, offset)) olditemlen = 0; else { olditemlen = att_addlength_pointer(0, elmlen, elt_ptr); olditemlen = att_align_nominal(olditemlen, elmalign); } lenafter = (int) (olddatasize - lenbefore - olditemlen); } if (isNull) newitemlen = 0; else { newitemlen = att_addlength_datum(0, elmlen, dataValue); newitemlen = att_align_nominal(newitemlen, elmalign); } newsize = overheadlen + lenbefore + newitemlen + lenafter; /* * OK, create the new array and fill in header/dimensions */ newarray = (ArrayType *) palloc(newsize); SET_VARSIZE(newarray, newsize); newarray->ndim = ndim; newarray->dataoffset = newhasnulls ? overheadlen : 0; newarray->elemtype = ARR_ELEMTYPE(array); memcpy(ARR_DIMS(newarray), dim, ndim * sizeof(int)); memcpy(ARR_LBOUND(newarray), lb, ndim * sizeof(int)); /* * Fill in data */ memcpy((char *) newarray + overheadlen, (char *) array + oldoverheadlen, lenbefore); if (!isNull) ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, (char *) newarray + overheadlen + lenbefore); memcpy((char *) newarray + overheadlen + lenbefore + newitemlen, (char *) array + oldoverheadlen + lenbefore + olditemlen, lenafter); /* * Fill in nulls bitmap if needed * * Note: it's possible we just replaced the last NULL with a non-NULL, and * could get rid of the bitmap. Seems not worth testing for though. */ if (newhasnulls) { bits8 *newnullbitmap = ARR_NULLBITMAP(newarray); /* Zero the bitmap to take care of marking inserted positions null */ MemSet(newnullbitmap, 0, (newnitems + 7) / 8); /* Fix the inserted value */ if (addedafter) array_set_isnull(newnullbitmap, newnitems - 1, isNull); else array_set_isnull(newnullbitmap, offset, isNull); /* Fix the copied range(s) */ if (addedbefore) array_bitmap_copy(newnullbitmap, addedbefore, oldnullbitmap, 0, oldnitems); else { array_bitmap_copy(newnullbitmap, 0, oldnullbitmap, 0, offset); if (addedafter == 0) array_bitmap_copy(newnullbitmap, offset + 1, oldnullbitmap, offset + 1, oldnitems - offset - 1); } } return newarray;}/* * array_set_slice : * This routine sets the value of a range of array locations (specified * by upper and lower subscript values) to new values passed as * another array. * * This handles both ordinary varlena arrays and fixed-length arrays. * * Inputs: * array: the initial array object (mustn't be NULL) * nSubscripts: number of subscripts supplied (must be same for upper/lower) * upperIndx[]: the upper subscript values * lowerIndx[]: the lower subscript values * srcArray: the source for the inserted values * isNull: indicates whether srcArray is NULL * arraytyplen: pg_type.typlen for the array type * elmlen: pg_type.typlen for the array's element type * elmbyval: pg_type.typbyval for the array's element type * elmalign: pg_type.typalign for the array's element type * * Result: * A new array is returned, just like the old except for the * modified range. The original array object is not changed. * * For one-dimensional arrays only, we allow the array to be extended * by assigning to positions outside the existing subscript range; any * positions between the existing elements and the new ones are set to NULLs. * (XXX TODO: allow a corresponding behavior for multidimensional arrays) * * 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 or empty array as the fetch operations do. */ArrayType *array_set_slice(ArrayType *array, int nSubscripts, int *upperIndx, int *lowerIndx, ArrayType *srcArray, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign){ ArrayType *newarray; int i, ndim, dim[MAXDIM], lb[MAXDIM], span[MAXDIM]; bool newhasnulls; int nitems, nsrcitems, olddatasize, newsize, olditemsize, newitemsize, overheadlen, oldoverheadlen, addedbefore, addedafter, lenbefore, lenafter, itemsbefore, itemsafter, nolditems; /* Currently, assignment from a NULL source array is a no-op */ if (isNull) return array; if (arraytyplen > 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; bool *dnulls; int nelems; Oid elmtype = ARR_ELEMTYPE(array); deconstruct_array(srcArray, elmtype, elmlen, elmbyval, elmalign, &dvalues, &dnulls, &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, dnulls, nSubscripts, dim, lb, elmtype, elmlen, elmbyval, elmalign); } if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of 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)); newhasnulls = (ARR_HASNULL(array) || ARR_HASNULL(srcArray)); addedbefore = addedafter = 0; /* * Check subscripts */ if (ndim == 1) { Assert(nSubscripts == 1); if (lowerIndx[0] > upperIndx[0]) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("upper bound cannot be less than lower bound"))); if (lowerIndx[0] < lb[0]) { if (upperIndx[0] < lb[0] - 1) newhasnulls = true; /* will insert nulls */ addedbefore = lb[0] - lowerIndx[0]; dim[0] += addedbefore; lb[0] = lowerIndx[0]; } if (upperIndx[0] >= (dim[0] + lb[0])) { if (lowerIndx[0] > (dim[0] + lb[0])) newhasnulls = true; /* will insert nulls */ addedafter = upperIndx[0] - (dim[0] + lb[0]) + 1; dim[0] += addedafter; } } else { /* * XXX currently we do not support extending multi-dimensional arrays * during assignment */ for (i = 0; i < nSubscripts; i++) { if (lowerIndx[i] > upperIndx[i]) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("upper bound cannot be less than lower bound"))); if (lowerIndx[i] < lb[i] || upperIndx[i] >= (dim[i] + lb[i])) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array subscript out of range"))); } /* 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("upper bound cannot be less than lower bound"))); } } /* Do this mainly to check for overflow */ nitems = ArrayGetNItems(ndim, dim); /* * 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. */ if (newhasnulls) overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, nitems); else overheadlen = ARR_OVERHEAD_NONULLS(ndim); newitemsize = array_nelems_size(ARR_DATA_PTR(srcArray), 0, ARR_NULLBITMAP(srcArray), nsrcitems, elmlen, elmbyval, elmalign); oldoverheadlen = ARR_DATA_OFFSET(array); olddatasize = ARR_SIZE(array) - oldoverheadlen; 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(ARR_DATA_PTR(array), ARR_NULLBITMAP(array), ndim, dim, lb, lowerIndx, upperIndx, elmlen, elmbyval, elmalign); lenbefore = lenafter = 0; /* keep compiler quiet */ itemsbefore = itemsafter = nolditems = 0; } 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); bits8 *oldarraybitmap = ARR_NULLBITMAP(array); itemsbefore = Min(slicelb, oldub + 1) - oldlb; lenbefore = array_nelems_size(oldarraydata, 0, oldarraybitmap, itemsbefore, elmlen, elmbyval, elmalign); if (slicelb > sliceub) { nolditems = 0; olditemsize = 0; } else { nolditems = sliceub - slicelb + 1; olditemsize = array_nelems_size(oldarraydata + lenbefore, itemsbefore, oldarraybitmap, nolditems, elmlen, elmbyval, elmalign); } itemsafter = oldub - sliceub; lenafter = olddatasize - lenbefore - olditemsize; } newsize = overheadlen + olddatasize - olditemsize + newitemsize; newarray = (ArrayType *) palloc(newsize); SET_VARSIZE(newarray, newsize); newarray->ndim = ndim; newarray->dataoffset = newhasnulls ? overheadlen : 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(newarray, array, srcArray, ndim, dim, lb, lowerIndx, upperIndx, elmlen, elmbyval, elmalign); } else { /* fill in data */ memcpy((char *) newarray + overheadlen, (char *) array + oldoverheadlen, lenbefore); memcpy((char *) newarray + overheadlen + lenbefore, ARR_DATA_PTR(srcArray), newitemsize); memcpy((char *) newarr
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?