arrayfuncs.c

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

C
2,367
字号
			ptr++;		itemstart = ptr;		while (!itemdone)		{			switch (*ptr)			{				case '\0':					/* Signal a premature end of the string */					ereport(ERROR,							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),					errmsg("malformed array literal: \"%s\"", arrayStr)));					break;				case '\\':					{						char	   *cptr;						/* Crunch the string on top of the backslash. */						for (cptr = ptr; *cptr != '\0'; cptr++)							*cptr = *(cptr + 1);						if (*ptr == '\0')							ereport(ERROR,							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),							 errmsg("malformed array literal: \"%s\"", arrayStr)));						break;					}				case '\"':					{						char	   *cptr;						scanning_string = !scanning_string;						/* Crunch the string on top of the quote. */						for (cptr = ptr; *cptr != '\0'; cptr++)							*cptr = *(cptr + 1);						/* Back up to not miss following character. */						ptr--;						break;					}				case '{':					if (!scanning_string)					{						if (nest_level >= ndim)							ereport(ERROR,							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),							 errmsg("malformed array literal: \"%s\"", arrayStr)));						nest_level++;						indx[nest_level - 1] = 0;						/* skip leading whitespace */						while (isspace((unsigned char) *(ptr + 1)))							ptr++;						itemstart = ptr + 1;					}					break;				case '}':					if (!scanning_string)					{						if (nest_level == 0)							ereport(ERROR,							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),							 errmsg("malformed array literal: \"%s\"", arrayStr)));						if (i == -1)							i = ArrayGetOffset0(ndim, indx, prod);						indx[nest_level - 1] = 0;						nest_level--;						if (nest_level == 0)							eoArray = itemdone = true;						else						{							/*							 * tricky coding: terminate item value string							 * at first '}', but don't process it till we							 * see a typdelim char or end of array.  This							 * handles case where several '}'s appear							 * successively in a multidimensional array.							 */							*ptr = '\0';							indx[nest_level - 1]++;						}					}					break;				default:					if (*ptr == typdelim && !scanning_string)					{						if (i == -1)							i = ArrayGetOffset0(ndim, indx, prod);						itemdone = true;						indx[ndim - 1]++;					}					break;			}			if (!itemdone)				ptr++;		}		*ptr++ = '\0';		if (i < 0 || i >= nitems)			ereport(ERROR,					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),				   errmsg("malformed array literal: \"%s\"", arrayStr)));		values[i] = FunctionCall3(inputproc,								  CStringGetDatum(itemstart),								  ObjectIdGetDatum(typelem),								  Int32GetDatum(typmod));	}	/*	 * Initialize any unset items and compute total data space needed	 */	if (typlen > 0)	{		*nbytes = nitems * att_align(typlen, typalign);		if (!typbyval)			for (i = 0; i < nitems; i++)				if (values[i] == (Datum) 0)					values[i] = PointerGetDatum(palloc0(typlen));	}	else	{		Assert(!typbyval);		*nbytes = 0;		for (i = 0; i < nitems; i++)		{			if (values[i] != (Datum) 0)			{				/* 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);			}			else if (typlen == -1)			{				/* dummy varlena value (XXX bogus, see notes above) */				values[i] = PointerGetDatum(palloc(sizeof(int32)));				VARATT_SIZEP(DatumGetPointer(values[i])) = sizeof(int32);				*nbytes += sizeof(int32);				*nbytes = att_align(*nbytes, typalign);			}			else			{				/* dummy cstring value */				Assert(typlen == -2);				values[i] = PointerGetDatum(palloc(1));				*((char *) DatumGetPointer(values[i])) = '\0';				*nbytes += 1;				*nbytes = att_align(*nbytes, typalign);			}		}	}	return values;}/*---------- * Copy data into an array object from a temporary array of Datums. * * p: pointer to start of array data area * values: array of Datums to be copied * nitems: number of Datums to be copied * typbyval, typlen, typalign: info about element datatype * freedata: if TRUE and element type is pass-by-ref, pfree data values * referenced by Datums after copying them. * * If the input data is of varlena type, the caller must have ensured that * the values are not toasted.	(Doing it here doesn't work since the * caller has already allocated space for the array...) *---------- */static voidCopyArrayEls(char *p,			 Datum *values,			 int nitems,			 int typlen,			 bool typbyval,			 char typalign,			 bool freedata){	int			i;	if (typbyval)		freedata = false;	for (i = 0; i < nitems; i++)	{		p += ArrayCastAndSet(values[i], typlen, typbyval, typalign, p);		if (freedata)			pfree(DatumGetPointer(values[i]));	}}/*------------------------------------------------------------------------- * array_out : *		   takes the internal representation of an array and returns a string *		  containing the array in its external format. *------------------------------------------------------------------------- */Datumarray_out(PG_FUNCTION_ARGS){	ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);	Oid			element_type;	int			typlen;	bool		typbyval;	char		typalign;	char		typdelim;	Oid			typelem;	char	   *p,			   *tmp,			   *retval,			  **values;	bool	   *needquotes;	int			nitems,				overall_length,				i,				j,				k,				indx[MAXDIM];	int			ndim,			   *dim;	ArrayMetaState *my_extra;	element_type = ARR_ELEMTYPE(v);	/*	 * We arrange to look up info about element type, including its output	 * 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 output conversion		 * proc		 */		get_type_io_data(element_type, IOFunc_output,						 &my_extra->typlen, &my_extra->typbyval,						 &my_extra->typalign, &my_extra->typdelim,						 &my_extra->typelem, &my_extra->typiofunc);		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;	typdelim = my_extra->typdelim;	typelem = my_extra->typelem;	ndim = ARR_NDIM(v);	dim = ARR_DIMS(v);	nitems = ArrayGetNItems(ndim, dim);	if (nitems == 0)	{		retval = pstrdup("{}");		PG_RETURN_CSTRING(retval);	}	/*	 * 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;			/* [TRH] don't forget to count \0 at end. */	for (i = 0; i < nitems; i++)	{		Datum		itemvalue;		bool		nq;		itemvalue = fetch_att(p, typbyval, typlen);		values[i] = DatumGetCString(FunctionCall3(&my_extra->proc,												  itemvalue,											   ObjectIdGetDatum(typelem),												  Int32GetDatum(-1)));		p = att_addlength(p, typlen, PointerGetDatum(p));		p = (char *) att_align(p, typalign);		/* count data plus backslashes; detect chars needing quotes */		nq = (values[i][0] == '\0');	/* force quotes for empty string */		for (tmp = values[i]; *tmp; tmp++)		{			char		ch = *tmp;			overall_length += 1;			if (ch == '"' || ch == '\\')			{				nq = true;#ifndef TCL_ARRAYS				overall_length += 1;#endif			}			else if (ch == '{' || ch == '}' || ch == typdelim ||					 isspace((unsigned char) ch))				nq = true;		}		needquotes[i] = nq;		/* Count the pair of double quotes, if needed */		if (nq)			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; k *= dim[i++], j += k);	retval = (char *) palloc(overall_length + 2 * j);	p = retval;#define APPENDSTR(str)	(strcpy(p, (str)), p += strlen(p))#define APPENDCHAR(ch)	(*p++ = (ch), *p = '\0')	APPENDCHAR('{');	for (i = 0; i < ndim; 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) % dim[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 */	Oid			element_type;	int			typlen;	bool		typbyval;	char		typalign;	Oid			typelem;	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);	if (nitems == 0)	{		/* Return empty array */		retval = (ArrayType *) palloc0(sizeof(ArrayType));		retval->size = sizeof(ArrayType);		retval->elemtype = element_type;		PG_RETURN_ARRAYTYPE_P(retval);	}	/*	 * 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 = InvalidOid;	}	if (my_extra->element_type != element_type)	{		/* Get info about element type, including its receive proc */		get_type_io_data(element_type, IOFunc_receive,

⌨️ 快捷键说明

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