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