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 + -
显示快捷键?