arrayfuncs.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,367 行 · 第 1/5 页

C
2,367
字号
						 &my_extra->typlen, &my_extra->typbyval,						 &my_extra->typalign, &my_extra->typdelim,						 &my_extra->typelem, &my_extra->typiofunc);		if (!OidIsValid(my_extra->typiofunc))			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_FUNCTION),				 errmsg("no binary input function available for type %s",						format_type_be(element_type))));		fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,					  fcinfo->flinfo->fn_mcxt);		my_extra->element_type = element_type;	}	typlen = my_extra->typlen;	typbyval = my_extra->typbyval;	typalign = my_extra->typalign;	typelem = my_extra->typelem;	dataPtr = ReadArrayBinary(buf, nitems, &my_extra->proc, typelem,							  typlen, typbyval, typalign,							  &nbytes);	nbytes += ARR_OVERHEAD(ndim);	retval = (ArrayType *) palloc0(nbytes);	retval->size = nbytes;	retval->ndim = ndim;	retval->elemtype = element_type;	memcpy((char *) ARR_DIMS(retval), (char *) dim,		   ndim * sizeof(int));	memcpy((char *) ARR_LBOUND(retval), (char *) lBound,		   ndim * sizeof(int));	CopyArrayEls(ARR_DATA_PTR(retval), dataPtr, nitems,				 typlen, typbyval, typalign, true);	pfree(dataPtr);	PG_RETURN_ARRAYTYPE_P(retval);}/*--------------------------------------------------------------------------- * ReadArrayBinary: *	 collect the data elements of an array being read in binary style. * result : *	 returns a palloc'd array of Datum representations of the array elements. *	 If element type is pass-by-ref, the Datums point to palloc'd values. *	 *nbytes is set to the amount of data space needed for the array, *	 including alignment padding but not including array header overhead. *--------------------------------------------------------------------------- */static Datum *ReadArrayBinary(StringInfo buf,				int nitems,				FmgrInfo *receiveproc,				Oid typelem,				int typlen,				bool typbyval,				char typalign,				int *nbytes){	Datum	   *values;	int			i;	values = (Datum *) palloc(nitems * sizeof(Datum));	for (i = 0; i < nitems; i++)	{		int			itemlen;		StringInfoData elem_buf;		char		csave;		/* Get and check the item length */		itemlen = pq_getmsgint(buf, 4);		if (itemlen < 0 || itemlen > (buf->len - buf->cursor))			ereport(ERROR,					(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),					 errmsg("insufficient data left in message")));		/*		 * Rather than copying data around, we just set up a phony		 * StringInfo pointing to the correct portion of the input buffer.		 * We assume we can scribble on the input buffer so as to maintain		 * the convention that StringInfos have a trailing null.		 */		elem_buf.data = &buf->data[buf->cursor];		elem_buf.maxlen = itemlen + 1;		elem_buf.len = itemlen;		elem_buf.cursor = 0;		buf->cursor += itemlen;		csave = buf->data[buf->cursor];		buf->data[buf->cursor] = '\0';		/* Now call the element's receiveproc */		values[i] = FunctionCall2(receiveproc,								  PointerGetDatum(&elem_buf),								  ObjectIdGetDatum(typelem));		/* Trouble if it didn't eat the whole buffer */		if (elem_buf.cursor != itemlen)			ereport(ERROR,					(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),					 errmsg("improper binary format in array element %d",							i + 1)));		buf->data[buf->cursor] = csave;	}	/*	 * Compute total data space needed	 */	if (typlen > 0)		*nbytes = nitems * att_align(typlen, typalign);	else	{		Assert(!typbyval);		*nbytes = 0;		for (i = 0; i < nitems; i++)		{			/* let's just make sure data is not toasted */			if (typlen == -1)				values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i]));			*nbytes = att_addlength(*nbytes, typlen, values[i]);			*nbytes = att_align(*nbytes, typalign);		}	}	return values;}/*------------------------------------------------------------------------- * array_send : *		   takes the internal representation of an array and returns a bytea *		  containing the array in its external binary format. *------------------------------------------------------------------------- */Datumarray_send(PG_FUNCTION_ARGS){	ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);	Oid			element_type;	int			typlen;	bool		typbyval;	char		typalign;	Oid			typelem;	char	   *p;	int			nitems,				i;	int			ndim,			   *dim;	StringInfoData buf;	ArrayMetaState *my_extra;	/* Get information about the element type and the array dimensions */	element_type = ARR_ELEMTYPE(v);	/*	 * We arrange to look up info about element type, including its send	 * conversion proc, only once per series of calls, assuming the	 * element type doesn't change underneath us.	 */	my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;	if (my_extra == NULL)	{		fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,												 sizeof(ArrayMetaState));		my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;		my_extra->element_type = InvalidOid;	}	if (my_extra->element_type != element_type)	{		/* Get info about element type, including its send proc */		get_type_io_data(element_type, IOFunc_send,						 &my_extra->typlen, &my_extra->typbyval,						 &my_extra->typalign, &my_extra->typdelim,						 &my_extra->typelem, &my_extra->typiofunc);		if (!OidIsValid(my_extra->typiofunc))			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_FUNCTION),				errmsg("no binary output function available for type %s",					   format_type_be(element_type))));		fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,					  fcinfo->flinfo->fn_mcxt);		my_extra->element_type = element_type;	}	typlen = my_extra->typlen;	typbyval = my_extra->typbyval;	typalign = my_extra->typalign;	typelem = my_extra->typelem;	ndim = ARR_NDIM(v);	dim = ARR_DIMS(v);	nitems = ArrayGetNItems(ndim, dim);	pq_begintypsend(&buf);	/* Send the array header information */	pq_sendint(&buf, ndim, 4);	pq_sendint(&buf, v->flags, 4);	pq_sendint(&buf, element_type, sizeof(Oid));	for (i = 0; i < ndim; i++)	{		pq_sendint(&buf, ARR_DIMS(v)[i], 4);		pq_sendint(&buf, ARR_LBOUND(v)[i], 4);	}	/* Send the array elements using the element's own sendproc */	p = ARR_DATA_PTR(v);	for (i = 0; i < nitems; i++)	{		Datum		itemvalue;		bytea	   *outputbytes;		itemvalue = fetch_att(p, typbyval, typlen);		outputbytes = DatumGetByteaP(FunctionCall2(&my_extra->proc,												   itemvalue,											 ObjectIdGetDatum(typelem)));		/* We assume the result will not have been toasted */		pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);		pq_sendbytes(&buf, VARDATA(outputbytes),					 VARSIZE(outputbytes) - VARHDRSZ);		pfree(outputbytes);		p = att_addlength(p, typlen, PointerGetDatum(p));		p = (char *) att_align(p, typalign);	}	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}/*------------------------------------------------------------------------- * array_length_coerce : *		  Apply the element type's length-coercion routine to each element *		  of the given array. *------------------------------------------------------------------------- */Datumarray_length_coerce(PG_FUNCTION_ARGS){	ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);	int32		len = PG_GETARG_INT32(1);	bool		isExplicit = PG_GETARG_BOOL(2);	FmgrInfo   *fmgr_info = fcinfo->flinfo;	typedef struct	{		Oid			elemtype;		FmgrInfo	coerce_finfo;	} alc_extra;	alc_extra  *my_extra;	FunctionCallInfoData locfcinfo;	/* If no typmod is provided, shortcircuit the whole thing */	if (len < 0)		PG_RETURN_ARRAYTYPE_P(v);	/*	 * We arrange to look up the element type's coercion function only	 * once per series of calls, assuming the element type doesn't change	 * underneath us.	 */	my_extra = (alc_extra *) fmgr_info->fn_extra;	if (my_extra == NULL)	{		fmgr_info->fn_extra = MemoryContextAlloc(fmgr_info->fn_mcxt,												 sizeof(alc_extra));		my_extra = (alc_extra *) fmgr_info->fn_extra;		my_extra->elemtype = InvalidOid;	}	if (my_extra->elemtype != ARR_ELEMTYPE(v))	{		Oid			funcId;		int			nargs;		funcId = find_typmod_coercion_function(ARR_ELEMTYPE(v), &nargs);		if (OidIsValid(funcId))			fmgr_info_cxt(funcId, &my_extra->coerce_finfo, fmgr_info->fn_mcxt);		else			my_extra->coerce_finfo.fn_oid = InvalidOid;		my_extra->elemtype = ARR_ELEMTYPE(v);	}	/*	 * If we didn't find a coercion function, return the array unmodified	 * (this should not happen in the normal course of things, but might	 * happen if this function is called manually).	 */	if (my_extra->coerce_finfo.fn_oid == InvalidOid)		PG_RETURN_ARRAYTYPE_P(v);	/*	 * Use array_map to apply the function to each array element.	 *	 * Note: we pass isExplicit whether or not the function wants it ...	 */	MemSet(&locfcinfo, 0, sizeof(locfcinfo));	locfcinfo.flinfo = &my_extra->coerce_finfo;	locfcinfo.nargs = 3;	locfcinfo.arg[0] = PointerGetDatum(v);	locfcinfo.arg[1] = Int32GetDatum(len);	locfcinfo.arg[2] = BoolGetDatum(isExplicit);	return array_map(&locfcinfo, ARR_ELEMTYPE(v), ARR_ELEMTYPE(v));}/*----------------------------------------------------------------------------- * 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);	}	VARATT_SIZEP(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 an index 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. *--------------------------------------------------------------------------- */Datumarray_ref(ArrayType *array,		  int nSubscripts,		  int *indx,		  int arraylen,		  int elmlen,		  bool elmbyval,		  char elmalign,		  bool *isNull){	int			i,				ndim,			   *dim,			   *lb,				offset,				fixedDim[1],				fixedLb[1];	char	   *arraydataptr,			   *retptr;	if (array == (ArrayType *) NULL)		RETURN_NULL(Datum);	if (arraylen > 0)	{		/*		 * fixed-length arrays -- these are assumed to be 1-d, 0-based		 */		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);	}	/*	 * Return NULL for invalid subscript	 */	if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM)		RETURN_NULL(Datum);	for (i = 0; i < ndim; i++)		if (indx[i] < lb[i] || indx[i] >= (dim[i] + lb[i]))			RETURN_NULL(Datum);	/*

⌨️ 快捷键说明

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