LCOV - code coverage report
Current view: top level - src/backend/utils/adt - oracle_compat.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 85.8 % 400 343
Test Date: 2026-02-17 17:20:33 Functions: 100.0 % 21 21
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1