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

📄 arrayfuncs.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/*------------------------------------------------------------------------- * * arrayfuncs.c *	  Support functions for arrays. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.123.2.1 2005/11/22 18:23:20 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <ctype.h>#include "access/tupmacs.h"#include "catalog/catalog.h"#include "catalog/pg_type.h"#include "libpq/pqformat.h"#include "parser/parse_coerce.h"#include "parser/parse_oper.h"#include "utils/array.h"#include "utils/builtins.h"#include "utils/datum.h"#include "utils/memutils.h"#include "utils/lsyscache.h"#include "utils/syscache.h"#include "utils/typcache.h"/*---------- * A standard varlena array has the following internal structure: *	  <size>		- total number of bytes (also, TOAST info flags) *	  <ndim>		- number of dimensions of the array *	  <flags>		- bit mask of flags *	  <elemtype>	- element type OID *	  <dim>			- size of each array axis (C array of int) *	  <dim_lower>	- lower boundary of each dimension (C array of int) *	  <actual data> - whatever is the stored data * The actual data starts on a MAXALIGN boundary.  Individual items in the * array are aligned as specified by the array element type. * * NOTE: it is important that array elements of toastable datatypes NOT be * toasted, since the tupletoaster won't know they are there.  (We could * support compressed toasted items; only out-of-line items are dangerous. * However, it seems preferable to store such items uncompressed and allow * the toaster to compress the whole array as one input.) * * There is currently no support for NULL elements in arrays, either. * A reasonable (and backwards-compatible) way to add support would be to * add a nulls bitmap following the <dim_lower> array, which would be present * if needed; and its presence would be signaled by a bit in the flags word. * * * There are also some "fixed-length array" datatypes, such as NAME and * POINT.  These are simply a sequence of a fixed number of items each * of a fixed-length datatype, with no overhead; the item size must be * a multiple of its alignment requirement, because we do no padding. * We support subscripting on these types, but array_in() and array_out() * only work with varlena arrays. *---------- *//* ---------- * Local definitions * ---------- */#define ASSGN	 "="#define RETURN_NULL(type)  do { *isNull = true; return (type) 0; } while (0)static int	ArrayCount(char *str, int *dim, char typdelim);static Datum *ReadArrayStr(char *arrayStr, const char *origStr,			 int nitems, int ndim, int *dim,			 FmgrInfo *inputproc, Oid typioparam, int32 typmod,			 char typdelim,			 int typlen, bool typbyval, char typalign,			 int *nbytes);static Datum *ReadArrayBinary(StringInfo buf, int nitems,				FmgrInfo *receiveproc, Oid typioparam, int32 typmod,				int typlen, bool typbyval, char typalign,				int *nbytes);static void CopyArrayEls(char *p, Datum *values, int nitems,			 int typlen, bool typbyval, char typalign,			 bool freedata);static Datum ArrayCast(char *value, bool byval, int len);static int ArrayCastAndSet(Datum src,				int typlen, bool typbyval, char typalign,				char *dest);static int array_nelems_size(char *ptr, int nitems,				  int typlen, bool typbyval, char typalign);static char *array_seek(char *ptr, int nitems,		   int typlen, bool typbyval, char typalign);static int array_copy(char *destptr, int nitems, char *srcptr,		   int typlen, bool typbyval, char typalign);static int array_slice_size(int ndim, int *dim, int *lb, char *arraydataptr,				 int *st, int *endp,				 int typlen, bool typbyval, char typalign);static void array_extract_slice(int ndim, int *dim, int *lb,					char *arraydataptr,					int *st, int *endp, char *destPtr,					int typlen, bool typbyval, char typalign);static void array_insert_slice(int ndim, int *dim, int *lb,				   char *origPtr, int origdatasize,				   char *destPtr,				   int *st, int *endp, char *srcPtr,				   int typlen, bool typbyval, char typalign);static int	array_cmp(FunctionCallInfo fcinfo);static Datum array_type_length_coerce_internal(ArrayType *src,								  int32 desttypmod,								  bool isExplicit,								  FmgrInfo *fmgr_info);/*--------------------------------------------------------------------- * array_in : *		  converts an array from the external format in "string" to *		  its internal format. * return value : *		  the internal representation of the input array *-------------------------------------------------------------------- */Datumarray_in(PG_FUNCTION_ARGS){	char	   *string = PG_GETARG_CSTRING(0);	/* external form */	Oid			element_type = PG_GETARG_OID(1);		/* type of an array														 * element */	int32		typmod = PG_GETARG_INT32(2);	/* typmod for array elements */	int			typlen;	bool		typbyval;	char		typalign;	char		typdelim;	Oid			typioparam;	char	   *string_save,			   *p;	int			i,				nitems;	int32		nbytes;	Datum	   *dataPtr;	ArrayType  *retval;	int			ndim,				dim[MAXDIM],				lBound[MAXDIM];	ArrayMetaState *my_extra;	/*	 * We arrange to look up info about element type, including its input	 * 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 input conversion proc		 */		get_type_io_data(element_type, IOFunc_input,						 &my_extra->typlen, &my_extra->typbyval,						 &my_extra->typalign, &my_extra->typdelim,						 &my_extra->typioparam, &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;	typioparam = my_extra->typioparam;	/* Make a modifiable copy of the input */	string_save = pstrdup(string);	/*	 * If the input string starts with dimension info, read and use that.	 * Otherwise, we require the input to be in curly-brace style, and we	 * prescan the input to determine dimensions.	 *	 * Dimension info takes the form of one or more [n] or [m:n] items. The	 * outer loop iterates once per dimension item.	 */	p = string_save;	ndim = 0;	for (;;)	{		char	   *q;		int			ub;		/*		 * Note: we currently allow whitespace between, but not within,		 * dimension items.		 */		while (isspace((unsigned char) *p))			p++;		if (*p != '[')			break;				/* no more dimension items */		p++;		if (ndim >= MAXDIM)			ereport(ERROR,					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),					 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",							ndim, MAXDIM)));		for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++);		if (q == p)				/* no digits? */			ereport(ERROR,					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),					 errmsg("missing dimension value")));		if (*q == ':')		{			/* [m:n] format */			*q = '\0';			lBound[ndim] = atoi(p);			p = q + 1;			for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++);			if (q == p)			/* no digits? */				ereport(ERROR,						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),						 errmsg("missing dimension value")));		}		else		{			/* [n] format */			lBound[ndim] = 1;		}		if (*q != ']')			ereport(ERROR,					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),					 errmsg("missing \"]\" in array dimensions")));		*q = '\0';		ub = atoi(p);		p = q + 1;		if (ub < lBound[ndim])			ereport(ERROR,					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),					 errmsg("upper bound cannot be less than lower bound")));		dim[ndim] = ub - lBound[ndim] + 1;		ndim++;	}	if (ndim == 0)	{		/* No array dimensions, so intuit dimensions from brace structure */		if (*p != '{')			ereport(ERROR,					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),					 errmsg("array value must start with \"{\" or dimension information")));		ndim = ArrayCount(p, dim, typdelim);		for (i = 0; i < ndim; i++)			lBound[i] = 1;	}	else	{		int			ndim_braces,					dim_braces[MAXDIM];		/* If array dimensions are given, expect '=' operator */		if (strncmp(p, ASSGN, strlen(ASSGN)) != 0)			ereport(ERROR,					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),					 errmsg("missing assignment operator")));		p += strlen(ASSGN);		while (isspace((unsigned char) *p))			p++;		/*		 * intuit dimensions from brace structure -- it better match what we		 * were given		 */		if (*p != '{')			ereport(ERROR,					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),					 errmsg("array value must start with \"{\" or dimension information")));		ndim_braces = ArrayCount(p, dim_braces, typdelim);		if (ndim_braces != ndim)			ereport(ERROR,					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),				errmsg("array dimensions incompatible with array literal")));		for (i = 0; i < ndim; ++i)		{			if (dim[i] != dim_braces[i])				ereport(ERROR,						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),				errmsg("array dimensions incompatible with array literal")));		}	}#ifdef ARRAYDEBUG	printf("array_in- ndim %d (", ndim);	for (i = 0; i < ndim; i++)	{		printf(" %d", dim[i]);	};	printf(") for %s\n", string);#endif	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);	}	if (*p != '{')		ereport(ERROR,				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),				 errmsg("missing left brace")));	dataPtr = ReadArrayStr(p, string,						   nitems, ndim, dim, &my_extra->proc, typioparam,						   typmod, typdelim, 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);	pfree(string_save);	PG_RETURN_ARRAYTYPE_P(retval);}/*----------------------------------------------------------------------------- * ArrayCount *	 Counts the number of dimensions and the *dim array for an array string. *		 The syntax for array input is C-like nested curly braces *----------------------------------------------------------------------------- */typedef enum{	ARRAY_NO_LEVEL,	ARRAY_LEVEL_STARTED,	ARRAY_ELEM_STARTED,	ARRAY_ELEM_COMPLETED,	ARRAY_QUOTED_ELEM_STARTED,	ARRAY_QUOTED_ELEM_COMPLETED,	ARRAY_ELEM_DELIMITED,	ARRAY_LEVEL_COMPLETED,	ARRAY_LEVEL_DELIMITED} ArrayParseState;static intArrayCount(char *str, int *dim, char typdelim){	int			nest_level = 0,				i;	int			ndim = 1,				temp[MAXDIM],				nelems[MAXDIM],				nelems_last[MAXDIM];	bool		in_quotes = false;	bool		eoArray = false;	bool		empty_array = true;	char	   *ptr;	ArrayParseState parse_state = ARRAY_NO_LEVEL;	for (i = 0; i < MAXDIM; ++i)	{		temp[i] = dim[i] = 0;		nelems_last[i] = nelems[i] = 1;	}	/* special case for an empty array */	if (strcmp(str, "{}") == 0)		return 0;	ptr = str;	while (!eoArray)	{		bool		itemdone = false;		while (!itemdone)		{			if (parse_state == ARRAY_ELEM_STARTED ||				parse_state == ARRAY_QUOTED_ELEM_STARTED)				empty_array = false;			switch (*ptr)			{				case '\0':					/* Signal a premature end of the string */					ereport(ERROR,							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),							 errmsg("malformed array literal: \"%s\"", str)));					break;				case '\\':					/*					 * An escape must be after a level start, after an element					 * start, or after an element delimiter. In any case we					 * now must be past an element start.					 */					if (parse_state != ARRAY_LEVEL_STARTED &&						parse_state != ARRAY_ELEM_STARTED &&						parse_state != ARRAY_QUOTED_ELEM_STARTED &&						parse_state != ARRAY_ELEM_DELIMITED)						ereport(ERROR,								(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),							errmsg("malformed array literal: \"%s\"", str)));					if (parse_state != ARRAY_QUOTED_ELEM_STARTED)						parse_state = ARRAY_ELEM_STARTED;					/* skip the escaped character */					if (*(ptr + 1))						ptr++;					else						ereport(ERROR,								(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),							errmsg("malformed array literal: \"%s\"", str)));					break;				case '\"':					/*					 * A quote must be after a level start, after a quoted					 * element start, or after an element delimiter. In any					 * case we now must be past an element start.					 */					if (parse_state != ARRAY_LEVEL_STARTED &&						parse_state != ARRAY_QUOTED_ELEM_STARTED &&						parse_state != ARRAY_ELEM_DELIMITED)						ereport(ERROR,								(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),							errmsg("malformed array literal: \"%s\"", str)));					in_quotes = !in_quotes;					if (in_quotes)						parse_state = ARRAY_QUOTED_ELEM_STARTED;					else						parse_state = ARRAY_QUOTED_ELEM_COMPLETED;					break;				case '{':					if (!in_quotes)					{						/*						 * A left brace can occur if no nesting has occurred						 * yet, after a level start, or after a level						 * delimiter.						 */						if (parse_state != ARRAY_NO_LEVEL &&							parse_state != ARRAY_LEVEL_STARTED &&							parse_state != ARRAY_LEVEL_DELIMITED)							ereport(ERROR,							   (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),							errmsg("malformed array literal: \"%s\"", str)));						parse_state = ARRAY_LEVEL_STARTED;						if (nest_level >= MAXDIM)							ereport(ERROR,									(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),									 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",											nest_level, MAXDIM)));						temp[nest_level] = 0;						nest_level++;

⌨️ 快捷键说明

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