LCOV - code coverage report
Current view: top level - src/backend/utils/adt - oracle_compat.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 83.8 % 518 434
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 21 21
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 50.9 % 234 119

             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                 :        1194 : lower(PG_FUNCTION_ARGS)
      50                 :             : {
      51                 :        1194 :         text       *in_string = PG_GETARG_TEXT_PP(0);
      52                 :        1194 :         char       *out_string;
      53                 :        1194 :         text       *result;
      54                 :             : 
      55                 :        2388 :         out_string = str_tolower(VARDATA_ANY(in_string),
      56                 :        1194 :                                                          VARSIZE_ANY_EXHDR(in_string),
      57                 :        1194 :                                                          PG_GET_COLLATION());
      58                 :        1194 :         result = cstring_to_text(out_string);
      59                 :        1194 :         pfree(out_string);
      60                 :             : 
      61                 :        2388 :         PG_RETURN_TEXT_P(result);
      62                 :        1194 : }
      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                 :      160938 : upper(PG_FUNCTION_ARGS)
      81                 :             : {
      82                 :      160938 :         text       *in_string = PG_GETARG_TEXT_PP(0);
      83                 :      160938 :         char       *out_string;
      84                 :      160938 :         text       *result;
      85                 :             : 
      86                 :      321876 :         out_string = str_toupper(VARDATA_ANY(in_string),
      87                 :      160938 :                                                          VARSIZE_ANY_EXHDR(in_string),
      88                 :      160938 :                                                          PG_GET_COLLATION());
      89                 :      160938 :         result = cstring_to_text(out_string);
      90                 :      160938 :         pfree(out_string);
      91                 :             : 
      92                 :      321876 :         PG_RETURN_TEXT_P(result);
      93                 :      160938 : }
      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                 :          37 : initcap(PG_FUNCTION_ARGS)
     115                 :             : {
     116                 :          37 :         text       *in_string = PG_GETARG_TEXT_PP(0);
     117                 :          37 :         char       *out_string;
     118                 :          37 :         text       *result;
     119                 :             : 
     120                 :          74 :         out_string = str_initcap(VARDATA_ANY(in_string),
     121                 :          37 :                                                          VARSIZE_ANY_EXHDR(in_string),
     122                 :          37 :                                                          PG_GET_COLLATION());
     123                 :          37 :         result = cstring_to_text(out_string);
     124                 :          37 :         pfree(out_string);
     125                 :             : 
     126                 :          74 :         PG_RETURN_TEXT_P(result);
     127                 :          37 : }
     128                 :             : 
     129                 :             : Datum
     130                 :           4 : casefold(PG_FUNCTION_ARGS)
     131                 :             : {
     132                 :           4 :         text       *in_string = PG_GETARG_TEXT_PP(0);
     133                 :           4 :         char       *out_string;
     134                 :           4 :         text       *result;
     135                 :             : 
     136                 :           8 :         out_string = str_casefold(VARDATA_ANY(in_string),
     137                 :           4 :                                                           VARSIZE_ANY_EXHDR(in_string),
     138                 :           4 :                                                           PG_GET_COLLATION());
     139                 :           4 :         result = cstring_to_text(out_string);
     140                 :           4 :         pfree(out_string);
     141                 :             : 
     142                 :           8 :         PG_RETURN_TEXT_P(result);
     143                 :           4 : }
     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                 :          95 : lpad(PG_FUNCTION_ARGS)
     164                 :             : {
     165                 :          95 :         text       *string1 = PG_GETARG_TEXT_PP(0);
     166                 :          95 :         int32           len = PG_GETARG_INT32(1);
     167                 :          95 :         text       *string2 = PG_GETARG_TEXT_PP(2);
     168                 :          95 :         text       *ret;
     169                 :          95 :         char       *ptr1,
     170                 :             :                            *ptr2,
     171                 :             :                            *ptr2start,
     172                 :             :                            *ptr2end,
     173                 :             :                            *ptr_ret;
     174                 :          95 :         int                     m,
     175                 :             :                                 s1len,
     176                 :             :                                 s2len;
     177                 :          95 :         int                     bytelen;
     178                 :             : 
     179                 :             :         /* Negative len is silently taken as zero */
     180         [ +  + ]:          95 :         if (len < 0)
     181                 :           1 :                 len = 0;
     182                 :             : 
     183                 :          95 :         s1len = VARSIZE_ANY_EXHDR(string1);
     184         [ +  - ]:          95 :         if (s1len < 0)
     185                 :           0 :                 s1len = 0;                              /* shouldn't happen */
     186                 :             : 
     187                 :          95 :         s2len = VARSIZE_ANY_EXHDR(string2);
     188         [ +  - ]:          95 :         if (s2len < 0)
     189                 :           0 :                 s2len = 0;                              /* shouldn't happen */
     190                 :             : 
     191                 :          95 :         s1len = pg_mbstrlen_with_len(VARDATA_ANY(string1), s1len);
     192                 :             : 
     193         [ +  + ]:          95 :         if (s1len > len)
     194                 :           2 :                 s1len = len;                    /* truncate string1 to len chars */
     195                 :             : 
     196         [ +  + ]:          95 :         if (s2len <= 0)
     197                 :           1 :                 len = s1len;                    /* nothing to pad with, so don't pad */
     198                 :             : 
     199                 :             :         /* compute worst-case output length */
     200                 :          95 :         if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), len,
     201         [ +  - ]:          95 :                                                                          &bytelen)) ||
     202                 :          95 :                 unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
     203                 :          95 :                 unlikely(!AllocSizeIsValid(bytelen)))
     204   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     205                 :             :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     206                 :             :                                  errmsg("requested length too large")));
     207                 :             : 
     208                 :          95 :         ret = (text *) palloc(bytelen);
     209                 :             : 
     210                 :          95 :         m = len - s1len;
     211                 :             : 
     212                 :          95 :         ptr2 = ptr2start = VARDATA_ANY(string2);
     213                 :          95 :         ptr2end = ptr2 + s2len;
     214                 :          95 :         ptr_ret = VARDATA(ret);
     215                 :             : 
     216         [ +  + ]:         153 :         while (m--)
     217                 :             :         {
     218                 :          58 :                 int                     mlen = pg_mblen(ptr2);
     219                 :             : 
     220                 :          58 :                 memcpy(ptr_ret, ptr2, mlen);
     221                 :          58 :                 ptr_ret += mlen;
     222                 :          58 :                 ptr2 += mlen;
     223         [ +  + ]:          58 :                 if (ptr2 == ptr2end)    /* wrap around at end of s2 */
     224                 :          56 :                         ptr2 = ptr2start;
     225                 :          58 :         }
     226                 :             : 
     227                 :          95 :         ptr1 = VARDATA_ANY(string1);
     228                 :             : 
     229         [ +  + ]:         291 :         while (s1len--)
     230                 :             :         {
     231                 :         196 :                 int                     mlen = pg_mblen(ptr1);
     232                 :             : 
     233                 :         196 :                 memcpy(ptr_ret, ptr1, mlen);
     234                 :         196 :                 ptr_ret += mlen;
     235                 :         196 :                 ptr1 += mlen;
     236                 :         196 :         }
     237                 :             : 
     238                 :          95 :         SET_VARSIZE(ret, ptr_ret - (char *) ret);
     239                 :             : 
     240                 :         190 :         PG_RETURN_TEXT_P(ret);
     241                 :          95 : }
     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                 :           6 : rpad(PG_FUNCTION_ARGS)
     262                 :             : {
     263                 :           6 :         text       *string1 = PG_GETARG_TEXT_PP(0);
     264                 :           6 :         int32           len = PG_GETARG_INT32(1);
     265                 :           6 :         text       *string2 = PG_GETARG_TEXT_PP(2);
     266                 :           6 :         text       *ret;
     267                 :           6 :         char       *ptr1,
     268                 :             :                            *ptr2,
     269                 :             :                            *ptr2start,
     270                 :             :                            *ptr2end,
     271                 :             :                            *ptr_ret;
     272                 :           6 :         int                     m,
     273                 :             :                                 s1len,
     274                 :             :                                 s2len;
     275                 :           6 :         int                     bytelen;
     276                 :             : 
     277                 :             :         /* Negative len is silently taken as zero */
     278         [ +  + ]:           6 :         if (len < 0)
     279                 :           1 :                 len = 0;
     280                 :             : 
     281                 :           6 :         s1len = VARSIZE_ANY_EXHDR(string1);
     282         [ +  - ]:           6 :         if (s1len < 0)
     283                 :           0 :                 s1len = 0;                              /* shouldn't happen */
     284                 :             : 
     285                 :           6 :         s2len = VARSIZE_ANY_EXHDR(string2);
     286         [ +  - ]:           6 :         if (s2len < 0)
     287                 :           0 :                 s2len = 0;                              /* shouldn't happen */
     288                 :             : 
     289                 :           6 :         s1len = pg_mbstrlen_with_len(VARDATA_ANY(string1), s1len);
     290                 :             : 
     291         [ +  + ]:           6 :         if (s1len > len)
     292                 :           2 :                 s1len = len;                    /* truncate string1 to len chars */
     293                 :             : 
     294         [ +  + ]:           6 :         if (s2len <= 0)
     295                 :           1 :                 len = s1len;                    /* nothing to pad with, so don't pad */
     296                 :             : 
     297                 :             :         /* compute worst-case output length */
     298                 :           6 :         if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), len,
     299         [ +  - ]:           6 :                                                                          &bytelen)) ||
     300                 :           6 :                 unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
     301                 :           6 :                 unlikely(!AllocSizeIsValid(bytelen)))
     302   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     303                 :             :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     304                 :             :                                  errmsg("requested length too large")));
     305                 :             : 
     306                 :           6 :         ret = (text *) palloc(bytelen);
     307                 :             : 
     308                 :           6 :         m = len - s1len;
     309                 :             : 
     310                 :           6 :         ptr1 = VARDATA_ANY(string1);
     311                 :           6 :         ptr_ret = VARDATA(ret);
     312                 :             : 
     313         [ +  + ]:          14 :         while (s1len--)
     314                 :             :         {
     315                 :           8 :                 int                     mlen = pg_mblen(ptr1);
     316                 :             : 
     317                 :           8 :                 memcpy(ptr_ret, ptr1, mlen);
     318                 :           8 :                 ptr_ret += mlen;
     319                 :           8 :                 ptr1 += mlen;
     320                 :           8 :         }
     321                 :             : 
     322                 :           6 :         ptr2 = ptr2start = VARDATA_ANY(string2);
     323                 :           6 :         ptr2end = ptr2 + s2len;
     324                 :             : 
     325         [ +  + ]:      320012 :         while (m--)
     326                 :             :         {
     327                 :      320006 :                 int                     mlen = pg_mblen(ptr2);
     328                 :             : 
     329                 :      320006 :                 memcpy(ptr_ret, ptr2, mlen);
     330                 :      320006 :                 ptr_ret += mlen;
     331                 :      320006 :                 ptr2 += mlen;
     332         [ +  + ]:      320006 :                 if (ptr2 == ptr2end)    /* wrap around at end of s2 */
     333                 :      320004 :                         ptr2 = ptr2start;
     334                 :      320006 :         }
     335                 :             : 
     336                 :           6 :         SET_VARSIZE(ret, ptr_ret - (char *) ret);
     337                 :             : 
     338                 :          12 :         PG_RETURN_TEXT_P(ret);
     339                 :           6 : }
     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                 :           1 : btrim(PG_FUNCTION_ARGS)
     359                 :             : {
     360                 :           1 :         text       *string = PG_GETARG_TEXT_PP(0);
     361                 :           1 :         text       *set = PG_GETARG_TEXT_PP(1);
     362                 :           1 :         text       *ret;
     363                 :             : 
     364                 :           2 :         ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
     365                 :           1 :                                  VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
     366                 :             :                                  true, true);
     367                 :             : 
     368                 :           2 :         PG_RETURN_TEXT_P(ret);
     369                 :           1 : }
     370                 :             : 
     371                 :             : /********************************************************************
     372                 :             :  *
     373                 :             :  * btrim1 --- btrim with set fixed as ' '
     374                 :             :  *
     375                 :             :  ********************************************************************/
     376                 :             : 
     377                 :             : Datum
     378                 :          93 : btrim1(PG_FUNCTION_ARGS)
     379                 :             : {
     380                 :          93 :         text       *string = PG_GETARG_TEXT_PP(0);
     381                 :          93 :         text       *ret;
     382                 :             : 
     383                 :          93 :         ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
     384                 :             :                                  " ", 1,
     385                 :             :                                  true, true);
     386                 :             : 
     387                 :         186 :         PG_RETURN_TEXT_P(ret);
     388                 :          93 : }
     389                 :             : 
     390                 :             : /*
     391                 :             :  * Common implementation for btrim, ltrim, rtrim
     392                 :             :  */
     393                 :             : static text *
     394                 :        5625 : dotrim(const char *string, int stringlen,
     395                 :             :            const char *set, int setlen,
     396                 :             :            bool doltrim, bool dortrim)
     397                 :             : {
     398                 :        5625 :         int                     i;
     399                 :             : 
     400                 :             :         /* Nothing to do if either string or set is empty */
     401   [ +  -  -  + ]:        5625 :         if (stringlen > 0 && setlen > 0)
     402                 :             :         {
     403         [ +  - ]:        5625 :                 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                 :        5625 :                         const char **stringchars;
     411                 :        5625 :                         const char **setchars;
     412                 :        5625 :                         int                *stringmblen;
     413                 :        5625 :                         int                *setmblen;
     414                 :        5625 :                         int                     stringnchars;
     415                 :        5625 :                         int                     setnchars;
     416                 :        5625 :                         int                     resultndx;
     417                 :        5625 :                         int                     resultnchars;
     418                 :        5625 :                         const char *p;
     419                 :        5625 :                         int                     len;
     420                 :        5625 :                         int                     mblen;
     421                 :        5625 :                         const char *str_pos;
     422                 :        5625 :                         int                     str_len;
     423                 :             : 
     424                 :        5625 :                         stringchars = (const char **) palloc(stringlen * sizeof(char *));
     425                 :        5625 :                         stringmblen = (int *) palloc(stringlen * sizeof(int));
     426                 :        5625 :                         stringnchars = 0;
     427                 :        5625 :                         p = string;
     428                 :        5625 :                         len = stringlen;
     429         [ +  + ]:       49832 :                         while (len > 0)
     430                 :             :                         {
     431                 :       44207 :                                 stringchars[stringnchars] = p;
     432                 :       44207 :                                 stringmblen[stringnchars] = mblen = pg_mblen(p);
     433                 :       44207 :                                 stringnchars++;
     434                 :       44207 :                                 p += mblen;
     435                 :       44207 :                                 len -= mblen;
     436                 :             :                         }
     437                 :             : 
     438                 :        5625 :                         setchars = (const char **) palloc(setlen * sizeof(char *));
     439                 :        5625 :                         setmblen = (int *) palloc(setlen * sizeof(int));
     440                 :        5625 :                         setnchars = 0;
     441                 :        5625 :                         p = set;
     442                 :        5625 :                         len = setlen;
     443         [ +  + ]:       11396 :                         while (len > 0)
     444                 :             :                         {
     445                 :        5771 :                                 setchars[setnchars] = p;
     446                 :        5771 :                                 setmblen[setnchars] = mblen = pg_mblen(p);
     447                 :        5771 :                                 setnchars++;
     448                 :        5771 :                                 p += mblen;
     449                 :        5771 :                                 len -= mblen;
     450                 :             :                         }
     451                 :             : 
     452                 :        5625 :                         resultndx = 0;          /* index in stringchars[] */
     453                 :        5625 :                         resultnchars = stringnchars;
     454                 :             : 
     455         [ +  + ]:        5625 :                         if (doltrim)
     456                 :             :                         {
     457         [ -  + ]:        9409 :                                 while (resultnchars > 0)
     458                 :             :                                 {
     459                 :        9409 :                                         str_pos = stringchars[resultndx];
     460                 :        9409 :                                         str_len = stringmblen[resultndx];
     461         [ +  + ]:       14164 :                                         for (i = 0; i < setnchars; i++)
     462                 :             :                                         {
     463   [ +  -  +  + ]:        9418 :                                                 if (str_len == setmblen[i] &&
     464                 :        9418 :                                                         memcmp(str_pos, setchars[i], str_len) == 0)
     465                 :        4663 :                                                         break;
     466                 :        4755 :                                         }
     467         [ +  + ]:        9409 :                                         if (i >= setnchars)
     468                 :        4746 :                                                 break;  /* no match here */
     469                 :        4663 :                                         string += str_len;
     470                 :        4663 :                                         stringlen -= str_len;
     471                 :        4663 :                                         resultndx++;
     472                 :        4663 :                                         resultnchars--;
     473                 :             :                                 }
     474                 :        4746 :                         }
     475                 :             : 
     476         [ +  + ]:        5625 :                         if (dortrim)
     477                 :             :                         {
     478         [ -  + ]:       11637 :                                 while (resultnchars > 0)
     479                 :             :                                 {
     480                 :       11637 :                                         str_pos = stringchars[resultndx + resultnchars - 1];
     481                 :       11637 :                                         str_len = stringmblen[resultndx + resultnchars - 1];
     482         [ +  + ]:       13014 :                                         for (i = 0; i < setnchars; i++)
     483                 :             :                                         {
     484   [ +  -  +  + ]:       12041 :                                                 if (str_len == setmblen[i] &&
     485                 :       12041 :                                                         memcmp(str_pos, setchars[i], str_len) == 0)
     486                 :       10664 :                                                         break;
     487                 :        1377 :                                         }
     488         [ +  + ]:       11637 :                                         if (i >= setnchars)
     489                 :         973 :                                                 break;  /* no match here */
     490                 :       10664 :                                         stringlen -= str_len;
     491                 :       10664 :                                         resultnchars--;
     492                 :             :                                 }
     493                 :         973 :                         }
     494                 :             : 
     495                 :        5625 :                         pfree(stringchars);
     496                 :        5625 :                         pfree(stringmblen);
     497                 :        5625 :                         pfree(setchars);
     498                 :        5625 :                         pfree(setmblen);
     499                 :        5625 :                 }
     500                 :             :                 else
     501                 :             :                 {
     502                 :             :                         /*
     503                 :             :                          * In the single-byte-encoding case, we don't need such overhead.
     504                 :             :                          */
     505         [ #  # ]:           0 :                         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                 :           0 :                                         }
     516         [ #  # ]:           0 :                                         if (i >= setlen)
     517                 :           0 :                                                 break;  /* no match here */
     518                 :           0 :                                         string++;
     519                 :           0 :                                         stringlen--;
     520         [ #  # ]:           0 :                                 }
     521                 :           0 :                         }
     522                 :             : 
     523         [ #  # ]:           0 :                         if (dortrim)
     524                 :             :                         {
     525         [ #  # ]:           0 :                                 while (stringlen > 0)
     526                 :             :                                 {
     527                 :           0 :                                         char            str_ch = string[stringlen - 1];
     528                 :             : 
     529         [ #  # ]:           0 :                                         for (i = 0; i < setlen; i++)
     530                 :             :                                         {
     531         [ #  # ]:           0 :                                                 if (str_ch == set[i])
     532                 :           0 :                                                         break;
     533                 :           0 :                                         }
     534         [ #  # ]:           0 :                                         if (i >= setlen)
     535                 :           0 :                                                 break;  /* no match here */
     536                 :           0 :                                         stringlen--;
     537         [ #  # ]:           0 :                                 }
     538                 :           0 :                         }
     539                 :             :                 }
     540                 :        5625 :         }
     541                 :             : 
     542                 :             :         /* Return selected portion of string */
     543                 :       11250 :         return cstring_to_text_with_len(string, stringlen);
     544                 :        5625 : }
     545                 :             : 
     546                 :             : /*
     547                 :             :  * Common implementation for bytea versions of btrim, ltrim, rtrim
     548                 :             :  */
     549                 :             : bytea *
     550                 :           6 : dobyteatrim(bytea *string, bytea *set, bool doltrim, bool dortrim)
     551                 :             : {
     552                 :           6 :         bytea      *ret;
     553                 :           6 :         char       *ptr,
     554                 :             :                            *end,
     555                 :             :                            *ptr2,
     556                 :             :                            *ptr2start,
     557                 :             :                            *end2;
     558                 :           6 :         int                     m,
     559                 :             :                                 stringlen,
     560                 :             :                                 setlen;
     561                 :             : 
     562                 :           6 :         stringlen = VARSIZE_ANY_EXHDR(string);
     563                 :           6 :         setlen = VARSIZE_ANY_EXHDR(set);
     564                 :             : 
     565   [ +  +  +  + ]:           6 :         if (stringlen <= 0 || setlen <= 0)
     566                 :           2 :                 return string;
     567                 :             : 
     568                 :           4 :         m = stringlen;
     569                 :           4 :         ptr = VARDATA_ANY(string);
     570                 :           4 :         end = ptr + stringlen - 1;
     571                 :           4 :         ptr2start = VARDATA_ANY(set);
     572                 :           4 :         end2 = ptr2start + setlen - 1;
     573                 :             : 
     574         [ +  + ]:           4 :         if (doltrim)
     575                 :             :         {
     576         [ -  + ]:           6 :                 while (m > 0)
     577                 :             :                 {
     578                 :           6 :                         ptr2 = ptr2start;
     579         [ +  + ]:           9 :                         while (ptr2 <= end2)
     580                 :             :                         {
     581         [ +  + ]:           6 :                                 if (*ptr == *ptr2)
     582                 :           3 :                                         break;
     583                 :           3 :                                 ++ptr2;
     584                 :             :                         }
     585         [ +  + ]:           6 :                         if (ptr2 > end2)
     586                 :           3 :                                 break;
     587                 :           3 :                         ptr++;
     588                 :           3 :                         m--;
     589                 :             :                 }
     590                 :           3 :         }
     591                 :             : 
     592         [ +  + ]:           4 :         if (dortrim)
     593                 :             :         {
     594         [ -  + ]:           6 :                 while (m > 0)
     595                 :             :                 {
     596                 :           6 :                         ptr2 = ptr2start;
     597         [ +  + ]:           9 :                         while (ptr2 <= end2)
     598                 :             :                         {
     599         [ +  + ]:           6 :                                 if (*end == *ptr2)
     600                 :           3 :                                         break;
     601                 :           3 :                                 ++ptr2;
     602                 :             :                         }
     603         [ +  + ]:           6 :                         if (ptr2 > end2)
     604                 :           3 :                                 break;
     605                 :           3 :                         end--;
     606                 :           3 :                         m--;
     607                 :             :                 }
     608                 :           3 :         }
     609                 :             : 
     610                 :           4 :         ret = (bytea *) palloc(VARHDRSZ + m);
     611                 :           4 :         SET_VARSIZE(ret, VARHDRSZ + m);
     612                 :           4 :         memcpy(VARDATA(ret), ptr, m);
     613                 :           4 :         return ret;
     614                 :           6 : }
     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                 :           4 : byteatrim(PG_FUNCTION_ARGS)
     634                 :             : {
     635                 :           4 :         bytea      *string = PG_GETARG_BYTEA_PP(0);
     636                 :           4 :         bytea      *set = PG_GETARG_BYTEA_PP(1);
     637                 :           4 :         bytea      *ret;
     638                 :             : 
     639                 :           4 :         ret = dobyteatrim(string, set, true, true);
     640                 :             : 
     641                 :           8 :         PG_RETURN_BYTEA_P(ret);
     642                 :           4 : }
     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                 :           1 : bytealtrim(PG_FUNCTION_ARGS)
     661                 :             : {
     662                 :           1 :         bytea      *string = PG_GETARG_BYTEA_PP(0);
     663                 :           1 :         bytea      *set = PG_GETARG_BYTEA_PP(1);
     664                 :           1 :         bytea      *ret;
     665                 :             : 
     666                 :           1 :         ret = dobyteatrim(string, set, true, false);
     667                 :             : 
     668                 :           2 :         PG_RETURN_BYTEA_P(ret);
     669                 :           1 : }
     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                 :           1 : byteartrim(PG_FUNCTION_ARGS)
     688                 :             : {
     689                 :           1 :         bytea      *string = PG_GETARG_BYTEA_PP(0);
     690                 :           1 :         bytea      *set = PG_GETARG_BYTEA_PP(1);
     691                 :           1 :         bytea      *ret;
     692                 :             : 
     693                 :           1 :         ret = dobyteatrim(string, set, false, true);
     694                 :             : 
     695                 :           2 :         PG_RETURN_BYTEA_P(ret);
     696                 :           1 : }
     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                 :        4651 : ltrim(PG_FUNCTION_ARGS)
     715                 :             : {
     716                 :        4651 :         text       *string = PG_GETARG_TEXT_PP(0);
     717                 :        4651 :         text       *set = PG_GETARG_TEXT_PP(1);
     718                 :        4651 :         text       *ret;
     719                 :             : 
     720                 :        9302 :         ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
     721                 :        4651 :                                  VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
     722                 :             :                                  true, false);
     723                 :             : 
     724                 :        9302 :         PG_RETURN_TEXT_P(ret);
     725                 :        4651 : }
     726                 :             : 
     727                 :             : /********************************************************************
     728                 :             :  *
     729                 :             :  * ltrim1 --- ltrim with set fixed as ' '
     730                 :             :  *
     731                 :             :  ********************************************************************/
     732                 :             : 
     733                 :             : Datum
     734                 :           1 : ltrim1(PG_FUNCTION_ARGS)
     735                 :             : {
     736                 :           1 :         text       *string = PG_GETARG_TEXT_PP(0);
     737                 :           1 :         text       *ret;
     738                 :             : 
     739                 :           1 :         ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
     740                 :             :                                  " ", 1,
     741                 :             :                                  true, false);
     742                 :             : 
     743                 :           2 :         PG_RETURN_TEXT_P(ret);
     744                 :           1 : }
     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                 :          35 : rtrim(PG_FUNCTION_ARGS)
     763                 :             : {
     764                 :          35 :         text       *string = PG_GETARG_TEXT_PP(0);
     765                 :          35 :         text       *set = PG_GETARG_TEXT_PP(1);
     766                 :          35 :         text       *ret;
     767                 :             : 
     768                 :          70 :         ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
     769                 :          35 :                                  VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
     770                 :             :                                  false, true);
     771                 :             : 
     772                 :          70 :         PG_RETURN_TEXT_P(ret);
     773                 :          35 : }
     774                 :             : 
     775                 :             : /********************************************************************
     776                 :             :  *
     777                 :             :  * rtrim1 --- rtrim with set fixed as ' '
     778                 :             :  *
     779                 :             :  ********************************************************************/
     780                 :             : 
     781                 :             : Datum
     782                 :         844 : rtrim1(PG_FUNCTION_ARGS)
     783                 :             : {
     784                 :         844 :         text       *string = PG_GETARG_TEXT_PP(0);
     785                 :         844 :         text       *ret;
     786                 :             : 
     787                 :         844 :         ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
     788                 :             :                                  " ", 1,
     789                 :             :                                  false, true);
     790                 :             : 
     791                 :        1688 :         PG_RETURN_TEXT_P(ret);
     792                 :         844 : }
     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                 :           3 : translate(PG_FUNCTION_ARGS)
     814                 :             : {
     815                 :           3 :         text       *string = PG_GETARG_TEXT_PP(0);
     816                 :           3 :         text       *from = PG_GETARG_TEXT_PP(1);
     817                 :           3 :         text       *to = PG_GETARG_TEXT_PP(2);
     818                 :           3 :         text       *result;
     819                 :           3 :         char       *from_ptr,
     820                 :             :                            *to_ptr,
     821                 :             :                            *to_end;
     822                 :           3 :         char       *source,
     823                 :             :                            *target;
     824                 :           3 :         int                     m,
     825                 :             :                                 fromlen,
     826                 :             :                                 tolen,
     827                 :             :                                 retlen,
     828                 :             :                                 i;
     829                 :           3 :         int                     bytelen;
     830                 :           3 :         int                     len;
     831                 :           3 :         int                     source_len;
     832                 :           3 :         int                     from_index;
     833                 :             : 
     834                 :           3 :         m = VARSIZE_ANY_EXHDR(string);
     835         [ +  + ]:           3 :         if (m <= 0)
     836                 :           1 :                 PG_RETURN_TEXT_P(string);
     837                 :           2 :         source = VARDATA_ANY(string);
     838                 :             : 
     839                 :           2 :         fromlen = VARSIZE_ANY_EXHDR(from);
     840                 :           2 :         from_ptr = VARDATA_ANY(from);
     841                 :           2 :         tolen = VARSIZE_ANY_EXHDR(to);
     842                 :           2 :         to_ptr = VARDATA_ANY(to);
     843                 :           2 :         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                 :           2 :         if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), m,
     850         [ +  - ]:           2 :                                                                          &bytelen)) ||
     851                 :           2 :                 unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
     852                 :           2 :                 unlikely(!AllocSizeIsValid(bytelen)))
     853   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     854                 :             :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     855                 :             :                                  errmsg("requested length too large")));
     856                 :             : 
     857                 :           2 :         result = (text *) palloc(bytelen);
     858                 :             : 
     859                 :           2 :         target = VARDATA(result);
     860                 :           2 :         retlen = 0;
     861                 :             : 
     862         [ +  + ]:          12 :         while (m > 0)
     863                 :             :         {
     864                 :          10 :                 source_len = pg_mblen(source);
     865                 :          10 :                 from_index = 0;
     866                 :             : 
     867         [ +  + ]:          26 :                 for (i = 0; i < fromlen; i += len)
     868                 :             :                 {
     869                 :          21 :                         len = pg_mblen(&from_ptr[i]);
     870   [ +  -  +  + ]:          21 :                         if (len == source_len &&
     871                 :          21 :                                 memcmp(source, &from_ptr[i], len) == 0)
     872                 :           5 :                                 break;
     873                 :             : 
     874                 :          16 :                         from_index++;
     875                 :          16 :                 }
     876         [ +  + ]:          10 :                 if (i < fromlen)
     877                 :             :                 {
     878                 :             :                         /* substitute, or delete if no corresponding "to" character */
     879                 :           5 :                         char       *p = to_ptr;
     880                 :             : 
     881         [ +  + ]:           8 :                         for (i = 0; i < from_index; i++)
     882                 :             :                         {
     883         [ +  + ]:           4 :                                 if (p >= to_end)
     884                 :           1 :                                         break;
     885                 :           3 :                                 p += pg_mblen(p);
     886                 :           3 :                         }
     887         [ +  + ]:           5 :                         if (p < to_end)
     888                 :             :                         {
     889                 :           3 :                                 len = pg_mblen(p);
     890                 :           3 :                                 memcpy(target, p, len);
     891                 :           3 :                                 target += len;
     892                 :           3 :                                 retlen += len;
     893                 :           3 :                         }
     894                 :           5 :                 }
     895                 :             :                 else
     896                 :             :                 {
     897                 :             :                         /* no match, so copy */
     898                 :           5 :                         memcpy(target, source, source_len);
     899                 :           5 :                         target += source_len;
     900                 :           5 :                         retlen += source_len;
     901                 :             :                 }
     902                 :             : 
     903                 :          10 :                 source += source_len;
     904                 :          10 :                 m -= source_len;
     905                 :             :         }
     906                 :             : 
     907                 :           2 :         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                 :           2 :         PG_RETURN_TEXT_P(result);
     916                 :           3 : }
     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                 :           7 : ascii(PG_FUNCTION_ARGS)
     942                 :             : {
     943                 :           7 :         text       *string = PG_GETARG_TEXT_PP(0);
     944                 :           7 :         int                     encoding = GetDatabaseEncoding();
     945                 :           7 :         unsigned char *data;
     946                 :             : 
     947         [ +  + ]:           7 :         if (VARSIZE_ANY_EXHDR(string) <= 0)
     948                 :           1 :                 PG_RETURN_INT32(0);
     949                 :             : 
     950                 :           6 :         data = (unsigned char *) VARDATA_ANY(string);
     951                 :             : 
     952   [ +  -  +  - ]:           6 :         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                 :           0 :                 }
     965         [ #  # ]:           0 :                 else if (*data >= 0xE0)
     966                 :             :                 {
     967                 :           0 :                         result = *data & 0x0F;
     968                 :           0 :                         tbytes = 2;
     969                 :           0 :                 }
     970                 :             :                 else
     971                 :             :                 {
     972         [ #  # ]:           0 :                         Assert(*data > 0xC0);
     973                 :           0 :                         result = *data & 0x1f;
     974                 :           0 :                         tbytes = 1;
     975                 :             :                 }
     976                 :             : 
     977         [ #  # ]:           0 :                 Assert(tbytes > 0);
     978                 :             : 
     979         [ #  # ]:           0 :                 for (i = 1; i <= tbytes; i++)
     980                 :             :                 {
     981         [ #  # ]:           0 :                         Assert((data[i] & 0xC0) == 0x80);
     982                 :           0 :                         result = (result << 6) + (data[i] & 0x3f);
     983                 :           0 :                 }
     984                 :             : 
     985                 :           0 :                 PG_RETURN_INT32(result);
     986                 :           0 :         }
     987                 :             :         else
     988                 :             :         {
     989   [ +  -  +  - ]:           6 :                 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                 :           6 :                 PG_RETURN_INT32((int32) *data);
     996                 :             :         }
     997                 :           7 : }
     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                 :         493 : chr                     (PG_FUNCTION_ARGS)
    1023                 :             : {
    1024                 :         493 :         int32           arg = PG_GETARG_INT32(0);
    1025                 :         493 :         uint32          cvalue;
    1026                 :         493 :         text       *result;
    1027                 :         493 :         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         [ +  - ]:         493 :         if (arg < 0)
    1034   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1035                 :             :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1036                 :             :                                  errmsg("character number must be positive")));
    1037         [ +  + ]:         493 :         else if (arg == 0)
    1038   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    1039                 :             :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1040                 :             :                                  errmsg("null character not permitted")));
    1041                 :             : 
    1042                 :         492 :         cvalue = arg;
    1043                 :             : 
    1044   [ +  -  +  - ]:         492 :         if (encoding == PG_UTF8 && cvalue > 127)
    1045                 :             :         {
    1046                 :             :                 /* for Unicode we treat the argument as a code point */
    1047                 :           0 :                 int                     bytes;
    1048                 :           0 :                 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                 :           0 :                 }
    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                 :           0 :                 }
    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                 :           0 :         }
    1102                 :             :         else
    1103                 :             :         {
    1104                 :         492 :                 bool            is_mb;
    1105                 :             : 
    1106                 :         492 :                 is_mb = pg_encoding_max_length(encoding) > 1;
    1107                 :             : 
    1108   [ +  -  +  -  :         492 :                 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                 :         492 :                 result = (text *) palloc(VARHDRSZ + 1);
    1115                 :         492 :                 SET_VARSIZE(result, VARHDRSZ + 1);
    1116                 :         492 :                 *VARDATA(result) = (char) cvalue;
    1117                 :         492 :         }
    1118                 :             : 
    1119                 :         984 :         PG_RETURN_TEXT_P(result);
    1120                 :         492 : }
    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                 :        2352 : repeat(PG_FUNCTION_ARGS)
    1138                 :             : {
    1139                 :        2352 :         text       *string = PG_GETARG_TEXT_PP(0);
    1140                 :        2352 :         int32           count = PG_GETARG_INT32(1);
    1141                 :        2352 :         text       *result;
    1142                 :        2352 :         int                     slen,
    1143                 :             :                                 tlen;
    1144                 :        2352 :         int                     i;
    1145                 :        2352 :         char       *cp,
    1146                 :             :                            *sp;
    1147                 :             : 
    1148         [ +  + ]:        2352 :         if (count < 0)
    1149                 :           1 :                 count = 0;
    1150                 :             : 
    1151                 :        2352 :         slen = VARSIZE_ANY_EXHDR(string);
    1152                 :             : 
    1153         [ +  - ]:        2352 :         if (unlikely(pg_mul_s32_overflow(count, slen, &tlen)) ||
    1154                 :        2352 :                 unlikely(pg_add_s32_overflow(tlen, VARHDRSZ, &tlen)) ||
    1155                 :        2352 :                 unlikely(!AllocSizeIsValid(tlen)))
    1156   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1157                 :             :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1158                 :             :                                  errmsg("requested length too large")));
    1159                 :             : 
    1160                 :        2352 :         result = (text *) palloc(tlen);
    1161                 :             : 
    1162                 :        2352 :         SET_VARSIZE(result, tlen);
    1163                 :        2352 :         cp = VARDATA(result);
    1164                 :        2352 :         sp = VARDATA_ANY(string);
    1165         [ +  + ]:     2213879 :         for (i = 0; i < count; i++)
    1166                 :             :         {
    1167                 :     2211527 :                 memcpy(cp, sp, slen);
    1168                 :     2211527 :                 cp += slen;
    1169         [ +  - ]:     2211527 :                 CHECK_FOR_INTERRUPTS();
    1170                 :     2211527 :         }
    1171                 :             : 
    1172                 :        4704 :         PG_RETURN_TEXT_P(result);
    1173                 :        2352 : }
        

Generated by: LCOV version 2.3.2-1