*
* 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"
#define ON true
#define OFF false
#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 = NULL;
errno_t sret;
char *ptr1 = NULL,
*ptr2 = NULL,
*ptr2start = NULL,
*ptr2end = NULL,
*ptr_ret = NULL,
*spc = " ";
int mlen,
dsplen,
s1blen,
s2blen,
hslen,
total_blen = 0,
s1_width = 0,
s1_add_blen = 0,
s2_add_blen = 0;
bool s2_operate = ON,
half_space = OFF,
init_ptr = ON;
if (output_width < 0)
output_width = 0;
if (output_width > PAD_MAX)
output_width = PAD_MAX;
s1blen = VARSIZE_ANY_EXHDR(string1);
s2blen = VARSIZE_ANY_EXHDR(string2);
if (s1blen < 0)
s1blen = 0;
if (s2blen < 0)
s2blen = 0;
if (s2blen == 0)
{
s2_operate = OFF;
output_width = 0;
}
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)
{
mlen = pg_mblen(ptr1);
dsplen = pg_dsplen(ptr1);
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)
{
if (output_width != 0)
{
s1_add_blen += hslen;
half_space = ON;
}
}
else
{
s1_add_blen += mlen;
}
* turn off string2 processing because string1 already
* consumed output_width
*/
s2_operate = OFF;
break;
}
s1_add_blen += mlen;
ptr1 += mlen;
s1blen -= mlen;
}
if (s2_operate)
{
int s2_add_width = 0;
s2_add_width = output_width - s1_width;
ptr2 = ptr2start = VARDATA_ANY(string2);
ptr2end = ptr2 + s2blen;
while (s2_add_width > 0)
{
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;
break;
}
s2_add_blen += mlen;
s2_add_width -= dsplen;
ptr2 += mlen;
if (ptr2 == ptr2end)
ptr2 = ptr2start;
}
}
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)
{
sret = memcpy_s(ptr_ret, hslen, spc, hslen);
securec_check(sret, "", "");
ptr_ret += hslen;
}
while(s2_add_blen > 0)
{
if(init_ptr)
{
init_ptr = OFF;
ptr2 = ptr2start;
}
mlen = pg_mblen(ptr2);
if ( s2_add_blen < mlen )
break;
sret = memcpy_s(ptr_ret, mlen, ptr2, mlen);
securec_check(sret, "", "");
ptr_ret += mlen;
ptr2 += mlen;
s2_add_blen -= mlen;
if (ptr2 == ptr2end)
ptr2 = ptr2start;
}
init_ptr = ON;
while(s1_add_blen > 0)
{
if(init_ptr)
{
init_ptr = OFF;
ptr1 = VARDATA_ANY(string1);
}
mlen = pg_mblen(ptr1);
if( s1_add_blen < mlen )
break;
sret = memcpy_s(ptr_ret, mlen, ptr1, mlen);
securec_check(sret, "", "");
ptr_ret += mlen;
ptr1 += mlen;
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,
s1_add_blen = 0,
s2_add_blen = 0;
bool s2_operate = ON,
half_space = OFF,
init_ptr = ON;
errno_t sret;
if (output_width < 0)
output_width = 0;
if (output_width > PAD_MAX)
output_width = PAD_MAX;
s1blen = VARSIZE_ANY_EXHDR(string1);
s2blen = VARSIZE_ANY_EXHDR(string2);
if (s1blen < 0)
s1blen = 0;
if (s2blen < 0)
s2blen = 0;
if (s2blen == 0)
{
s2_operate = OFF;
output_width = 0;
}
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)
{
mlen = pg_mblen(ptr1);
dsplen = pg_dsplen(ptr1);
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)
{
if (output_width != 0)
{
s1_add_blen += hslen;
half_space = ON;
}
}
else
{
s1_add_blen += mlen;
}
* turn off string2 processing because string1 already
* consumed output_width
*/
s2_operate = OFF;
break;
}
s1_add_blen += mlen;
ptr1 += mlen;
s1blen -= mlen;
}
if (s2_operate)
{
int s2_add_width = 0;
s2_add_width = output_width - s1_width;
ptr2 = ptr2start = VARDATA_ANY(string2);
ptr2end = ptr2 + s2blen;
while (s2_add_width > 0)
{
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;
break;
}
s2_add_blen += mlen;
s2_add_width -= dsplen;
ptr2 += mlen;
if (ptr2 == ptr2end)
ptr2 = ptr2start;
}
}
total_blen = s1_add_blen + s2_add_blen;
ret = (text *) palloc(VARHDRSZ + total_blen);
ptr_ret = VARDATA(ret);
while(s1_add_blen > 0)
{
if(init_ptr)
{
init_ptr = OFF;
ptr1 = VARDATA_ANY(string1);
}
mlen = pg_mblen(ptr1);
if( s1_add_blen < mlen )
break;
sret = memcpy_s(ptr_ret, mlen, ptr1, mlen);
securec_check(sret, "", "");
ptr_ret += mlen;
ptr1 += mlen;
s1_add_blen -= mlen;
}
init_ptr = ON;
while(s2_add_blen > 0)
{
if(init_ptr)
{
init_ptr = OFF;
ptr2 = ptr2start;
}
mlen = pg_mblen(ptr2);
if ( s2_add_blen < mlen )
break;
sret = memcpy_s(ptr_ret, mlen, ptr2, mlen);
securec_check(sret, "", "");
ptr_ret += mlen;
ptr2 += mlen;
s2_add_blen -= mlen;
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)
{
sret = memcpy_s(ptr_ret, hslen, spc, hslen);
securec_check(sret, "", "");
ptr_ret += hslen;
}
SET_VARSIZE(ret, ptr_ret - (char *) ret);
PG_RETURN_TEXT_P(ret);
}