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

Generated by: LCOV version 1.14