⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arrayfuncs.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
	nitems = ArrayGetNItems(ndim, dims);	if (nitems == 0)	{		retval = pstrdup("{}");		PG_RETURN_CSTRING(retval);	}	/*	 * we will need to add explicit dimensions if any dimension has a lower	 * bound other than one	 */	for (i = 0; i < ndim; i++)	{		if (lb[i] != 1)		{			needdims = true;			break;		}	}	/*	 * Convert all values to string form, count total space needed (including	 * any overhead such as escaping backslashes), and detect whether each	 * item needs double quotes.	 */	values = (char **) palloc(nitems * sizeof(char *));	needquotes = (bool *) palloc(nitems * sizeof(bool));	p = ARR_DATA_PTR(v);	overall_length = 1;			/* don't forget to count \0 at end. */	for (i = 0; i < nitems; i++)	{		Datum		itemvalue;		bool		needquote;		itemvalue = fetch_att(p, typbyval, typlen);		values[i] = DatumGetCString(FunctionCall1(&my_extra->proc,												  itemvalue));		p = att_addlength(p, typlen, PointerGetDatum(p));		p = (char *) att_align(p, typalign);		/* count data plus backslashes; detect chars needing quotes */		if (values[i][0] == '\0')			needquote = true;	/* force quotes for empty string */		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;	}	/*	 * 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;	int32		nbytes;	Datum	   *dataPtr;	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)		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);	}	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 */		retval = (ArrayType *) palloc0(sizeof(ArrayType));		retval->size = sizeof(ArrayType);		retval->elemtype = element_type;		PG_RETURN_ARRAYTYPE_P(retval);	}	typlen = my_extra->typlen;	typbyval = my_extra->typbyval;	typalign = my_extra->typalign;	typioparam = my_extra->typioparam;	dataPtr = ReadArrayBinary(buf, nitems, &my_extra->proc,							  typioparam, typmod,							  typlen, typbyval, typalign,							  &nbytes);	nbytes += ARR_OVERHEAD(ndim);	retval = (ArrayType *) palloc0(nbytes);	retval->size = nbytes;	retval->ndim = ndim;	retval->elemtype = element_type;	memcpy(ARR_DIMS(retval), dim, ndim * sizeof(int));	memcpy(ARR_LBOUND(retval), 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 typioparam,				int32 typmod,				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] = FunctionCall3(receiveproc,								  PointerGetDatum(&elem_buf),								  ObjectIdGetDatum(typioparam),								  Int32GetDatum(typmod));		/* 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;	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->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, 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(FunctionCall1(&my_extra->proc,												   itemvalue));		/* We assume the result will not have been toasted */		pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);		pq_sendbytes(&buf, VARDATA(outputbytes),

⌨️ 快捷键说明

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