arrayfuncs.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,484 行 · 第 1/5 页

C
2,484
字号
	bitmap = ARR_NULLBITMAP(v);	bitmask = 1;	for (i = 0; i < nitems; i++)	{		/* Get source element, checking for NULL */		if (bitmap && (*bitmap & bitmask) == 0)		{			/* -1 length means a NULL */			pq_sendint(&buf, -1, 4);		}		else		{			Datum		itemvalue;			bytea	   *outputbytes;			itemvalue = fetch_att(p, typbyval, typlen);			outputbytes = SendFunctionCall(&my_extra->proc, itemvalue);			pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);			pq_sendbytes(&buf, VARDATA(outputbytes),						 VARSIZE(outputbytes) - VARHDRSZ);			pfree(outputbytes);			p = att_addlength_pointer(p, typlen, p);			p = (char *) att_align_nominal(p, typalign);		}		/* advance bitmap pointer if any */		if (bitmap)		{			bitmask <<= 1;			if (bitmask == 0x100)			{				bitmap++;				bitmask = 1;			}		}	}	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}/* * array_dims : *		  returns the dimensions of the array pointed to by "v", as a "text" */Datumarray_dims(PG_FUNCTION_ARGS){	ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);	text	   *result;	char	   *p;	int			nbytes,				i;	int		   *dimv,			   *lb;	/* Sanity check: does it look like an array at all? */	if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)		PG_RETURN_NULL();	nbytes = ARR_NDIM(v) * 33 + 1;	/*	 * 33 since we assume 15 digits per number + ':' +'[]'	 *	 * +1 allows for temp trailing null	 */	result = (text *) palloc(nbytes + VARHDRSZ);	p = VARDATA(result);	dimv = ARR_DIMS(v);	lb = ARR_LBOUND(v);	for (i = 0; i < ARR_NDIM(v); i++)	{		sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);		p += strlen(p);	}	SET_VARSIZE(result, strlen(VARDATA(result)) + VARHDRSZ);	PG_RETURN_TEXT_P(result);}/* * array_lower : *		returns the lower dimension, of the DIM requested, for *		the array pointed to by "v", as an int4 */Datumarray_lower(PG_FUNCTION_ARGS){	ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);	int			reqdim = PG_GETARG_INT32(1);	int		   *lb;	int			result;	/* Sanity check: does it look like an array at all? */	if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)		PG_RETURN_NULL();	/* Sanity check: was the requested dim valid */	if (reqdim <= 0 || reqdim > ARR_NDIM(v))		PG_RETURN_NULL();	lb = ARR_LBOUND(v);	result = lb[reqdim - 1];	PG_RETURN_INT32(result);}/* * array_upper : *		returns the upper dimension, of the DIM requested, for *		the array pointed to by "v", as an int4 */Datumarray_upper(PG_FUNCTION_ARGS){	ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);	int			reqdim = PG_GETARG_INT32(1);	int		   *dimv,			   *lb;	int			result;	/* Sanity check: does it look like an array at all? */	if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)		PG_RETURN_NULL();	/* Sanity check: was the requested dim valid */	if (reqdim <= 0 || reqdim > ARR_NDIM(v))		PG_RETURN_NULL();	lb = ARR_LBOUND(v);	dimv = ARR_DIMS(v);	result = dimv[reqdim - 1] + lb[reqdim - 1] - 1;	PG_RETURN_INT32(result);}/* * array_ref : *	  This routine takes an array pointer and a subscript array and returns *	  the referenced item as a Datum.  Note that for a pass-by-reference *	  datatype, the returned Datum is a pointer into the array object. * * This handles both ordinary varlena arrays and fixed-length arrays. * * Inputs: *	array: the array object (mustn't be NULL) *	nSubscripts: number of subscripts supplied *	indx[]: the subscript values *	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 * * Outputs: *	The return value is the element Datum. *	*isNull is set to indicate whether the element is NULL. */Datumarray_ref(ArrayType *array,		  int nSubscripts,		  int *indx,		  int arraytyplen,		  int elmlen,		  bool elmbyval,		  char elmalign,		  bool *isNull){	int			i,				ndim,			   *dim,			   *lb,				offset,				fixedDim[1],				fixedLb[1];	char	   *arraydataptr,			   *retptr;	bits8	   *arraynullsptr;	if (arraytyplen > 0)	{		/*		 * fixed-length arrays -- these are assumed to be 1-d, 0-based		 */		ndim = 1;		fixedDim[0] = arraytyplen / elmlen;		fixedLb[0] = 0;		dim = fixedDim;		lb = fixedLb;		arraydataptr = (char *) array;		arraynullsptr = NULL;	}	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);		arraynullsptr = ARR_NULLBITMAP(array);	}	/*	 * Return NULL for invalid subscript	 */	if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM)	{		*isNull = true;		return (Datum) 0;	}	for (i = 0; i < ndim; i++)	{		if (indx[i] < lb[i] || indx[i] >= (dim[i] + lb[i]))		{			*isNull = true;			return (Datum) 0;		}	}	/*	 * Calculate the element number	 */	offset = ArrayGetOffset(nSubscripts, dim, lb, indx);	/*	 * Check for NULL array element	 */	if (array_get_isnull(arraynullsptr, offset))	{		*isNull = true;		return (Datum) 0;	}	/*	 * OK, get the element	 */	*isNull = false;	retptr = array_seek(arraydataptr, 0, arraynullsptr, offset,						elmlen, elmbyval, elmalign);	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. * * This handles both ordinary varlena arrays and fixed-length arrays. * * Inputs: *	array: the 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 *	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 * * Outputs: *	The return value is the new array Datum (it's never NULL) * * NOTE: we assume it is OK to scribble on the provided subscript arrays * lowerIndx[] and upperIndx[].  These are generally just temporaries. */ArrayType *array_get_slice(ArrayType *array,				int nSubscripts,				int *upperIndx,				int *lowerIndx,				int arraytyplen,				int elmlen,				bool elmbyval,				char elmalign){	ArrayType  *newarray;	int			i,				ndim,			   *dim,			   *lb,			   *newlb;	int			fixedDim[1],				fixedLb[1];	Oid			elemtype;	char	   *arraydataptr;	bits8	   *arraynullsptr;	int32		dataoffset;	int			bytes,				span[MAXDIM];	if (arraytyplen > 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] = arraytyplen / elmlen;		fixedLb[0] = 0;		dim = fixedDim;		lb = fixedLb;		elemtype = InvalidOid;	/* XXX */		arraydataptr = (char *) array;		arraynullsptr = NULL;	}	else	{		/* detoast input array if necessary */		array = DatumGetArrayTypeP(PointerGetDatum(array));		ndim = ARR_NDIM(array);		dim = ARR_DIMS(array);		lb = ARR_LBOUND(array);		elemtype = ARR_ELEMTYPE(array);		arraydataptr = ARR_DATA_PTR(array);		arraynullsptr = ARR_NULLBITMAP(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 an empty array.	 */	if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)		return construct_empty_array(elemtype);	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 construct_empty_array(elemtype);	}	/* 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 construct_empty_array(elemtype);	}	mda_get_range(ndim, span, lowerIndx, upperIndx);	bytes = array_slice_size(arraydataptr, arraynullsptr,							 ndim, dim, lb,							 lowerIndx, upperIndx,							 elmlen, elmbyval, elmalign);	/*	 * Currently, we put a null bitmap in the result if the source has one;	 * could be smarter ...	 */	if (arraynullsptr)	{		dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, ArrayGetNItems(ndim, span));		bytes += dataoffset;	}	else	{		dataoffset = 0;			/* marker for no null bitmap */		bytes += ARR_OVERHEAD_NONULLS(ndim);	}	newarray = (ArrayType *) palloc(bytes);	SET_VARSIZE(newarray, bytes);	newarray->ndim = ndim;	newarray->dataoffset = dataoffset;	newarray->elemtype = elemtype;	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(newarray,						ndim, dim, lb,						arraydataptr, arraynullsptr,						lowerIndx, upperIndx,						elmlen, elmbyval, elmalign);	return newarray;}/* * array_set : *		  This routine sets the value of an array element (specified by *		  a subscript array) to a new value specified by "dataValue". * * 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 *	indx[]: the subscript values *	dataValue: the datum to be inserted at the given position *	isNull: whether dataValue 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 one *		  modified entry.  The original array object is not changed. * * For one-dimensional arrays only, we allow the array to be extended * by assigning to a position outside the existing subscript range; any * positions between the existing elements and the new one are set to NULLs. * (XXX TODO: allow a corresponding behavior for multidimensional arrays) * * NOTE: For assignments, we throw an error for invalid subscripts etc, * rather than returning a NULL as the fetch operations do. */ArrayType *array_set(ArrayType *array,		  int nSubscripts,		  int *indx,		  Datum dataValue,		  bool isNull,		  int arraytyplen,		  int elmlen,		  bool elmbyval,		  char elmalign){	ArrayType  *newarray;	int			i,				ndim,				dim[MAXDIM],				lb[MAXDIM],				offset;	char	   *elt_ptr;	bool		newhasnulls;	bits8	   *oldnullbitmap;	int			oldnitems,				newnitems,				olddatasize,				newsize,				olditemlen,				newitemlen,				overheadlen,				oldoverheadlen,				addedbefore,				addedafter,				lenbefore,				lenafter;	if (arraytyplen > 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("wrong number of array subscripts")));		if (indx[0] < 0 || indx[0] * elmlen >= arraytyplen)			ereport(ERROR,					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),					 errmsg("array subscript out of range")));		if (isNull)			ereport(ERROR,					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),					 errmsg("cannot assign null value to an element of a fixed-length array")));		newarray = (ArrayType *) palloc(arraytyplen);		memcpy(newarray, array, arraytyplen);		elt_ptr = (char *) newarray + indx[0] * elmlen;		ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, elt_ptr);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?