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

Generated by: LCOV version 1.14