LCOV - code coverage report
Current view: top level - src/backend/utils/adt - oracle_compat.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 302 372 81.2 %
Date: 2017-09-29 13:40:31 Functions: 17 17 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  * oracle_compat.c
       3             :  *  Oracle compatible functions.
       4             :  *
       5             :  * Copyright (c) 1996-2017, PostgreSQL Global Development Group
       6             :  *
       7             :  *  Author: Edmund Mergl <E.Mergl@bawue.de>
       8             :  *  Multibyte enhancement: Tatsuo Ishii <ishii@postgresql.org>
       9             :  *
      10             :  *
      11             :  * IDENTIFICATION
      12             :  *  src/backend/utils/adt/oracle_compat.c
      13             :  *
      14             :  *-------------------------------------------------------------------------
      15             :  */
      16             : #include "postgres.h"
      17             : 
      18             : #include "utils/builtins.h"
      19             : #include "utils/formatting.h"
      20             : #include "mb/pg_wchar.h"
      21             : 
      22             : 
      23             : static text *dotrim(const char *string, int stringlen,
      24             :        const char *set, int setlen,
      25             :        bool doltrim, bool dortrim);
      26             : 
      27             : 
      28             : /********************************************************************
      29             :  *
      30             :  * lower
      31             :  *
      32             :  * Syntax:
      33             :  *
      34             :  *   text lower(text string)
      35             :  *
      36             :  * Purpose:
      37             :  *
      38             :  *   Returns string, with all letters forced to lowercase.
      39             :  *
      40             :  ********************************************************************/
      41             : 
      42             : Datum
      43         190 : lower(PG_FUNCTION_ARGS)
      44             : {
      45         190 :     text       *in_string = PG_GETARG_TEXT_PP(0);
      46             :     char       *out_string;
      47             :     text       *result;
      48             : 
      49         570 :     out_string = str_tolower(VARDATA_ANY(in_string),
      50         380 :                              VARSIZE_ANY_EXHDR(in_string),
      51             :                              PG_GET_COLLATION());
      52         190 :     result = cstring_to_text(out_string);
      53         190 :     pfree(out_string);
      54             : 
      55         190 :     PG_RETURN_TEXT_P(result);
      56             : }
      57             : 
      58             : 
      59             : /********************************************************************
      60             :  *
      61             :  * upper
      62             :  *
      63             :  * Syntax:
      64             :  *
      65             :  *   text upper(text string)
      66             :  *
      67             :  * Purpose:
      68             :  *
      69             :  *   Returns string, with all letters forced to uppercase.
      70             :  *
      71             :  ********************************************************************/
      72             : 
      73             : Datum
      74          56 : upper(PG_FUNCTION_ARGS)
      75             : {
      76          56 :     text       *in_string = PG_GETARG_TEXT_PP(0);
      77             :     char       *out_string;
      78             :     text       *result;
      79             : 
      80         168 :     out_string = str_toupper(VARDATA_ANY(in_string),
      81         112 :                              VARSIZE_ANY_EXHDR(in_string),
      82             :                              PG_GET_COLLATION());
      83          56 :     result = cstring_to_text(out_string);
      84          56 :     pfree(out_string);
      85             : 
      86          56 :     PG_RETURN_TEXT_P(result);
      87             : }
      88             : 
      89             : 
      90             : /********************************************************************
      91             :  *
      92             :  * initcap
      93             :  *
      94             :  * Syntax:
      95             :  *
      96             :  *   text initcap(text string)
      97             :  *
      98             :  * Purpose:
      99             :  *
     100             :  *   Returns string, with first letter of each word in uppercase, all
     101             :  *   other letters in lowercase. A word is defined as a sequence of
     102             :  *   alphanumeric characters, delimited by non-alphanumeric
     103             :  *   characters.
     104             :  *
     105             :  ********************************************************************/
     106             : 
     107             : Datum
     108           5 : initcap(PG_FUNCTION_ARGS)
     109             : {
     110           5 :     text       *in_string = PG_GETARG_TEXT_PP(0);
     111             :     char       *out_string;
     112             :     text       *result;
     113             : 
     114          15 :     out_string = str_initcap(VARDATA_ANY(in_string),
     115          10 :                              VARSIZE_ANY_EXHDR(in_string),
     116             :                              PG_GET_COLLATION());
     117           5 :     result = cstring_to_text(out_string);
     118           5 :     pfree(out_string);
     119             : 
     120           5 :     PG_RETURN_TEXT_P(result);
     121             : }
     122             : 
     123             : 
     124             : /********************************************************************
     125             :  *
     126             :  * lpad
     127             :  *
     128             :  * Syntax:
     129             :  *
     130             :  *   text lpad(text string1, int4 len, text string2)
     131             :  *
     132             :  * Purpose:
     133             :  *
     134             :  *   Returns string1, left-padded to length len with the sequence of
     135             :  *   characters in string2.  If len is less than the length of string1,
     136             :  *   instead truncate (on the right) to len.
     137             :  *
     138             :  ********************************************************************/
     139             : 
     140             : Datum
     141           5 : lpad(PG_FUNCTION_ARGS)
     142             : {
     143           5 :     text       *string1 = PG_GETARG_TEXT_PP(0);
     144           5 :     int32       len = PG_GETARG_INT32(1);
     145           5 :     text       *string2 = PG_GETARG_TEXT_PP(2);
     146             :     text       *ret;
     147             :     char       *ptr1,
     148             :                *ptr2,
     149             :                *ptr2start,
     150             :                *ptr2end,
     151             :                *ptr_ret;
     152             :     int         m,
     153             :                 s1len,
     154             :                 s2len;
     155             : 
     156             :     int         bytelen;
     157             : 
     158             :     /* Negative len is silently taken as zero */
     159           5 :     if (len < 0)
     160           1 :         len = 0;
     161             : 
     162           5 :     s1len = VARSIZE_ANY_EXHDR(string1);
     163           5 :     if (s1len < 0)
     164           0 :         s1len = 0;              /* shouldn't happen */
     165             : 
     166           5 :     s2len = VARSIZE_ANY_EXHDR(string2);
     167           5 :     if (s2len < 0)
     168           0 :         s2len = 0;              /* shouldn't happen */
     169             : 
     170           5 :     s1len = pg_mbstrlen_with_len(VARDATA_ANY(string1), s1len);
     171             : 
     172           5 :     if (s1len > len)
     173           2 :         s1len = len;            /* truncate string1 to len chars */
     174             : 
     175           5 :     if (s2len <= 0)
     176           1 :         len = s1len;            /* nothing to pad with, so don't pad */
     177             : 
     178           5 :     bytelen = pg_database_encoding_max_length() * len;
     179             : 
     180             :     /* check for integer overflow */
     181           5 :     if (len != 0 && bytelen / pg_database_encoding_max_length() != len)
     182           0 :         ereport(ERROR,
     183             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     184             :                  errmsg("requested length too large")));
     185             : 
     186           5 :     ret = (text *) palloc(VARHDRSZ + bytelen);
     187             : 
     188           5 :     m = len - s1len;
     189             : 
     190           5 :     ptr2 = ptr2start = VARDATA_ANY(string2);
     191           5 :     ptr2end = ptr2 + s2len;
     192           5 :     ptr_ret = VARDATA(ret);
     193             : 
     194          16 :     while (m--)
     195             :     {
     196           6 :         int         mlen = pg_mblen(ptr2);
     197             : 
     198           6 :         memcpy(ptr_ret, ptr2, mlen);
     199           6 :         ptr_ret += mlen;
     200           6 :         ptr2 += mlen;
     201           6 :         if (ptr2 == ptr2end)    /* wrap around at end of s2 */
     202           4 :             ptr2 = ptr2start;
     203             :     }
     204             : 
     205           5 :     ptr1 = VARDATA_ANY(string1);
     206             : 
     207          18 :     while (s1len--)
     208             :     {
     209           8 :         int         mlen = pg_mblen(ptr1);
     210             : 
     211           8 :         memcpy(ptr_ret, ptr1, mlen);
     212           8 :         ptr_ret += mlen;
     213           8 :         ptr1 += mlen;
     214             :     }
     215             : 
     216           5 :     SET_VARSIZE(ret, ptr_ret - (char *) ret);
     217             : 
     218           5 :     PG_RETURN_TEXT_P(ret);
     219             : }
     220             : 
     221             : 
     222             : /********************************************************************
     223             :  *
     224             :  * rpad
     225             :  *
     226             :  * Syntax:
     227             :  *
     228             :  *   text rpad(text string1, int4 len, text string2)
     229             :  *
     230             :  * Purpose:
     231             :  *
     232             :  *   Returns string1, right-padded to length len with the sequence of
     233             :  *   characters in string2.  If len is less than the length of string1,
     234             :  *   instead truncate (on the right) to len.
     235             :  *
     236             :  ********************************************************************/
     237             : 
     238             : Datum
     239           5 : rpad(PG_FUNCTION_ARGS)
     240             : {
     241           5 :     text       *string1 = PG_GETARG_TEXT_PP(0);
     242           5 :     int32       len = PG_GETARG_INT32(1);
     243           5 :     text       *string2 = PG_GETARG_TEXT_PP(2);
     244             :     text       *ret;
     245             :     char       *ptr1,
     246             :                *ptr2,
     247             :                *ptr2start,
     248             :                *ptr2end,
     249             :                *ptr_ret;
     250             :     int         m,
     251             :                 s1len,
     252             :                 s2len;
     253             : 
     254             :     int         bytelen;
     255             : 
     256             :     /* Negative len is silently taken as zero */
     257           5 :     if (len < 0)
     258           1 :         len = 0;
     259             : 
     260           5 :     s1len = VARSIZE_ANY_EXHDR(string1);
     261           5 :     if (s1len < 0)
     262           0 :         s1len = 0;              /* shouldn't happen */
     263             : 
     264           5 :     s2len = VARSIZE_ANY_EXHDR(string2);
     265           5 :     if (s2len < 0)
     266           0 :         s2len = 0;              /* shouldn't happen */
     267             : 
     268           5 :     s1len = pg_mbstrlen_with_len(VARDATA_ANY(string1), s1len);
     269             : 
     270           5 :     if (s1len > len)
     271           2 :         s1len = len;            /* truncate string1 to len chars */
     272             : 
     273           5 :     if (s2len <= 0)
     274           1 :         len = s1len;            /* nothing to pad with, so don't pad */
     275             : 
     276           5 :     bytelen = pg_database_encoding_max_length() * len;
     277             : 
     278             :     /* Check for integer overflow */
     279           5 :     if (len != 0 && bytelen / pg_database_encoding_max_length() != len)
     280           0 :         ereport(ERROR,
     281             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     282             :                  errmsg("requested length too large")));
     283             : 
     284           5 :     ret = (text *) palloc(VARHDRSZ + bytelen);
     285           5 :     m = len - s1len;
     286             : 
     287           5 :     ptr1 = VARDATA_ANY(string1);
     288           5 :     ptr_ret = VARDATA(ret);
     289             : 
     290          18 :     while (s1len--)
     291             :     {
     292           8 :         int         mlen = pg_mblen(ptr1);
     293             : 
     294           8 :         memcpy(ptr_ret, ptr1, mlen);
     295           8 :         ptr_ret += mlen;
     296           8 :         ptr1 += mlen;
     297             :     }
     298             : 
     299           5 :     ptr2 = ptr2start = VARDATA_ANY(string2);
     300           5 :     ptr2end = ptr2 + s2len;
     301             : 
     302          16 :     while (m--)
     303             :     {
     304           6 :         int         mlen = pg_mblen(ptr2);
     305             : 
     306           6 :         memcpy(ptr_ret, ptr2, mlen);
     307           6 :         ptr_ret += mlen;
     308           6 :         ptr2 += mlen;
     309           6 :         if (ptr2 == ptr2end)    /* wrap around at end of s2 */
     310           4 :             ptr2 = ptr2start;
     311             :     }
     312             : 
     313           5 :     SET_VARSIZE(ret, ptr_ret - (char *) ret);
     314             : 
     315           5 :     PG_RETURN_TEXT_P(ret);
     316             : }
     317             : 
     318             : 
     319             : /********************************************************************
     320             :  *
     321             :  * btrim
     322             :  *
     323             :  * Syntax:
     324             :  *
     325             :  *   text btrim(text string, text set)
     326             :  *
     327             :  * Purpose:
     328             :  *
     329             :  *   Returns string with characters removed from the front and back
     330             :  *   up to the first character not in set.
     331             :  *
     332             :  ********************************************************************/
     333             : 
     334             : Datum
     335           1 : btrim(PG_FUNCTION_ARGS)
     336             : {
     337           1 :     text       *string = PG_GETARG_TEXT_PP(0);
     338           1 :     text       *set = PG_GETARG_TEXT_PP(1);
     339             :     text       *ret;
     340             : 
     341           4 :     ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
     342           4 :                  VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
     343             :                  true, true);
     344             : 
     345           1 :     PG_RETURN_TEXT_P(ret);
     346             : }
     347             : 
     348             : /********************************************************************
     349             :  *
     350             :  * btrim1 --- btrim with set fixed as ' '
     351             :  *
     352             :  ********************************************************************/
     353             : 
     354             : Datum
     355          93 : btrim1(PG_FUNCTION_ARGS)
     356             : {
     357          93 :     text       *string = PG_GETARG_TEXT_PP(0);
     358             :     text       *ret;
     359             : 
     360          93 :     ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
     361             :                  " ", 1,
     362             :                  true, true);
     363             : 
     364          93 :     PG_RETURN_TEXT_P(ret);
     365             : }
     366             : 
     367             : /*
     368             :  * Common implementation for btrim, ltrim, rtrim
     369             :  */
     370             : static text *
     371         951 : dotrim(const char *string, int stringlen,
     372             :        const char *set, int setlen,
     373             :        bool doltrim, bool dortrim)
     374             : {
     375             :     int         i;
     376             : 
     377             :     /* Nothing to do if either string or set is empty */
     378         951 :     if (stringlen > 0 && setlen > 0)
     379             :     {
     380         951 :         if (pg_database_encoding_max_length() > 1)
     381             :         {
     382             :             /*
     383             :              * In the multibyte-encoding case, build arrays of pointers to
     384             :              * character starts, so that we can avoid inefficient checks in
     385             :              * the inner loops.
     386             :              */
     387             :             const char **stringchars;
     388             :             const char **setchars;
     389             :             int        *stringmblen;
     390             :             int        *setmblen;
     391             :             int         stringnchars;
     392             :             int         setnchars;
     393             :             int         resultndx;
     394             :             int         resultnchars;
     395             :             const char *p;
     396             :             int         len;
     397             :             int         mblen;
     398             :             const char *str_pos;
     399             :             int         str_len;
     400             : 
     401         951 :             stringchars = (const char **) palloc(stringlen * sizeof(char *));
     402         951 :             stringmblen = (int *) palloc(stringlen * sizeof(int));
     403         951 :             stringnchars = 0;
     404         951 :             p = string;
     405         951 :             len = stringlen;
     406       20880 :             while (len > 0)
     407             :             {
     408       18978 :                 stringchars[stringnchars] = p;
     409       18978 :                 stringmblen[stringnchars] = mblen = pg_mblen(p);
     410       18978 :                 stringnchars++;
     411       18978 :                 p += mblen;
     412       18978 :                 len -= mblen;
     413             :             }
     414             : 
     415         951 :             setchars = (const char **) palloc(setlen * sizeof(char *));
     416         951 :             setmblen = (int *) palloc(setlen * sizeof(int));
     417         951 :             setnchars = 0;
     418         951 :             p = set;
     419         951 :             len = setlen;
     420        2855 :             while (len > 0)
     421             :             {
     422         953 :                 setchars[setnchars] = p;
     423         953 :                 setmblen[setnchars] = mblen = pg_mblen(p);
     424         953 :                 setnchars++;
     425         953 :                 p += mblen;
     426         953 :                 len -= mblen;
     427             :             }
     428             : 
     429         951 :             resultndx = 0;      /* index in stringchars[] */
     430         951 :             resultnchars = stringnchars;
     431             : 
     432         951 :             if (doltrim)
     433             :             {
     434         205 :                 while (resultnchars > 0)
     435             :                 {
     436         109 :                     str_pos = stringchars[resultndx];
     437         109 :                     str_len = stringmblen[resultndx];
     438         214 :                     for (i = 0; i < setnchars; i++)
     439             :                     {
     440         236 :                         if (str_len == setmblen[i] &&
     441         118 :                             memcmp(str_pos, setchars[i], str_len) == 0)
     442          13 :                             break;
     443             :                     }
     444         109 :                     if (i >= setnchars)
     445          96 :                         break;  /* no match here */
     446          13 :                     string += str_len;
     447          13 :                     stringlen -= str_len;
     448          13 :                     resultndx++;
     449          13 :                     resultnchars--;
     450             :                 }
     451             :             }
     452             : 
     453         951 :             if (dortrim)
     454             :             {
     455       12477 :                 while (resultnchars > 0)
     456             :                 {
     457       11528 :                     str_pos = stringchars[resultndx + resultnchars - 1];
     458       11528 :                     str_len = stringmblen[resultndx + resultnchars - 1];
     459       12477 :                     for (i = 0; i < setnchars; i++)
     460             :                     {
     461       23056 :                         if (str_len == setmblen[i] &&
     462       11528 :                             memcmp(str_pos, setchars[i], str_len) == 0)
     463       10579 :                             break;
     464             :                     }
     465       11528 :                     if (i >= setnchars)
     466         949 :                         break;  /* no match here */
     467       10579 :                     stringlen -= str_len;
     468       10579 :                     resultnchars--;
     469             :                 }
     470             :             }
     471             : 
     472         951 :             pfree(stringchars);
     473         951 :             pfree(stringmblen);
     474         951 :             pfree(setchars);
     475         951 :             pfree(setmblen);
     476             :         }
     477             :         else
     478             :         {
     479             :             /*
     480             :              * In the single-byte-encoding case, we don't need such overhead.
     481             :              */
     482           0 :             if (doltrim)
     483             :             {
     484           0 :                 while (stringlen > 0)
     485             :                 {
     486           0 :                     char        str_ch = *string;
     487             : 
     488           0 :                     for (i = 0; i < setlen; i++)
     489             :                     {
     490           0 :                         if (str_ch == set[i])
     491           0 :                             break;
     492             :                     }
     493           0 :                     if (i >= setlen)
     494           0 :                         break;  /* no match here */
     495           0 :                     string++;
     496           0 :                     stringlen--;
     497             :                 }
     498             :             }
     499             : 
     500           0 :             if (dortrim)
     501             :             {
     502           0 :                 while (stringlen > 0)
     503             :                 {
     504           0 :                     char        str_ch = string[stringlen - 1];
     505             : 
     506           0 :                     for (i = 0; i < setlen; i++)
     507             :                     {
     508           0 :                         if (str_ch == set[i])
     509           0 :                             break;
     510             :                     }
     511           0 :                     if (i >= setlen)
     512           0 :                         break;  /* no match here */
     513           0 :                     stringlen--;
     514             :                 }
     515             :             }
     516             :         }
     517             :     }
     518             : 
     519             :     /* Return selected portion of string */
     520         951 :     return cstring_to_text_with_len(string, stringlen);
     521             : }
     522             : 
     523             : /********************************************************************
     524             :  *
     525             :  * byteatrim
     526             :  *
     527             :  * Syntax:
     528             :  *
     529             :  *   bytea byteatrim(byta string, bytea set)
     530             :  *
     531             :  * Purpose:
     532             :  *
     533             :  *   Returns string with characters removed from the front and back
     534             :  *   up to the first character not in set.
     535             :  *
     536             :  * Cloned from btrim and modified as required.
     537             :  ********************************************************************/
     538             : 
     539             : Datum
     540           4 : byteatrim(PG_FUNCTION_ARGS)
     541             : {
     542           4 :     bytea      *string = PG_GETARG_BYTEA_PP(0);
     543           4 :     bytea      *set = PG_GETARG_BYTEA_PP(1);
     544             :     bytea      *ret;
     545             :     char       *ptr,
     546             :                *end,
     547             :                *ptr2,
     548             :                *ptr2start,
     549             :                *end2;
     550             :     int         m,
     551             :                 stringlen,
     552             :                 setlen;
     553             : 
     554           4 :     stringlen = VARSIZE_ANY_EXHDR(string);
     555           4 :     setlen = VARSIZE_ANY_EXHDR(set);
     556             : 
     557           4 :     if (stringlen <= 0 || setlen <= 0)
     558           2 :         PG_RETURN_BYTEA_P(string);
     559             : 
     560           2 :     m = stringlen;
     561           2 :     ptr = VARDATA_ANY(string);
     562           2 :     end = ptr + stringlen - 1;
     563           2 :     ptr2start = VARDATA_ANY(set);
     564           2 :     end2 = ptr2start + setlen - 1;
     565             : 
     566           6 :     while (m > 0)
     567             :     {
     568           4 :         ptr2 = ptr2start;
     569          10 :         while (ptr2 <= end2)
     570             :         {
     571           4 :             if (*ptr == *ptr2)
     572           2 :                 break;
     573           2 :             ++ptr2;
     574             :         }
     575           4 :         if (ptr2 > end2)
     576           2 :             break;
     577           2 :         ptr++;
     578           2 :         m--;
     579             :     }
     580             : 
     581           6 :     while (m > 0)
     582             :     {
     583           4 :         ptr2 = ptr2start;
     584          10 :         while (ptr2 <= end2)
     585             :         {
     586           4 :             if (*end == *ptr2)
     587           2 :                 break;
     588           2 :             ++ptr2;
     589             :         }
     590           4 :         if (ptr2 > end2)
     591           2 :             break;
     592           2 :         end--;
     593           2 :         m--;
     594             :     }
     595             : 
     596           2 :     ret = (bytea *) palloc(VARHDRSZ + m);
     597           2 :     SET_VARSIZE(ret, VARHDRSZ + m);
     598           2 :     memcpy(VARDATA(ret), ptr, m);
     599             : 
     600           2 :     PG_RETURN_BYTEA_P(ret);
     601             : }
     602             : 
     603             : /********************************************************************
     604             :  *
     605             :  * ltrim
     606             :  *
     607             :  * Syntax:
     608             :  *
     609             :  *   text ltrim(text string, text set)
     610             :  *
     611             :  * Purpose:
     612             :  *
     613             :  *   Returns string with initial characters removed up to the first
     614             :  *   character not in set.
     615             :  *
     616             :  ********************************************************************/
     617             : 
     618             : Datum
     619           1 : ltrim(PG_FUNCTION_ARGS)
     620             : {
     621           1 :     text       *string = PG_GETARG_TEXT_PP(0);
     622           1 :     text       *set = PG_GETARG_TEXT_PP(1);
     623             :     text       *ret;
     624             : 
     625           4 :     ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
     626           4 :                  VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
     627             :                  true, false);
     628             : 
     629           1 :     PG_RETURN_TEXT_P(ret);
     630             : }
     631             : 
     632             : /********************************************************************
     633             :  *
     634             :  * ltrim1 --- ltrim with set fixed as ' '
     635             :  *
     636             :  ********************************************************************/
     637             : 
     638             : Datum
     639           1 : ltrim1(PG_FUNCTION_ARGS)
     640             : {
     641           1 :     text       *string = PG_GETARG_TEXT_PP(0);
     642             :     text       *ret;
     643             : 
     644           1 :     ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
     645             :                  " ", 1,
     646             :                  true, false);
     647             : 
     648           1 :     PG_RETURN_TEXT_P(ret);
     649             : }
     650             : 
     651             : /********************************************************************
     652             :  *
     653             :  * rtrim
     654             :  *
     655             :  * Syntax:
     656             :  *
     657             :  *   text rtrim(text string, text set)
     658             :  *
     659             :  * Purpose:
     660             :  *
     661             :  *   Returns string with final characters removed after the last
     662             :  *   character not in set.
     663             :  *
     664             :  ********************************************************************/
     665             : 
     666             : Datum
     667          14 : rtrim(PG_FUNCTION_ARGS)
     668             : {
     669          14 :     text       *string = PG_GETARG_TEXT_PP(0);
     670          14 :     text       *set = PG_GETARG_TEXT_PP(1);
     671             :     text       *ret;
     672             : 
     673          56 :     ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
     674          56 :                  VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
     675             :                  false, true);
     676             : 
     677          14 :     PG_RETURN_TEXT_P(ret);
     678             : }
     679             : 
     680             : /********************************************************************
     681             :  *
     682             :  * rtrim1 --- rtrim with set fixed as ' '
     683             :  *
     684             :  ********************************************************************/
     685             : 
     686             : Datum
     687         841 : rtrim1(PG_FUNCTION_ARGS)
     688             : {
     689         841 :     text       *string = PG_GETARG_TEXT_PP(0);
     690             :     text       *ret;
     691             : 
     692         841 :     ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
     693             :                  " ", 1,
     694             :                  false, true);
     695             : 
     696         841 :     PG_RETURN_TEXT_P(ret);
     697             : }
     698             : 
     699             : 
     700             : /********************************************************************
     701             :  *
     702             :  * translate
     703             :  *
     704             :  * Syntax:
     705             :  *
     706             :  *   text translate(text string, text from, text to)
     707             :  *
     708             :  * Purpose:
     709             :  *
     710             :  *   Returns string after replacing all occurrences of characters in from
     711             :  *   with the corresponding character in to.  If from is longer than to,
     712             :  *   occurrences of the extra characters in from are deleted.
     713             :  *   Improved by Edwin Ramirez <ramirez@doc.mssm.edu>.
     714             :  *
     715             :  ********************************************************************/
     716             : 
     717             : Datum
     718           2 : translate(PG_FUNCTION_ARGS)
     719             : {
     720           2 :     text       *string = PG_GETARG_TEXT_PP(0);
     721           2 :     text       *from = PG_GETARG_TEXT_PP(1);
     722           2 :     text       *to = PG_GETARG_TEXT_PP(2);
     723             :     text       *result;
     724             :     char       *from_ptr,
     725             :                *to_ptr;
     726             :     char       *source,
     727             :                *target;
     728             :     int         m,
     729             :                 fromlen,
     730             :                 tolen,
     731             :                 retlen,
     732             :                 i;
     733             :     int         worst_len;
     734             :     int         len;
     735             :     int         source_len;
     736             :     int         from_index;
     737             : 
     738           2 :     m = VARSIZE_ANY_EXHDR(string);
     739           2 :     if (m <= 0)
     740           1 :         PG_RETURN_TEXT_P(string);
     741           1 :     source = VARDATA_ANY(string);
     742             : 
     743           1 :     fromlen = VARSIZE_ANY_EXHDR(from);
     744           1 :     from_ptr = VARDATA_ANY(from);
     745           1 :     tolen = VARSIZE_ANY_EXHDR(to);
     746           1 :     to_ptr = VARDATA_ANY(to);
     747             : 
     748             :     /*
     749             :      * The worst-case expansion is to substitute a max-length character for a
     750             :      * single-byte character at each position of the string.
     751             :      */
     752           1 :     worst_len = pg_database_encoding_max_length() * m;
     753             : 
     754             :     /* check for integer overflow */
     755           1 :     if (worst_len / pg_database_encoding_max_length() != m)
     756           0 :         ereport(ERROR,
     757             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     758             :                  errmsg("requested length too large")));
     759             : 
     760           1 :     result = (text *) palloc(worst_len + VARHDRSZ);
     761           1 :     target = VARDATA(result);
     762           1 :     retlen = 0;
     763             : 
     764           7 :     while (m > 0)
     765             :     {
     766           5 :         source_len = pg_mblen(source);
     767           5 :         from_index = 0;
     768             : 
     769          12 :         for (i = 0; i < fromlen; i += len)
     770             :         {
     771           9 :             len = pg_mblen(&from_ptr[i]);
     772          18 :             if (len == source_len &&
     773           9 :                 memcmp(source, &from_ptr[i], len) == 0)
     774           2 :                 break;
     775             : 
     776           7 :             from_index++;
     777             :         }
     778           5 :         if (i < fromlen)
     779             :         {
     780             :             /* substitute */
     781           2 :             char       *p = to_ptr;
     782             : 
     783           3 :             for (i = 0; i < from_index; i++)
     784             :             {
     785           1 :                 p += pg_mblen(p);
     786           1 :                 if (p >= (to_ptr + tolen))
     787           0 :                     break;
     788             :             }
     789           2 :             if (p < (to_ptr + tolen))
     790             :             {
     791           2 :                 len = pg_mblen(p);
     792           2 :                 memcpy(target, p, len);
     793           2 :                 target += len;
     794           2 :                 retlen += len;
     795             :             }
     796             : 
     797             :         }
     798             :         else
     799             :         {
     800             :             /* no match, so copy */
     801           3 :             memcpy(target, source, source_len);
     802           3 :             target += source_len;
     803           3 :             retlen += source_len;
     804             :         }
     805             : 
     806           5 :         source += source_len;
     807           5 :         m -= source_len;
     808             :     }
     809             : 
     810           1 :     SET_VARSIZE(result, retlen + VARHDRSZ);
     811             : 
     812             :     /*
     813             :      * The function result is probably much bigger than needed, if we're using
     814             :      * a multibyte encoding, but it's not worth reallocating it; the result
     815             :      * probably won't live long anyway.
     816             :      */
     817             : 
     818           1 :     PG_RETURN_TEXT_P(result);
     819             : }
     820             : 
     821             : /********************************************************************
     822             :  *
     823             :  * ascii
     824             :  *
     825             :  * Syntax:
     826             :  *
     827             :  *   int ascii(text string)
     828             :  *
     829             :  * Purpose:
     830             :  *
     831             :  *   Returns the decimal representation of the first character from
     832             :  *   string.
     833             :  *   If the string is empty we return 0.
     834             :  *   If the database encoding is UTF8, we return the Unicode codepoint.
     835             :  *   If the database encoding is any other multi-byte encoding, we
     836             :  *   return the value of the first byte if it is an ASCII character
     837             :  *   (range 1 .. 127), or raise an error.
     838             :  *   For all other encodings we return the value of the first byte,
     839             :  *   (range 1..255).
     840             :  *
     841             :  ********************************************************************/
     842             : 
     843             : Datum
     844           2 : ascii(PG_FUNCTION_ARGS)
     845             : {
     846           2 :     text       *string = PG_GETARG_TEXT_PP(0);
     847           2 :     int         encoding = GetDatabaseEncoding();
     848             :     unsigned char *data;
     849             : 
     850           2 :     if (VARSIZE_ANY_EXHDR(string) <= 0)
     851           1 :         PG_RETURN_INT32(0);
     852             : 
     853           1 :     data = (unsigned char *) VARDATA_ANY(string);
     854             : 
     855           1 :     if (encoding == PG_UTF8 && *data > 127)
     856             :     {
     857             :         /* return the code point for Unicode */
     858             : 
     859           0 :         int         result = 0,
     860           0 :                     tbytes = 0,
     861             :                     i;
     862             : 
     863           0 :         if (*data >= 0xF0)
     864             :         {
     865           0 :             result = *data & 0x07;
     866           0 :             tbytes = 3;
     867             :         }
     868           0 :         else if (*data >= 0xE0)
     869             :         {
     870           0 :             result = *data & 0x0F;
     871           0 :             tbytes = 2;
     872             :         }
     873             :         else
     874             :         {
     875           0 :             Assert(*data > 0xC0);
     876           0 :             result = *data & 0x1f;
     877           0 :             tbytes = 1;
     878             :         }
     879             : 
     880           0 :         Assert(tbytes > 0);
     881             : 
     882           0 :         for (i = 1; i <= tbytes; i++)
     883             :         {
     884           0 :             Assert((data[i] & 0xC0) == 0x80);
     885           0 :             result = (result << 6) + (data[i] & 0x3f);
     886             :         }
     887             : 
     888           0 :         PG_RETURN_INT32(result);
     889             :     }
     890             :     else
     891             :     {
     892           1 :         if (pg_encoding_max_length(encoding) > 1 && *data > 127)
     893           0 :             ereport(ERROR,
     894             :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     895             :                      errmsg("requested character too large")));
     896             : 
     897             : 
     898           1 :         PG_RETURN_INT32((int32) *data);
     899             :     }
     900             : }
     901             : 
     902             : /********************************************************************
     903             :  *
     904             :  * chr
     905             :  *
     906             :  * Syntax:
     907             :  *
     908             :  *   text chr(int val)
     909             :  *
     910             :  * Purpose:
     911             :  *
     912             :  *  Returns the character having the binary equivalent to val.
     913             :  *
     914             :  * For UTF8 we treat the argumwent as a Unicode code point.
     915             :  * For other multi-byte encodings we raise an error for arguments
     916             :  * outside the strict ASCII range (1..127).
     917             :  *
     918             :  * It's important that we don't ever return a value that is not valid
     919             :  * in the database encoding, so that this doesn't become a way for
     920             :  * invalid data to enter the database.
     921             :  *
     922             :  ********************************************************************/
     923             : 
     924             : Datum
     925          21 : chr         (PG_FUNCTION_ARGS)
     926             : {
     927          21 :     uint32      cvalue = PG_GETARG_UINT32(0);
     928             :     text       *result;
     929          21 :     int         encoding = GetDatabaseEncoding();
     930             : 
     931          21 :     if (encoding == PG_UTF8 && cvalue > 127)
     932           0 :     {
     933             :         /* for Unicode we treat the argument as a code point */
     934             :         int         bytes;
     935             :         unsigned char *wch;
     936             : 
     937             :         /*
     938             :          * We only allow valid Unicode code points; per RFC3629 that stops at
     939             :          * U+10FFFF, even though 4-byte UTF8 sequences can hold values up to
     940             :          * U+1FFFFF.
     941             :          */
     942           0 :         if (cvalue > 0x0010ffff)
     943           0 :             ereport(ERROR,
     944             :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     945             :                      errmsg("requested character too large for encoding: %d",
     946             :                             cvalue)));
     947             : 
     948           0 :         if (cvalue > 0xffff)
     949           0 :             bytes = 4;
     950           0 :         else if (cvalue > 0x07ff)
     951           0 :             bytes = 3;
     952             :         else
     953           0 :             bytes = 2;
     954             : 
     955           0 :         result = (text *) palloc(VARHDRSZ + bytes);
     956           0 :         SET_VARSIZE(result, VARHDRSZ + bytes);
     957           0 :         wch = (unsigned char *) VARDATA(result);
     958             : 
     959           0 :         if (bytes == 2)
     960             :         {
     961           0 :             wch[0] = 0xC0 | ((cvalue >> 6) & 0x1F);
     962           0 :             wch[1] = 0x80 | (cvalue & 0x3F);
     963             :         }
     964           0 :         else if (bytes == 3)
     965             :         {
     966           0 :             wch[0] = 0xE0 | ((cvalue >> 12) & 0x0F);
     967           0 :             wch[1] = 0x80 | ((cvalue >> 6) & 0x3F);
     968           0 :             wch[2] = 0x80 | (cvalue & 0x3F);
     969             :         }
     970             :         else
     971             :         {
     972           0 :             wch[0] = 0xF0 | ((cvalue >> 18) & 0x07);
     973           0 :             wch[1] = 0x80 | ((cvalue >> 12) & 0x3F);
     974           0 :             wch[2] = 0x80 | ((cvalue >> 6) & 0x3F);
     975           0 :             wch[3] = 0x80 | (cvalue & 0x3F);
     976             :         }
     977             : 
     978             :         /*
     979             :          * The preceding range check isn't sufficient, because UTF8 excludes
     980             :          * Unicode "surrogate pair" codes.  Make sure what we created is valid
     981             :          * UTF8.
     982             :          */
     983           0 :         if (!pg_utf8_islegal(wch, bytes))
     984           0 :             ereport(ERROR,
     985             :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     986             :                      errmsg("requested character not valid for encoding: %d",
     987             :                             cvalue)));
     988             :     }
     989             :     else
     990             :     {
     991             :         bool        is_mb;
     992             : 
     993             :         /*
     994             :          * Error out on arguments that make no sense or that we can't validly
     995             :          * represent in the encoding.
     996             :          */
     997          21 :         if (cvalue == 0)
     998           1 :             ereport(ERROR,
     999             :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1000             :                      errmsg("null character not permitted")));
    1001             : 
    1002          20 :         is_mb = pg_encoding_max_length(encoding) > 1;
    1003             : 
    1004          20 :         if ((is_mb && (cvalue > 127)) || (!is_mb && (cvalue > 255)))
    1005           0 :             ereport(ERROR,
    1006             :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1007             :                      errmsg("requested character too large for encoding: %d",
    1008             :                             cvalue)));
    1009             : 
    1010          20 :         result = (text *) palloc(VARHDRSZ + 1);
    1011          20 :         SET_VARSIZE(result, VARHDRSZ + 1);
    1012          20 :         *VARDATA(result) = (char) cvalue;
    1013             :     }
    1014             : 
    1015          20 :     PG_RETURN_TEXT_P(result);
    1016             : }
    1017             : 
    1018             : /********************************************************************
    1019             :  *
    1020             :  * repeat
    1021             :  *
    1022             :  * Syntax:
    1023             :  *
    1024             :  *   text repeat(text string, int val)
    1025             :  *
    1026             :  * Purpose:
    1027             :  *
    1028             :  *  Repeat string by val.
    1029             :  *
    1030             :  ********************************************************************/
    1031             : 
    1032             : Datum
    1033        1983 : repeat(PG_FUNCTION_ARGS)
    1034             : {
    1035        1983 :     text       *string = PG_GETARG_TEXT_PP(0);
    1036        1983 :     int32       count = PG_GETARG_INT32(1);
    1037             :     text       *result;
    1038             :     int         slen,
    1039             :                 tlen;
    1040             :     int         i;
    1041             :     char       *cp,
    1042             :                *sp;
    1043             : 
    1044        1983 :     if (count < 0)
    1045           1 :         count = 0;
    1046             : 
    1047        1983 :     slen = VARSIZE_ANY_EXHDR(string);
    1048        1983 :     tlen = VARHDRSZ + (count * slen);
    1049             : 
    1050             :     /* Check for integer overflow */
    1051        1983 :     if (slen != 0 && count != 0)
    1052             :     {
    1053        1900 :         int         check = count * slen;
    1054        1900 :         int         check2 = check + VARHDRSZ;
    1055             : 
    1056        1900 :         if ((check / slen) != count || check2 <= check)
    1057           0 :             ereport(ERROR,
    1058             :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1059             :                      errmsg("requested length too large")));
    1060             :     }
    1061             : 
    1062        1983 :     result = (text *) palloc(tlen);
    1063             : 
    1064        1983 :     SET_VARSIZE(result, tlen);
    1065        1983 :     cp = VARDATA(result);
    1066        1983 :     sp = VARDATA_ANY(string);
    1067      542109 :     for (i = 0; i < count; i++)
    1068             :     {
    1069      540126 :         memcpy(cp, sp, slen);
    1070      540126 :         cp += slen;
    1071             :     }
    1072             : 
    1073        1983 :     PG_RETURN_TEXT_P(result);
    1074             : }

Generated by: LCOV version 1.11