arrayfuncs.c

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

C
2,484
字号
	bitmask = 1;	for (i = 0; i < nitems; i++)	{		bool		needquote;		/* Get source element, checking for NULL */		if (bitmap && (*bitmap & bitmask) == 0)		{			values[i] = pstrdup("NULL");			overall_length += 4;			needquote = false;		}		else		{			Datum		itemvalue;			itemvalue = fetch_att(p, typbyval, typlen);			values[i] = OutputFunctionCall(&my_extra->proc, itemvalue);			p = att_addlength_pointer(p, typlen, p);			p = (char *) att_align_nominal(p, typalign);			/* count data plus backslashes; detect chars needing quotes */			if (values[i][0] == '\0')				needquote = true;		/* force quotes for empty string */			else if (pg_strcasecmp(values[i], "NULL") == 0)				needquote = true;		/* force quotes for literal NULL */			else				needquote = false;			for (tmp = values[i]; *tmp != '\0'; tmp++)			{				char		ch = *tmp;				overall_length += 1;				if (ch == '"' || ch == '\\')				{					needquote = true;#ifndef TCL_ARRAYS					overall_length += 1;#endif				}				else if (ch == '{' || ch == '}' || ch == typdelim ||						 isspace((unsigned char) ch))					needquote = true;			}		}		needquotes[i] = needquote;		/* Count the pair of double quotes, if needed */		if (needquote)			overall_length += 2;		/* and the comma */		overall_length += 1;		/* advance bitmap pointer if any */		if (bitmap)		{			bitmask <<= 1;			if (bitmask == 0x100)			{				bitmap++;				bitmask = 1;			}		}	}	/*	 * count total number of curly braces in output string	 */	for (i = j = 0, k = 1; i < ndim; i++)		k *= dims[i], j += k;	dims_str[0] = '\0';	/* add explicit dimensions if required */	if (needdims)	{		char	   *ptr = dims_str;		for (i = 0; i < ndim; i++)		{			sprintf(ptr, "[%d:%d]", lb[i], lb[i] + dims[i] - 1);			ptr += strlen(ptr);		}		*ptr++ = *ASSGN;		*ptr = '\0';	}	retval = (char *) palloc(strlen(dims_str) + overall_length + 2 * j);	p = retval;#define APPENDSTR(str)	(strcpy(p, (str)), p += strlen(p))#define APPENDCHAR(ch)	(*p++ = (ch), *p = '\0')	if (needdims)		APPENDSTR(dims_str);	APPENDCHAR('{');	for (i = 0; i < ndim; i++)		indx[i] = 0;	j = 0;	k = 0;	do	{		for (i = j; i < ndim - 1; i++)			APPENDCHAR('{');		if (needquotes[k])		{			APPENDCHAR('"');#ifndef TCL_ARRAYS			for (tmp = values[k]; *tmp; tmp++)			{				char		ch = *tmp;				if (ch == '"' || ch == '\\')					*p++ = '\\';				*p++ = ch;			}			*p = '\0';#else			APPENDSTR(values[k]);#endif			APPENDCHAR('"');		}		else			APPENDSTR(values[k]);		pfree(values[k++]);		for (i = ndim - 1; i >= 0; i--)		{			indx[i] = (indx[i] + 1) % dims[i];			if (indx[i])			{				APPENDCHAR(typdelim);				break;			}			else				APPENDCHAR('}');		}		j = i;	} while (j != -1);#undef APPENDSTR#undef APPENDCHAR	pfree(values);	pfree(needquotes);	PG_RETURN_CSTRING(retval);}/* * array_recv : *		  converts an array from the external binary format to *		  its internal format. * * return value : *		  the internal representation of the input array */Datumarray_recv(PG_FUNCTION_ARGS){	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);	Oid			spec_element_type = PG_GETARG_OID(1);	/* type of an array														 * element */	int32		typmod = PG_GETARG_INT32(2);	/* typmod for array elements */	Oid			element_type;	int			typlen;	bool		typbyval;	char		typalign;	Oid			typioparam;	int			i,				nitems;	Datum	   *dataPtr;	bool	   *nullsPtr;	bool		hasnulls;	int32		nbytes;	int32		dataoffset;	ArrayType  *retval;	int			ndim,				flags,				dim[MAXDIM],				lBound[MAXDIM];	ArrayMetaState *my_extra;	/* Get the array header information */	ndim = pq_getmsgint(buf, 4);	if (ndim < 0)				/* we do allow zero-dimension arrays */		ereport(ERROR,				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),				 errmsg("invalid number of dimensions: %d", ndim)));	if (ndim > MAXDIM)		ereport(ERROR,				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),				 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",						ndim, MAXDIM)));	flags = pq_getmsgint(buf, 4);	if (flags != 0 && flags != 1)		ereport(ERROR,				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),				 errmsg("invalid array flags")));	element_type = pq_getmsgint(buf, sizeof(Oid));	if (element_type != spec_element_type)	{		/* XXX Can we allow taking the input element type in any cases? */		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),				 errmsg("wrong element type")));	}	for (i = 0; i < ndim; i++)	{		dim[i] = pq_getmsgint(buf, 4);		lBound[i] = pq_getmsgint(buf, 4);	}	/* This checks for overflow of array dimensions */	nitems = ArrayGetNItems(ndim, dim);	/*	 * We arrange to look up info about element type, including its receive	 * 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 = ~element_type;	}	if (my_extra->element_type != element_type)	{		/* Get info about element type, including its receive proc */		get_type_io_data(element_type, IOFunc_receive,						 &my_extra->typlen, &my_extra->typbyval,						 &my_extra->typalign, &my_extra->typdelim,						 &my_extra->typioparam, &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;	}	if (nitems == 0)	{		/* Return empty array ... but not till we've validated element_type */		PG_RETURN_ARRAYTYPE_P(construct_empty_array(element_type));	}	typlen = my_extra->typlen;	typbyval = my_extra->typbyval;	typalign = my_extra->typalign;	typioparam = my_extra->typioparam;	dataPtr = (Datum *) palloc(nitems * sizeof(Datum));	nullsPtr = (bool *) palloc(nitems * sizeof(bool));	ReadArrayBinary(buf, nitems,					&my_extra->proc, typioparam, typmod,					typlen, typbyval, typalign,					dataPtr, nullsPtr,					&hasnulls, &nbytes);	if (hasnulls)	{		dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);		nbytes += dataoffset;	}	else	{		dataoffset = 0;			/* marker for no null bitmap */		nbytes += ARR_OVERHEAD_NONULLS(ndim);	}	retval = (ArrayType *) palloc(nbytes);	SET_VARSIZE(retval, nbytes);	retval->ndim = ndim;	retval->dataoffset = dataoffset;	retval->elemtype = element_type;	memcpy(ARR_DIMS(retval), dim, ndim * sizeof(int));	memcpy(ARR_LBOUND(retval), lBound, ndim * sizeof(int));	CopyArrayEls(retval,				 dataPtr, nullsPtr, nitems,				 typlen, typbyval, typalign,				 true);	pfree(dataPtr);	pfree(nullsPtr);	PG_RETURN_ARRAYTYPE_P(retval);}/* * ReadArrayBinary: *	 collect the data elements of an array being read in binary style. * * Inputs: *	buf: the data buffer to read from. *	nitems: total number of array elements (already read). *	receiveproc: type-specific receive procedure for element datatype. *	typioparam, typmod: auxiliary values to pass to receiveproc. *	typlen, typbyval, typalign: storage parameters of element datatype. * * Outputs: *	values[]: filled with converted data values. *	nulls[]: filled with is-null markers. *	*hasnulls: set TRUE iff there are any null elements. *	*nbytes: set to total size of data area needed (including alignment *		padding but not including array header overhead). * * Note that values[] and nulls[] are allocated by the caller, and must have * nitems elements. */static voidReadArrayBinary(StringInfo buf,				int nitems,				FmgrInfo *receiveproc,				Oid typioparam,				int32 typmod,				int typlen,				bool typbyval,				char typalign,				Datum *values,				bool *nulls,				bool *hasnulls,				int32 *nbytes){	int			i;	bool		hasnull;	int32		totbytes;	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 < -1 || itemlen > (buf->len - buf->cursor))			ereport(ERROR,					(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),					 errmsg("insufficient data left in message")));		if (itemlen == -1)		{			/* -1 length means NULL */			values[i] = ReceiveFunctionCall(receiveproc, NULL,											typioparam, typmod);			nulls[i] = true;			continue;		}		/*		 * 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] = ReceiveFunctionCall(receiveproc, &elem_buf,										typioparam, typmod);		nulls[i] = false;		/* 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;	}	/*	 * Check for nulls, compute total data space needed	 */	hasnull = false;	totbytes = 0;	for (i = 0; i < nitems; i++)	{		if (nulls[i])			hasnull = true;		else		{			/* let's just make sure data is not toasted */			if (typlen == -1)				values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i]));			totbytes = att_addlength_datum(totbytes, typlen, values[i]);			totbytes = att_align_nominal(totbytes, typalign);			/* check for overflow of total request */			if (!AllocSizeIsValid(totbytes))				ereport(ERROR,						(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),						 errmsg("array size exceeds the maximum allowed (%d)",								(int) MaxAllocSize)));		}	}	*hasnulls = hasnull;	*nbytes = totbytes;}/* * 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 = ARR_ELEMTYPE(v);	int			typlen;	bool		typbyval;	char		typalign;	char	   *p;	bits8	   *bitmap;	int			bitmask;	int			nitems,				i;	int			ndim,			   *dim;	StringInfoData buf;	ArrayMetaState *my_extra;	/*	 * 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 = ~element_type;	}	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->typioparam, &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;	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, ARR_HASNULL(v) ? 1 : 0, 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);

⌨️ 快捷键说明

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