greenplumn charpad 源码

  • 2022-08-18
  • 浏览 (373)

greenplumn charpad 代码

文件路径:/gpcontrib/orafce/charpad.c

/*----------------------------------------------------------------------------
 *
 *  charpad.c
 *  LPAD and RPAD SQL functions for PostgreSQL.
 *
 *----------------------------------------------------------------------------
 */

#include "postgres.h"
#include "utils/builtins.h"
#include "utils/formatting.h"
#include "mb/pg_wchar.h"
#include "fmgr.h"

#include "orafce.h"
#include "builtins.h"

/* flags */
#define ON	true
#define OFF	false

/* Upper limit on total width of the padded output of *pad functions */
#define PAD_MAX 4000

PG_FUNCTION_INFO_V1(orafce_lpad);
PG_FUNCTION_INFO_V1(orafce_rpad);

/*
 * orafce_lpad(string text, length int32 [, fill text])
 *
 * Fill up the string to length 'length' by prepending
 * the characters fill (a half-width space by default)
 */
Datum
orafce_lpad(PG_FUNCTION_ARGS)
{
	text	*string1 = PG_GETARG_TEXT_PP(0);
	int32	output_width = PG_GETARG_INT32(1);
	text	*string2 = PG_GETARG_TEXT_PP(2);
	text	*ret;
	char	*ptr1,
			*ptr2 = NULL,
			*ptr2start = NULL,
			*ptr2end = NULL,
			*ptr_ret,
			*spc = " ";
	int		mlen,
			dsplen,
			s1blen,
			s2blen,
			hslen,
			total_blen = 0,
			s1_width = 0,
			s2_add_width = 0,
			s1_add_blen = 0,
			s2_add_blen = 0;
	bool	s2_operate = ON,
			half_space = OFF,
			init_ptr = ON;

	/* validate output width (the 2nd argument) */
	if (output_width < 0)
		output_width = 0;
	if (output_width > PAD_MAX)
		output_width = PAD_MAX;

	/* get byte-length of the 1st and 3rd argument strings */
	s1blen = VARSIZE_ANY_EXHDR(string1);
	s2blen = VARSIZE_ANY_EXHDR(string2);

	/* validate the lengths */
	if (s1blen < 0)
		s1blen = 0;
	if (s2blen < 0)
		s2blen = 0;

	/* if the filler length is zero disable filling */
	if (s2blen == 0)
	{
		s2_operate = OFF;	/* turn off string2 processing flag */
		output_width = 0;	/* same behavior as Oracle database */
	}

	/* byte-length of half-width space */
	hslen = pg_mblen(spc);

	/*
	 * Calculate the length of the portion of string1 to include in
	 * the final output
	 */
	ptr1 = VARDATA_ANY(string1);
	while (s1blen > 0)
	{
		/* byte-length and display length per character of string1 */
		mlen = pg_mblen(ptr1);
		dsplen = pg_dsplen(ptr1);

		/* accumulate display length of string1 */
		s1_width += dsplen;

		/*
		 * if string1 is longer/wider than the requested output_width,
		 * discard this character and prepend a half-width space instead
		 */
		if(s1_width >= output_width)
		{
			if(s1_width != output_width)
			{
				/* secure bytes for a half-width space in the final output */
				if (output_width != 0)
				{
					s1_add_blen += hslen;
					half_space = ON;
				}
			}
			else /* exactly fits, so include this chracter */
			{
				s1_add_blen += mlen;
			}

			/*
			 * turn off string2 processing because string1 already
			 * consumed output_width
			 */
			s2_operate = OFF;

			/* done with string1 */
			break;
		}

		/* accumulate string1's portion of byte-length of the output */
		s1_add_blen += mlen;

		/* advance one character within string1 */
		ptr1 += mlen;

		/* loop counter */
		s1blen -= mlen;
	}

	/* Calculate the length of the portion composed of string2 to use for padding */
	if (s2_operate)
	{
		/* remaining part of output_width is composed of string2 */
		s2_add_width = output_width - s1_width;

		ptr2 = ptr2start = VARDATA_ANY(string2);
		ptr2end = ptr2 + s2blen;

		while (s2_add_width > 0)
		{
			/*  byte-length and display length per character of string2 */
			mlen = pg_mblen(ptr2);
			dsplen = pg_dsplen(ptr2);

			/*
			 * output_width can not fit this character of string2, so discard it and
			 * prepend a half-width space instead
			 */
			if(dsplen > s2_add_width)
			{
				s2_add_blen += hslen;
				half_space = ON;

				/* done with string2 */
				break;
			}

			/* accumulate string2's portion of byte-length of the output */
			s2_add_blen += mlen;

			/* loop counter */
			s2_add_width -= dsplen;

			/* advance one character within string2 */
			ptr2 += mlen;

			/* when get to the end of string2, reset ptr2 to the start */
			if (ptr2 == ptr2end)
				ptr2 = ptr2start;
		}
	}

	/* allocate enough space to contain output_width worth of characters */
	total_blen = s1_add_blen + s2_add_blen;
	ret = (text *) palloc(VARHDRSZ + total_blen);
	ptr_ret = VARDATA(ret);

	/*
	 * add a half-width space as a padding necessary to satisfy the required
	 * output_width
	 *
	 * (memory already allocated as reserved by either s1_add_blen
	 *  or s2_add_blen)
	 */
	if (half_space)
	{
		memcpy(ptr_ret, spc, hslen);
		ptr_ret += hslen;
	}

	/* prepend string2 padding */
	while(s2_add_blen > 0)
	{
		/* reset ptr2 to the string2 start */
		if(init_ptr)
		{
			init_ptr = OFF;
			ptr2 = ptr2start;
		}

		mlen = pg_mblen(ptr2);
		if ( s2_add_blen < mlen )
			break;

		memcpy(ptr_ret, ptr2, mlen);
		ptr_ret += mlen;
		ptr2 += mlen;

		/* loop counter */
		s2_add_blen -= mlen;

		/* when get to the end of string2, reset ptr2 back to the start */
		if (ptr2 == ptr2end)
			ptr2 = ptr2start;
	}

	init_ptr = ON;

	/* string1 */
	while(s1_add_blen > 0)
	{
		/* reset ptr1 back to the start of string1 */
		if(init_ptr)
		{
			init_ptr = OFF;
			ptr1 = VARDATA_ANY(string1);
		}

		mlen = pg_mblen(ptr1);

		if( s1_add_blen < mlen )
			break;

		memcpy(ptr_ret, ptr1, mlen);
		ptr_ret += mlen;
		ptr1 += mlen;

		/* loop counter */
		s1_add_blen -= mlen;
	}

	SET_VARSIZE(ret, ptr_ret - (char *) ret);

	PG_RETURN_TEXT_P(ret);
}

