LCOV - code coverage report
Current view: top level - src/backend/utils/adt - oracle_compat.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 85.8 % 400 343
Test Date: 2026-07-22 12:15:41 Functions: 100.0 % 21 21
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 61.3 % 222 136

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

Generated by: LCOV version 2.0-1