varlena.c

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

C
2,310
字号
						(errcode(ERRCODE_SUBSTRING_ERROR),					   errmsg("negative substring length not allowed")));			/*			 * A zero or negative value for the end position can happen if			 * the start was negative or one. SQL99 says to return a			 * zero-length string.			 */			if (E < 1)				return PG_STR_GET_TEXT("");			L1 = E - S1;		}		/*		 * If the start position is past the end of the string, SQL99 says		 * to return a zero-length string -- PG_GETARG_TEXT_P_SLICE() will		 * do that for us. Convert to zero-based starting position		 */		return DatumGetTextPSlice(str, S1 - 1, L1);	}	else if (eml > 1)	{		/*		 * When encoding max length is > 1, we can't get LC without		 * detoasting, so we'll grab a conservatively large slice now and		 * go back later to do the right thing		 */		int32		slice_start;		int32		slice_size;		int32		slice_strlen;		text	   *slice;		int32		E1;		int32		i;		char	   *p;		char	   *s;		text	   *ret;		/*		 * if S is past the end of the string, the tuple toaster will		 * return a zero-length string to us		 */		S1 = Max(S, 1);		/*		 * We need to start at position zero because there is no way to		 * know in advance which byte offset corresponds to the supplied		 * start position.		 */		slice_start = 0;		if (length_not_specified)		/* special case - get length to										 * end of string */			slice_size = L1 = -1;		else		{			int			E = S + length;			/*			 * A negative value for L is the only way for the end position			 * to be before the start. SQL99 says to throw an error.			 */			if (E < S)				ereport(ERROR,						(errcode(ERRCODE_SUBSTRING_ERROR),					   errmsg("negative substring length not allowed")));			/*			 * A zero or negative value for the end position can happen if			 * the start was negative or one. SQL99 says to return a			 * zero-length string.			 */			if (E < 1)				return PG_STR_GET_TEXT("");			/*			 * if E is past the end of the string, the tuple toaster will			 * truncate the length for us			 */			L1 = E - S1;			/*			 * Total slice size in bytes can't be any longer than the			 * start position plus substring length times the encoding max			 * length.			 */			slice_size = (S1 + L1) * eml;		}		slice = DatumGetTextPSlice(str, slice_start, slice_size);		/* see if we got back an empty string */		if ((VARSIZE(slice) - VARHDRSZ) == 0)			return PG_STR_GET_TEXT("");		/* Now we can get the actual length of the slice in MB characters */		slice_strlen = pg_mbstrlen_with_len(VARDATA(slice), VARSIZE(slice) - VARHDRSZ);		/*		 * Check that the start position wasn't > slice_strlen. If so,		 * SQL99 says to return a zero-length string.		 */		if (S1 > slice_strlen)			return PG_STR_GET_TEXT("");		/*		 * Adjust L1 and E1 now that we know the slice string length.		 * Again remember that S1 is one based, and slice_start is zero		 * based.		 */		if (L1 > -1)			E1 = Min(S1 + L1, slice_start + 1 + slice_strlen);		else			E1 = slice_start + 1 + slice_strlen;		/*		 * Find the start position in the slice; remember S1 is not zero		 * based		 */		p = VARDATA(slice);		for (i = 0; i < S1 - 1; i++)			p += pg_mblen(p);		/* hang onto a pointer to our start position */		s = p;		/*		 * Count the actual bytes used by the substring of the requested		 * length.		 */		for (i = S1; i < E1; i++)			p += pg_mblen(p);		ret = (text *) palloc(VARHDRSZ + (p - s));		VARATT_SIZEP(ret) = VARHDRSZ + (p - s);		memcpy(VARDATA(ret), s, (p - s));		return ret;	}	else		elog(ERROR, "invalid backend encoding: encoding max length < 1");	/* not reached: suppress compiler warning */	return PG_STR_GET_TEXT("");}/* * textpos - *	  Return the position of the specified substring. *	  Implements the SQL92 POSITION() function. *	  Ref: A Guide To The SQL Standard, Date & Darwen, 1997 * - thomas 1997-07-27 */Datumtextpos(PG_FUNCTION_ARGS){	PG_RETURN_INT32(text_position(PG_GETARG_DATUM(0), PG_GETARG_DATUM(1), 1));}/* * text_position - *	Does the real work for textpos() *	This is broken out so it can be called directly by other string processing *	functions. */static int32text_position(Datum str, Datum search_str, int matchnum){	int			eml = pg_database_encoding_max_length();	text	   *t1 = DatumGetTextP(str);	text	   *t2 = DatumGetTextP(search_str);	int			match = 0,				pos = 0,				p = 0,				px,				len1,				len2;	if (matchnum == 0)		return 0;				/* result for 0th match */	if (VARSIZE(t2) <= VARHDRSZ)		PG_RETURN_INT32(1);		/* result for empty pattern */	len1 = (VARSIZE(t1) - VARHDRSZ);	len2 = (VARSIZE(t2) - VARHDRSZ);	if (eml == 1)				/* simple case - single byte encoding */	{		char	   *p1,				   *p2;		p1 = VARDATA(t1);		p2 = VARDATA(t2);		/* no use in searching str past point where search_str will fit */		px = (len1 - len2);		for (p = 0; p <= px; p++)		{			if ((*p2 == *p1) && (strncmp(p1, p2, len2) == 0))			{				if (++match == matchnum)				{					pos = p + 1;					break;				}			}			p1++;		}	}	else if (eml > 1)			/* not as simple - multibyte encoding */	{		pg_wchar   *p1,				   *p2,				   *ps1,				   *ps2;		ps1 = p1 = (pg_wchar *) palloc((len1 + 1) * sizeof(pg_wchar));		(void) pg_mb2wchar_with_len((unsigned char *) VARDATA(t1), p1, len1);		len1 = pg_wchar_strlen(p1);		ps2 = p2 = (pg_wchar *) palloc((len2 + 1) * sizeof(pg_wchar));		(void) pg_mb2wchar_with_len((unsigned char *) VARDATA(t2), p2, len2);		len2 = pg_wchar_strlen(p2);		/* no use in searching str past point where search_str will fit */		px = (len1 - len2);		for (p = 0; p <= px; p++)		{			if ((*p2 == *p1) && (pg_wchar_strncmp(p1, p2, len2) == 0))			{				if (++match == matchnum)				{					pos = p + 1;					break;				}			}			p1++;		}		pfree(ps1);		pfree(ps2);	}	else		elog(ERROR, "invalid backend encoding: encoding max length < 1");	PG_RETURN_INT32(pos);}/* varstr_cmp() * Comparison function for text strings with given lengths. * Includes locale support, but must copy strings to temporary memory *	to allow null-termination for inputs to strcoll(). * Returns -1, 0 or 1 */intvarstr_cmp(char *arg1, int len1, char *arg2, int len2){	int			result;	/*	 * Unfortunately, there is no strncoll(), so in the non-C locale case	 * we have to do some memory copying.  This turns out to be	 * significantly slower, so we optimize the case where LC_COLLATE is	 * C.  We also try to optimize relatively-short strings by avoiding	 * palloc/pfree overhead.	 */#define STACKBUFLEN		1024	if (!lc_collate_is_c())	{		char		a1buf[STACKBUFLEN];		char		a2buf[STACKBUFLEN];		char	   *a1p,				   *a2p;		if (len1 >= STACKBUFLEN)			a1p = (char *) palloc(len1 + 1);		else			a1p = a1buf;		if (len2 >= STACKBUFLEN)			a2p = (char *) palloc(len2 + 1);		else			a2p = a2buf;		memcpy(a1p, arg1, len1);		a1p[len1] = '\0';		memcpy(a2p, arg2, len2);		a2p[len2] = '\0';		result = strcoll(a1p, a2p);		if (len1 >= STACKBUFLEN)			pfree(a1p);		if (len2 >= STACKBUFLEN)			pfree(a2p);	}	else	{		result = strncmp(arg1, arg2, Min(len1, len2));		if ((result == 0) && (len1 != len2))			result = (len1 < len2) ? -1 : 1;	}	return result;}/* text_cmp() * Internal comparison function for text strings. * Returns -1, 0 or 1 */static inttext_cmp(text *arg1, text *arg2){	char	   *a1p,			   *a2p;	int			len1,				len2;	a1p = VARDATA(arg1);	a2p = VARDATA(arg2);	len1 = VARSIZE(arg1) - VARHDRSZ;	len2 = VARSIZE(arg2) - VARHDRSZ;	return varstr_cmp(a1p, len1, a2p, len2);}/* * Comparison functions for text strings. * * Note: btree indexes need these routines not to leak memory; therefore, * be careful to free working copies of toasted datums.  Most places don't * need to be so careful. */Datumtexteq(PG_FUNCTION_ARGS){	text	   *arg1 = PG_GETARG_TEXT_P(0);	text	   *arg2 = PG_GETARG_TEXT_P(1);	bool		result;	/* fast path for different-length inputs */	if (VARSIZE(arg1) != VARSIZE(arg2))		result = false;	else		result = (text_cmp(arg1, arg2) == 0);	PG_FREE_IF_COPY(arg1, 0);	PG_FREE_IF_COPY(arg2, 1);	PG_RETURN_BOOL(result);}Datumtextne(PG_FUNCTION_ARGS){	text	   *arg1 = PG_GETARG_TEXT_P(0);	text	   *arg2 = PG_GETARG_TEXT_P(1);	bool		result;	/* fast path for different-length inputs */	if (VARSIZE(arg1) != VARSIZE(arg2))		result = true;	else		result = (text_cmp(arg1, arg2) != 0);	PG_FREE_IF_COPY(arg1, 0);	PG_FREE_IF_COPY(arg2, 1);	PG_RETURN_BOOL(result);}Datumtext_lt(PG_FUNCTION_ARGS){	text	   *arg1 = PG_GETARG_TEXT_P(0);	text	   *arg2 = PG_GETARG_TEXT_P(1);	bool		result;	result = (text_cmp(arg1, arg2) < 0);	PG_FREE_IF_COPY(arg1, 0);	PG_FREE_IF_COPY(arg2, 1);	PG_RETURN_BOOL(result);}Datumtext_le(PG_FUNCTION_ARGS){	text	   *arg1 = PG_GETARG_TEXT_P(0);	text	   *arg2 = PG_GETARG_TEXT_P(1);	bool		result;	result = (text_cmp(arg1, arg2) <= 0);	PG_FREE_IF_COPY(arg1, 0);	PG_FREE_IF_COPY(arg2, 1);	PG_RETURN_BOOL(result);}Datumtext_gt(PG_FUNCTION_ARGS){	text	   *arg1 = PG_GETARG_TEXT_P(0);	text	   *arg2 = PG_GETARG_TEXT_P(1);	bool		result;	result = (text_cmp(arg1, arg2) > 0);	PG_FREE_IF_COPY(arg1, 0);	PG_FREE_IF_COPY(arg2, 1);	PG_RETURN_BOOL(result);}Datumtext_ge(PG_FUNCTION_ARGS){	text	   *arg1 = PG_GETARG_TEXT_P(0);	text	   *arg2 = PG_GETARG_TEXT_P(1);	bool		result;	result = (text_cmp(arg1, arg2) >= 0);	PG_FREE_IF_COPY(arg1, 0);	PG_FREE_IF_COPY(arg2, 1);	PG_RETURN_BOOL(result);}Datumbttextcmp(PG_FUNCTION_ARGS){	text	   *arg1 = PG_GETARG_TEXT_P(0);	text	   *arg2 = PG_GETARG_TEXT_P(1);	int32		result;	result = text_cmp(arg1, arg2);	PG_FREE_IF_COPY(arg1, 0);	PG_FREE_IF_COPY(arg2, 1);	PG_RETURN_INT32(result);}Datumtext_larger(PG_FUNCTION_ARGS){	text	   *arg1 = PG_GETARG_TEXT_P(0);	text	   *arg2 = PG_GETARG_TEXT_P(1);	text	   *result;	result = ((text_cmp(arg1, arg2) > 0) ? arg1 : arg2);	PG_RETURN_TEXT_P(result);}Datumtext_smaller(PG_FUNCTION_ARGS){	text	   *arg1 = PG_GETARG_TEXT_P(0);	text	   *arg2 = PG_GETARG_TEXT_P(1);	text	   *result;	result = ((text_cmp(arg1, arg2) < 0) ? arg1 : arg2);	PG_RETURN_TEXT_P(result);}/* * The following operators support character-by-character comparison * of text data types, to allow building indexes suitable for LIKE * clauses. */static intinternal_text_pattern_compare(text *arg1, text *arg2){	int			result;	result = memcmp(VARDATA(arg1), VARDATA(arg2),					Min(VARSIZE(arg1), VARSIZE(arg2)) - VARHDRSZ);	if (result != 0)		return result;	else if (VARSIZE(arg1) < VARSIZE(arg2))		return -1;	else if (VARSIZE(arg1) > VARSIZE(arg2))		return 1;	else		return 0;}Datumtext_pattern_lt(PG_FUNCTION_ARGS){	text	   *arg1 = PG_GETARG_TEXT_P(0);	text	   *arg2 = PG_GETARG_TEXT_P(1);	int			result;	result = internal_text_pattern_compare(arg1, arg2);	PG_FREE_IF_COPY(arg1, 0);	PG_FREE_IF_COPY(arg2, 1);	PG_RETURN_BOOL(result < 0);}Datumtext_pattern_le(PG_FUNCTION_ARGS){	text	   *arg1 = PG_GETARG_TEXT_P(0);	text	   *arg2 = PG_GETARG_TEXT_P(1);	int			result;	result = internal_text_pattern_compare(arg1, arg2);	PG_FREE_IF_COPY(arg1, 0);	PG_FREE_IF_COPY(arg2, 1);	PG_RETURN_BOOL(result <= 0);}Datumtext_pattern_eq(PG_FUNCTION_ARGS){	text	   *arg1 = PG_GETARG_TEXT_P(0);	text	   *arg2 = PG_GETARG_TEXT_P(1);	int			result;	if (VARSIZE(arg1) != VARSIZE(arg2))		result = 1;	else		result = internal_text_pattern_compare(arg1, arg2);	PG_FREE_IF_COPY(arg1, 0);	PG_FREE_IF_COPY(arg2, 1);	PG_RETURN_BOOL(result == 0);}Datumtext_pattern_ge(PG_FUNCTION_ARGS){	text	   *arg1 = PG_GETARG_TEXT_P(0);	text	   *arg2 = PG_GETARG_TEXT_P(1);	int			result;	result = internal_text_pattern_compare(arg1, arg2);	PG_FREE_IF_COPY(arg1, 0);	PG_FREE_IF_COPY(arg2, 1);	PG_RETURN_BOOL(result >= 0);}Datumtext_pattern_gt(PG_FUNCTION_ARGS){	text	   *arg1 = PG_GETARG_TEXT_P(0);	text	   *arg2 = PG_GETARG_TEXT_P(1);	int			result;	result = internal_text_pattern_compare(arg1, arg2);	PG_FREE_IF_COPY(arg1, 0);	PG_FREE_IF_COPY(arg2, 1);

⌨️ 快捷键说明

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