/*
 * orafce_rpad(string text, length int32 [, fill text])
 *
 * Fill up the string to length 'length' by appending
 * the characters fill (a half-width space by default)
 */
Datum
orafce_rpad(PG_FUNCTION_ARGS)
{
	text	*string1 = PG_GETARG_TEXT_PP(0);
	int32	output_width = PG_GETARG_INT32(1);
	text	*string2 = PG_GETARG_TEXT_PP(2);
	text	*ret;
	char	*ptr1,
			*ptr2 = NULL,
			*ptr2start = NULL,
			*ptr2end = NULL,
			*ptr_ret,
			*spc = " ";
	int		mlen,
			dsplen,
			s1blen,
			s2blen,
			hslen,
			total_blen = 0,
			s1_width = 0,
			s2_add_width = 0,
			s1_add_blen = 0,
			s2_add_blen = 0;
	bool	s2_operate = ON,
			half_space = OFF,
			init_ptr = ON;

	/* validate output width (the 2nd argument) */
	if (output_width < 0)
		output_width = 0;
	if (output_width > PAD_MAX)
		output_width = PAD_MAX;

	/* get byte-length of the 1st and 3rd argument strings */
	s1blen = VARSIZE_ANY_EXHDR(string1);
	s2blen = VARSIZE_ANY_EXHDR(string2);

	/* validate the lengths */
	if (s1blen < 0)
		s1blen = 0;
	if (s2blen < 0)
		s2blen = 0;

	/* if the filler length is zero disable filling */
	if (s2blen == 0)
	{
		s2_operate = OFF;	/* turn off string2 processing flag */
		output_width = 0;	/* same behavior as Oracle database */
	}

	/* byte-length of half-width space */
	hslen = pg_mblen(spc);

	/*
	 * Calculate the length of the portion of string1 to include in
	 * the final output
	 */
	ptr1 = VARDATA_ANY(string1);
	while (s1blen > 0)
	{
		/* byte-length and display length per character of string1 */
		mlen = pg_mblen(ptr1);
		dsplen = pg_dsplen(ptr1);

		/* accumulate display length of string1 */
		s1_width += dsplen;

		/*
		 * if string1 is longer/wider than the requested output_width,
		 * discard this character and prepend a half-width space instead
		 */
		if(s1_width >= output_width)
		{
			if(s1_width != output_width)
			{
				/* secure bytes for a half-width space in the final output */
				if (output_width != 0)
				{
					s1_add_blen += hslen;
					half_space = ON;
				}
			}
			else /* exactly fits, so include this chracter */
			{
				s1_add_blen += mlen;
			}

			/*
			 * turn off string2 processing because string1 already
			 * consumed output_width
			 */
			s2_operate = OFF;

			/* done with string1 */
			break;
		}

		/* accumulate string1's portion of byte-length of the output */
		s1_add_blen += mlen;

		/* advance one character within string1 */
		ptr1 += mlen;

		/* loop counter */
		s1blen -= mlen;
	}

	/* Calculate the length of the portion composed of string2 to use for padding */
	if (s2_operate)
	{
		/* remaining part of output_width is composed of string2 */
		s2_add_width = output_width - s1_width;

		ptr2 = ptr2start = VARDATA_ANY(string2);
		ptr2end = ptr2 + s2blen;

		while (s2_add_width > 0)
		{
			/*  byte-length and display length per character of string2 */
			mlen = pg_mblen(ptr2);
			dsplen = pg_dsplen(ptr2);

			/*
			 * output_width can not fit this character of string2, so discard it and
			 * prepend a half-width space instead
			 */
			if(dsplen > s2_add_width)
			{
				s2_add_blen += hslen;
				half_space = ON;

				/* done with string2 */
				break;
			}

			/* accumulate string2's portion of byte-length of the output */
			s2_add_blen += mlen;

			/* loop counter */
			s2_add_width -= dsplen;

			/* advance one character within string2 */
			ptr2 += mlen;

			/* when get to the end of string2, reset ptr2 to the start */
			if (ptr2 == ptr2end)
				ptr2 = ptr2start;
		}
	}

	/* allocate enough space to contain output_width worth of characters */
	total_blen = s1_add_blen + s2_add_blen;
	ret = (text *) palloc(VARHDRSZ + total_blen);
	ptr_ret = VARDATA(ret);

	/* string1 */
	while(s1_add_blen > 0)
	{
		/* reset ptr1 back to the start of string1 */
		if(init_ptr)
		{
			init_ptr = OFF;
			ptr1 = VARDATA_ANY(string1);
		}

		mlen = pg_mblen(ptr1);

		if( s1_add_blen < mlen )
			break;

		memcpy(ptr_ret, ptr1, mlen);
		ptr_ret += mlen;
		ptr1 += mlen;

		/* loop counter */
		s1_add_blen -= mlen;
	}

	init_ptr = ON;

	/* append string2 padding */
	while(s2_add_blen > 0)
	{
		/* reset ptr2 to the string2 start */
		if(init_ptr)
		{
			init_ptr = OFF;
			ptr2 = ptr2start;
		}

		mlen = pg_mblen(ptr2);
		if ( s2_add_blen < mlen )
			break;

		memcpy(ptr_ret, ptr2, mlen);
		ptr_ret += mlen;
		ptr2 += mlen;

		/* loop counter */
		s2_add_blen -= mlen;

		/* when get to the end of string2, reset ptr2 back to the start */
		if (ptr2 == ptr2end)
			ptr2 = ptr2start;
	}

	/*
	 * add a half-width space as a padding necessary to satisfy the required
	 * output_width
	 *
	 * (memory already allocated as reserved by either s1_add_blen
	 *  or s2_add_blen)
	 */
	if (half_space)
	{
		memcpy(ptr_ret, spc, hslen);
		ptr_ret += hslen;
	}

	SET_VARSIZE(ret, ptr_ret - (char *) ret);

	PG_RETURN_TEXT_P(ret);
}

相关信息

greenplumn 源码目录

相关文章

greenplumn aggregate 源码

greenplumn alert 源码

greenplumn assert 源码

greenplumn assert 源码

greenplumn builtins 源码

greenplumn charlen 源码

greenplumn convert 源码

greenplumn datefce 源码

greenplumn file 源码

greenplumn magic 源码

0  赞