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

Generated by: LCOV version 1.14