LCOV - code coverage report
Current view: top level - src/backend/utils/mb - mbutils.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 60.6 % 652 395
Test Date: 2026-01-26 10:56:24 Functions: 78.2 % 55 43
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 36.6 % 429 157

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * mbutils.c
       4                 :             :  *        This file contains functions for encoding conversion.
       5                 :             :  *
       6                 :             :  * The string-conversion functions in this file share some API quirks.
       7                 :             :  * Note the following:
       8                 :             :  *
       9                 :             :  * The functions return a palloc'd, null-terminated string if conversion
      10                 :             :  * is required.  However, if no conversion is performed, the given source
      11                 :             :  * string pointer is returned as-is.
      12                 :             :  *
      13                 :             :  * Although the presence of a length argument means that callers can pass
      14                 :             :  * non-null-terminated strings, care is required because the same string
      15                 :             :  * will be passed back if no conversion occurs.  Such callers *must* check
      16                 :             :  * whether result == src and handle that case differently.
      17                 :             :  *
      18                 :             :  * If the source and destination encodings are the same, the source string
      19                 :             :  * is returned without any verification; it's assumed to be valid data.
      20                 :             :  * If that might not be the case, the caller is responsible for validating
      21                 :             :  * the string using a separate call to pg_verify_mbstr().  Whenever the
      22                 :             :  * source and destination encodings are different, the functions ensure that
      23                 :             :  * the result is validly encoded according to the destination encoding.
      24                 :             :  *
      25                 :             :  *
      26                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      27                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
      28                 :             :  *
      29                 :             :  *
      30                 :             :  * IDENTIFICATION
      31                 :             :  *        src/backend/utils/mb/mbutils.c
      32                 :             :  *
      33                 :             :  *-------------------------------------------------------------------------
      34                 :             :  */
      35                 :             : #include "postgres.h"
      36                 :             : 
      37                 :             : #include "access/xact.h"
      38                 :             : #include "catalog/namespace.h"
      39                 :             : #include "mb/pg_wchar.h"
      40                 :             : #include "utils/fmgrprotos.h"
      41                 :             : #include "utils/memutils.h"
      42                 :             : #include "utils/relcache.h"
      43                 :             : #include "varatt.h"
      44                 :             : 
      45                 :             : /*
      46                 :             :  * We maintain a simple linked list caching the fmgr lookup info for the
      47                 :             :  * currently selected conversion functions, as well as any that have been
      48                 :             :  * selected previously in the current session.  (We remember previous
      49                 :             :  * settings because we must be able to restore a previous setting during
      50                 :             :  * transaction rollback, without doing any fresh catalog accesses.)
      51                 :             :  *
      52                 :             :  * Since we'll never release this data, we just keep it in TopMemoryContext.
      53                 :             :  */
      54                 :             : typedef struct ConvProcInfo
      55                 :             : {
      56                 :             :         int                     s_encoding;             /* server and client encoding IDs */
      57                 :             :         int                     c_encoding;
      58                 :             :         FmgrInfo        to_server_info; /* lookup info for conversion procs */
      59                 :             :         FmgrInfo        to_client_info;
      60                 :             : } ConvProcInfo;
      61                 :             : 
      62                 :             : static List *ConvProcList = NIL;        /* List of ConvProcInfo */
      63                 :             : 
      64                 :             : /*
      65                 :             :  * These variables point to the currently active conversion functions,
      66                 :             :  * or are NULL when no conversion is needed.
      67                 :             :  */
      68                 :             : static FmgrInfo *ToServerConvProc = NULL;
      69                 :             : static FmgrInfo *ToClientConvProc = NULL;
      70                 :             : 
      71                 :             : /*
      72                 :             :  * This variable stores the conversion function to convert from UTF-8
      73                 :             :  * to the server encoding.  It's NULL if the server encoding *is* UTF-8,
      74                 :             :  * or if we lack a conversion function for this.
      75                 :             :  */
      76                 :             : static FmgrInfo *Utf8ToServerConvProc = NULL;
      77                 :             : 
      78                 :             : /*
      79                 :             :  * These variables track the currently-selected encodings.
      80                 :             :  */
      81                 :             : static const pg_enc2name *ClientEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
      82                 :             : static const pg_enc2name *DatabaseEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
      83                 :             : static const pg_enc2name *MessageEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
      84                 :             : 
      85                 :             : /*
      86                 :             :  * During backend startup we can't set client encoding because we (a)
      87                 :             :  * can't look up the conversion functions, and (b) may not know the database
      88                 :             :  * encoding yet either.  So SetClientEncoding() just accepts anything and
      89                 :             :  * remembers it for InitializeClientEncoding() to apply later.
      90                 :             :  */
      91                 :             : static bool backend_startup_complete = false;
      92                 :             : static int      pending_client_encoding = PG_SQL_ASCII;
      93                 :             : 
      94                 :             : 
      95                 :             : /* Internal functions */
      96                 :             : static char *perform_default_encoding_conversion(const char *src,
      97                 :             :                                                                                                  int len, bool is_client_to_server);
      98                 :             : static int      cliplen(const char *str, int len, int limit);
      99                 :             : 
     100                 :             : 
     101                 :             : /*
     102                 :             :  * Prepare for a future call to SetClientEncoding.  Success should mean
     103                 :             :  * that SetClientEncoding is guaranteed to succeed for this encoding request.
     104                 :             :  *
     105                 :             :  * (But note that success before backend_startup_complete does not guarantee
     106                 :             :  * success after ...)
     107                 :             :  *
     108                 :             :  * Returns 0 if okay, -1 if not (bad encoding or can't support conversion)
     109                 :             :  */
     110                 :             : int
     111                 :        1126 : PrepareClientEncoding(int encoding)
     112                 :             : {
     113                 :        1126 :         int                     current_server_encoding;
     114                 :        1126 :         ListCell   *lc;
     115                 :             : 
     116   [ +  -  -  + ]:        1126 :         if (!PG_VALID_FE_ENCODING(encoding))
     117                 :           0 :                 return -1;
     118                 :             : 
     119                 :             :         /* Can't do anything during startup, per notes above */
     120         [ +  + ]:        1126 :         if (!backend_startup_complete)
     121                 :         324 :                 return 0;
     122                 :             : 
     123                 :         802 :         current_server_encoding = GetDatabaseEncoding();
     124                 :             : 
     125                 :             :         /*
     126                 :             :          * Check for cases that require no conversion function.
     127                 :             :          */
     128         [ +  + ]:         802 :         if (current_server_encoding == encoding ||
     129   [ +  -  +  + ]:         479 :                 current_server_encoding == PG_SQL_ASCII ||
     130                 :         479 :                 encoding == PG_SQL_ASCII)
     131                 :         800 :                 return 0;
     132                 :             : 
     133         [ +  - ]:           2 :         if (IsTransactionState())
     134                 :             :         {
     135                 :             :                 /*
     136                 :             :                  * If we're in a live transaction, it's safe to access the catalogs,
     137                 :             :                  * so look up the functions.  We repeat the lookup even if the info is
     138                 :             :                  * already cached, so that we can react to changes in the contents of
     139                 :             :                  * pg_conversion.
     140                 :             :                  */
     141                 :           2 :                 Oid                     to_server_proc,
     142                 :             :                                         to_client_proc;
     143                 :           2 :                 ConvProcInfo *convinfo;
     144                 :           2 :                 MemoryContext oldcontext;
     145                 :             : 
     146                 :           4 :                 to_server_proc = FindDefaultConversionProc(encoding,
     147                 :           2 :                                                                                                    current_server_encoding);
     148         [ +  - ]:           2 :                 if (!OidIsValid(to_server_proc))
     149                 :           0 :                         return -1;
     150                 :           4 :                 to_client_proc = FindDefaultConversionProc(current_server_encoding,
     151                 :           2 :                                                                                                    encoding);
     152         [ +  - ]:           2 :                 if (!OidIsValid(to_client_proc))
     153                 :           0 :                         return -1;
     154                 :             : 
     155                 :             :                 /*
     156                 :             :                  * Load the fmgr info into TopMemoryContext (could still fail here)
     157                 :             :                  */
     158                 :           2 :                 convinfo = (ConvProcInfo *) MemoryContextAlloc(TopMemoryContext,
     159                 :             :                                                                                                            sizeof(ConvProcInfo));
     160                 :           2 :                 convinfo->s_encoding = current_server_encoding;
     161                 :           2 :                 convinfo->c_encoding = encoding;
     162                 :           4 :                 fmgr_info_cxt(to_server_proc, &convinfo->to_server_info,
     163                 :           2 :                                           TopMemoryContext);
     164                 :           4 :                 fmgr_info_cxt(to_client_proc, &convinfo->to_client_info,
     165                 :           2 :                                           TopMemoryContext);
     166                 :             : 
     167                 :             :                 /* Attach new info to head of list */
     168                 :           2 :                 oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     169                 :           2 :                 ConvProcList = lcons(convinfo, ConvProcList);
     170                 :           2 :                 MemoryContextSwitchTo(oldcontext);
     171                 :             : 
     172                 :             :                 /*
     173                 :             :                  * We cannot yet remove any older entry for the same encoding pair,
     174                 :             :                  * since it could still be in use.  SetClientEncoding will clean up.
     175                 :             :                  */
     176                 :             : 
     177                 :           2 :                 return 0;                               /* success */
     178                 :           2 :         }
     179                 :             :         else
     180                 :             :         {
     181                 :             :                 /*
     182                 :             :                  * If we're not in a live transaction, the only thing we can do is
     183                 :             :                  * restore a previous setting using the cache.  This covers all
     184                 :             :                  * transaction-rollback cases.  The only case it might not work for is
     185                 :             :                  * trying to change client_encoding on the fly by editing
     186                 :             :                  * postgresql.conf and SIGHUP'ing.  Which would probably be a stupid
     187                 :             :                  * thing to do anyway.
     188                 :             :                  */
     189   [ #  #  #  #  :           0 :                 foreach(lc, ConvProcList)
             #  #  #  # ]
     190                 :             :                 {
     191                 :           0 :                         ConvProcInfo *oldinfo = (ConvProcInfo *) lfirst(lc);
     192                 :             : 
     193   [ #  #  #  # ]:           0 :                         if (oldinfo->s_encoding == current_server_encoding &&
     194                 :           0 :                                 oldinfo->c_encoding == encoding)
     195                 :           0 :                                 return 0;
     196         [ #  # ]:           0 :                 }
     197                 :             : 
     198                 :           0 :                 return -1;                              /* it's not cached, so fail */
     199                 :             :         }
     200                 :        1126 : }
     201                 :             : 
     202                 :             : /*
     203                 :             :  * Set the active client encoding and set up the conversion-function pointers.
     204                 :             :  * PrepareClientEncoding should have been called previously for this encoding.
     205                 :             :  *
     206                 :             :  * Returns 0 if okay, -1 if not (bad encoding or can't support conversion)
     207                 :             :  */
     208                 :             : int
     209                 :        1605 : SetClientEncoding(int encoding)
     210                 :             : {
     211                 :        1605 :         int                     current_server_encoding;
     212                 :        1605 :         bool            found;
     213                 :        1605 :         ListCell   *lc;
     214                 :             : 
     215   [ +  -  -  + ]:        1605 :         if (!PG_VALID_FE_ENCODING(encoding))
     216                 :           0 :                 return -1;
     217                 :             : 
     218                 :             :         /* Can't do anything during startup, per notes above */
     219         [ +  + ]:        1605 :         if (!backend_startup_complete)
     220                 :             :         {
     221                 :         324 :                 pending_client_encoding = encoding;
     222                 :         324 :                 return 0;
     223                 :             :         }
     224                 :             : 
     225                 :        1281 :         current_server_encoding = GetDatabaseEncoding();
     226                 :             : 
     227                 :             :         /*
     228                 :             :          * Check for cases that require no conversion function.
     229                 :             :          */
     230         [ +  + ]:        1281 :         if (current_server_encoding == encoding ||
     231   [ +  -  +  + ]:         479 :                 current_server_encoding == PG_SQL_ASCII ||
     232                 :         479 :                 encoding == PG_SQL_ASCII)
     233                 :             :         {
     234                 :        1279 :                 ClientEncoding = &pg_enc2name_tbl[encoding];
     235                 :        1279 :                 ToServerConvProc = NULL;
     236                 :        1279 :                 ToClientConvProc = NULL;
     237                 :        1279 :                 return 0;
     238                 :             :         }
     239                 :             : 
     240                 :             :         /*
     241                 :             :          * Search the cache for the entry previously prepared by
     242                 :             :          * PrepareClientEncoding; if there isn't one, we lose.  While at it,
     243                 :             :          * release any duplicate entries so that repeated Prepare/Set cycles don't
     244                 :             :          * leak memory.
     245                 :             :          */
     246                 :           2 :         found = false;
     247   [ +  -  +  +  :           5 :         foreach(lc, ConvProcList)
                   +  + ]
     248                 :             :         {
     249                 :           3 :                 ConvProcInfo *convinfo = (ConvProcInfo *) lfirst(lc);
     250                 :             : 
     251   [ +  -  +  + ]:           3 :                 if (convinfo->s_encoding == current_server_encoding &&
     252                 :           3 :                         convinfo->c_encoding == encoding)
     253                 :             :                 {
     254         [ -  + ]:           2 :                         if (!found)
     255                 :             :                         {
     256                 :             :                                 /* Found newest entry, so set up */
     257                 :           2 :                                 ClientEncoding = &pg_enc2name_tbl[encoding];
     258                 :           2 :                                 ToServerConvProc = &convinfo->to_server_info;
     259                 :           2 :                                 ToClientConvProc = &convinfo->to_client_info;
     260                 :           2 :                                 found = true;
     261                 :           2 :                         }
     262                 :             :                         else
     263                 :             :                         {
     264                 :             :                                 /* Duplicate entry, release it */
     265                 :           0 :                                 ConvProcList = foreach_delete_current(ConvProcList, lc);
     266                 :           0 :                                 pfree(convinfo);
     267                 :             :                         }
     268                 :           2 :                 }
     269                 :           3 :         }
     270                 :             : 
     271         [ +  - ]:           2 :         if (found)
     272                 :           2 :                 return 0;                               /* success */
     273                 :             :         else
     274                 :           0 :                 return -1;                              /* it's not cached, so fail */
     275                 :        1605 : }
     276                 :             : 
     277                 :             : /*
     278                 :             :  * Initialize client encoding conversions.
     279                 :             :  *              Called from InitPostgres() once during backend startup.
     280                 :             :  */
     281                 :             : void
     282                 :         796 : InitializeClientEncoding(void)
     283                 :             : {
     284                 :         796 :         int                     current_server_encoding;
     285                 :             : 
     286         [ +  - ]:         796 :         Assert(!backend_startup_complete);
     287                 :         796 :         backend_startup_complete = true;
     288                 :             : 
     289         [ +  - ]:         796 :         if (PrepareClientEncoding(pending_client_encoding) < 0 ||
     290                 :         796 :                 SetClientEncoding(pending_client_encoding) < 0)
     291                 :             :         {
     292                 :             :                 /*
     293                 :             :                  * Oops, the requested conversion is not available. We couldn't fail
     294                 :             :                  * before, but we can now.
     295                 :             :                  */
     296   [ #  #  #  # ]:           0 :                 ereport(FATAL,
     297                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     298                 :             :                                  errmsg("conversion between %s and %s is not supported",
     299                 :             :                                                 pg_enc2name_tbl[pending_client_encoding].name,
     300                 :             :                                                 GetDatabaseEncodingName())));
     301                 :           0 :         }
     302                 :             : 
     303                 :             :         /*
     304                 :             :          * Also look up the UTF8-to-server conversion function if needed.  Since
     305                 :             :          * the server encoding is fixed within any one backend process, we don't
     306                 :             :          * have to do this more than once.
     307                 :             :          */
     308                 :         796 :         current_server_encoding = GetDatabaseEncoding();
     309   [ +  +  +  - ]:         796 :         if (current_server_encoding != PG_UTF8 &&
     310                 :           1 :                 current_server_encoding != PG_SQL_ASCII)
     311                 :             :         {
     312                 :           0 :                 Oid                     utf8_to_server_proc;
     313                 :             : 
     314                 :           0 :                 AssertCouldGetRelation();
     315                 :           0 :                 utf8_to_server_proc =
     316                 :           0 :                         FindDefaultConversionProc(PG_UTF8,
     317                 :           0 :                                                                           current_server_encoding);
     318                 :             :                 /* If there's no such conversion, just leave the pointer as NULL */
     319         [ #  # ]:           0 :                 if (OidIsValid(utf8_to_server_proc))
     320                 :             :                 {
     321                 :           0 :                         FmgrInfo   *finfo;
     322                 :             : 
     323                 :           0 :                         finfo = (FmgrInfo *) MemoryContextAlloc(TopMemoryContext,
     324                 :             :                                                                                                         sizeof(FmgrInfo));
     325                 :           0 :                         fmgr_info_cxt(utf8_to_server_proc, finfo,
     326                 :           0 :                                                   TopMemoryContext);
     327                 :             :                         /* Set Utf8ToServerConvProc only after data is fully valid */
     328                 :           0 :                         Utf8ToServerConvProc = finfo;
     329                 :           0 :                 }
     330                 :           0 :         }
     331                 :         796 : }
     332                 :             : 
     333                 :             : /*
     334                 :             :  * returns the current client encoding
     335                 :             :  */
     336                 :             : int
     337                 :         273 : pg_get_client_encoding(void)
     338                 :             : {
     339                 :         273 :         return ClientEncoding->encoding;
     340                 :             : }
     341                 :             : 
     342                 :             : /*
     343                 :             :  * returns the current client encoding name
     344                 :             :  */
     345                 :             : const char *
     346                 :           0 : pg_get_client_encoding_name(void)
     347                 :             : {
     348                 :           0 :         return ClientEncoding->name;
     349                 :             : }
     350                 :             : 
     351                 :             : /*
     352                 :             :  * Convert src string to another encoding (general case).
     353                 :             :  *
     354                 :             :  * See the notes about string conversion functions at the top of this file.
     355                 :             :  */
     356                 :             : unsigned char *
     357                 :         496 : pg_do_encoding_conversion(unsigned char *src, int len,
     358                 :             :                                                   int src_encoding, int dest_encoding)
     359                 :             : {
     360                 :         496 :         unsigned char *result;
     361                 :         496 :         Oid                     proc;
     362                 :             : 
     363         [ +  + ]:         496 :         if (len <= 0)
     364                 :           5 :                 return src;                             /* empty string is always valid */
     365                 :             : 
     366         [ +  + ]:         491 :         if (src_encoding == dest_encoding)
     367                 :         363 :                 return src;                             /* no conversion required, assume valid */
     368                 :             : 
     369         [ +  - ]:         128 :         if (dest_encoding == PG_SQL_ASCII)
     370                 :           0 :                 return src;                             /* any string is valid in SQL_ASCII */
     371                 :             : 
     372         [ +  - ]:         128 :         if (src_encoding == PG_SQL_ASCII)
     373                 :             :         {
     374                 :             :                 /* No conversion is possible, but we must validate the result */
     375                 :           0 :                 (void) pg_verify_mbstr(dest_encoding, (const char *) src, len, false);
     376                 :           0 :                 return src;
     377                 :             :         }
     378                 :             : 
     379         [ +  - ]:         128 :         if (!IsTransactionState())      /* shouldn't happen */
     380   [ #  #  #  # ]:           0 :                 elog(ERROR, "cannot perform encoding conversion outside a transaction");
     381                 :             : 
     382                 :         128 :         proc = FindDefaultConversionProc(src_encoding, dest_encoding);
     383         [ +  - ]:         128 :         if (!OidIsValid(proc))
     384   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     385                 :             :                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     386                 :             :                                  errmsg("default conversion function for encoding \"%s\" to \"%s\" does not exist",
     387                 :             :                                                 pg_encoding_to_char(src_encoding),
     388                 :             :                                                 pg_encoding_to_char(dest_encoding))));
     389                 :             : 
     390                 :             :         /*
     391                 :             :          * Allocate space for conversion result, being wary of integer overflow.
     392                 :             :          *
     393                 :             :          * len * MAX_CONVERSION_GROWTH is typically a vast overestimate of the
     394                 :             :          * required space, so it might exceed MaxAllocSize even though the result
     395                 :             :          * would actually fit.  We do not want to hand back a result string that
     396                 :             :          * exceeds MaxAllocSize, because callers might not cope gracefully --- but
     397                 :             :          * if we just allocate more than that, and don't use it, that's fine.
     398                 :             :          */
     399         [ +  - ]:         128 :         if ((Size) len >= (MaxAllocHugeSize / (Size) MAX_CONVERSION_GROWTH))
     400   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     401                 :             :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     402                 :             :                                  errmsg("out of memory"),
     403                 :             :                                  errdetail("String of %d bytes is too long for encoding conversion.",
     404                 :             :                                                    len)));
     405                 :             : 
     406                 :         128 :         result = (unsigned char *)
     407                 :         256 :                 MemoryContextAllocHuge(CurrentMemoryContext,
     408                 :         128 :                                                            (Size) len * MAX_CONVERSION_GROWTH + 1);
     409                 :             : 
     410                 :         128 :         (void) OidFunctionCall6(proc,
     411                 :             :                                                         Int32GetDatum(src_encoding),
     412                 :             :                                                         Int32GetDatum(dest_encoding),
     413                 :             :                                                         CStringGetDatum((char *) src),
     414                 :             :                                                         CStringGetDatum((char *) result),
     415                 :             :                                                         Int32GetDatum(len),
     416                 :             :                                                         BoolGetDatum(false));
     417                 :             : 
     418                 :             :         /*
     419                 :             :          * If the result is large, it's worth repalloc'ing to release any extra
     420                 :             :          * space we asked for.  The cutoff here is somewhat arbitrary, but we
     421                 :             :          * *must* check when len * MAX_CONVERSION_GROWTH exceeds MaxAllocSize.
     422                 :             :          */
     423         [ +  - ]:         128 :         if (len > 1000000)
     424                 :             :         {
     425                 :           0 :                 Size            resultlen = strlen((char *) result);
     426                 :             : 
     427         [ #  # ]:           0 :                 if (resultlen >= MaxAllocSize)
     428   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     429                 :             :                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     430                 :             :                                          errmsg("out of memory"),
     431                 :             :                                          errdetail("String of %d bytes is too long for encoding conversion.",
     432                 :             :                                                            len)));
     433                 :             : 
     434                 :           0 :                 result = (unsigned char *) repalloc(result, resultlen + 1);
     435                 :           0 :         }
     436                 :             : 
     437                 :         128 :         return result;
     438                 :         496 : }
     439                 :             : 
     440                 :             : /*
     441                 :             :  * Convert src string to another encoding.
     442                 :             :  *
     443                 :             :  * This function has a different API than the other conversion functions.
     444                 :             :  * The caller should've looked up the conversion function using
     445                 :             :  * FindDefaultConversionProc().  Unlike the other functions, the converted
     446                 :             :  * result is not palloc'd.  It is written to the caller-supplied buffer
     447                 :             :  * instead.
     448                 :             :  *
     449                 :             :  * src_encoding   - encoding to convert from
     450                 :             :  * dest_encoding  - encoding to convert to
     451                 :             :  * src, srclen    - input buffer and its length in bytes
     452                 :             :  * dest, destlen  - destination buffer and its size in bytes
     453                 :             :  *
     454                 :             :  * The output is null-terminated.
     455                 :             :  *
     456                 :             :  * If destlen < srclen * MAX_CONVERSION_INPUT_LENGTH + 1, the converted output
     457                 :             :  * wouldn't necessarily fit in the output buffer, and the function will not
     458                 :             :  * convert the whole input.
     459                 :             :  *
     460                 :             :  * TODO: The conversion function interface is not great.  Firstly, it
     461                 :             :  * would be nice to pass through the destination buffer size to the
     462                 :             :  * conversion function, so that if you pass a shorter destination buffer, it
     463                 :             :  * could still continue to fill up the whole buffer.  Currently, we have to
     464                 :             :  * assume worst case expansion and stop the conversion short, even if there
     465                 :             :  * is in fact space left in the destination buffer.  Secondly, it would be
     466                 :             :  * nice to return the number of bytes written to the caller, to avoid a call
     467                 :             :  * to strlen().
     468                 :             :  */
     469                 :             : int
     470                 :         968 : pg_do_encoding_conversion_buf(Oid proc,
     471                 :             :                                                           int src_encoding,
     472                 :             :                                                           int dest_encoding,
     473                 :             :                                                           unsigned char *src, int srclen,
     474                 :             :                                                           unsigned char *dest, int destlen,
     475                 :             :                                                           bool noError)
     476                 :             : {
     477                 :         968 :         Datum           result;
     478                 :             : 
     479                 :             :         /*
     480                 :             :          * If the destination buffer is not large enough to hold the result in the
     481                 :             :          * worst case, limit the input size passed to the conversion function.
     482                 :             :          */
     483         [ +  + ]:         968 :         if ((Size) srclen >= ((destlen - 1) / (Size) MAX_CONVERSION_GROWTH))
     484                 :         960 :                 srclen = ((destlen - 1) / (Size) MAX_CONVERSION_GROWTH);
     485                 :             : 
     486                 :         968 :         result = OidFunctionCall6(proc,
     487                 :             :                                                           Int32GetDatum(src_encoding),
     488                 :             :                                                           Int32GetDatum(dest_encoding),
     489                 :             :                                                           CStringGetDatum((char *) src),
     490                 :             :                                                           CStringGetDatum((char *) dest),
     491                 :             :                                                           Int32GetDatum(srclen),
     492                 :             :                                                           BoolGetDatum(noError));
     493                 :        1936 :         return DatumGetInt32(result);
     494                 :         968 : }
     495                 :             : 
     496                 :             : /*
     497                 :             :  * Convert string to encoding encoding_name. The source
     498                 :             :  * encoding is the DB encoding.
     499                 :             :  *
     500                 :             :  * BYTEA convert_to(TEXT string, NAME encoding_name)
     501                 :             :  */
     502                 :             : Datum
     503                 :          66 : pg_convert_to(PG_FUNCTION_ARGS)
     504                 :             : {
     505                 :          66 :         Datum           string = PG_GETARG_DATUM(0);
     506                 :          66 :         Datum           dest_encoding_name = PG_GETARG_DATUM(1);
     507                 :          66 :         Datum           src_encoding_name = DirectFunctionCall1(namein,
     508                 :             :                                                                                                                 CStringGetDatum(DatabaseEncoding->name));
     509                 :          66 :         Datum           result;
     510                 :             : 
     511                 :             :         /*
     512                 :             :          * pg_convert expects a bytea as its first argument. We're passing it a
     513                 :             :          * text argument here, relying on the fact that they are both in fact
     514                 :             :          * varlena types, and thus structurally identical.
     515                 :             :          */
     516                 :          66 :         result = DirectFunctionCall3(pg_convert, string,
     517                 :             :                                                                  src_encoding_name, dest_encoding_name);
     518                 :             : 
     519                 :         132 :         PG_RETURN_DATUM(result);
     520                 :          66 : }
     521                 :             : 
     522                 :             : /*
     523                 :             :  * Convert string from encoding encoding_name. The destination
     524                 :             :  * encoding is the DB encoding.
     525                 :             :  *
     526                 :             :  * TEXT convert_from(BYTEA string, NAME encoding_name)
     527                 :             :  */
     528                 :             : Datum
     529                 :          94 : pg_convert_from(PG_FUNCTION_ARGS)
     530                 :             : {
     531                 :          94 :         Datum           string = PG_GETARG_DATUM(0);
     532                 :          94 :         Datum           src_encoding_name = PG_GETARG_DATUM(1);
     533                 :          94 :         Datum           dest_encoding_name = DirectFunctionCall1(namein,
     534                 :             :                                                                                                                  CStringGetDatum(DatabaseEncoding->name));
     535                 :          94 :         Datum           result;
     536                 :             : 
     537                 :          94 :         result = DirectFunctionCall3(pg_convert, string,
     538                 :             :                                                                  src_encoding_name, dest_encoding_name);
     539                 :             : 
     540                 :             :         /*
     541                 :             :          * pg_convert returns a bytea, which we in turn return as text, relying on
     542                 :             :          * the fact that they are both in fact varlena types, and thus
     543                 :             :          * structurally identical. Although not all bytea values are valid text,
     544                 :             :          * in this case it will be because we've told pg_convert to return one
     545                 :             :          * that is valid as text in the current database encoding.
     546                 :             :          */
     547                 :         188 :         PG_RETURN_DATUM(result);
     548                 :          94 : }
     549                 :             : 
     550                 :             : /*
     551                 :             :  * Convert string between two arbitrary encodings.
     552                 :             :  *
     553                 :             :  * BYTEA convert(BYTEA string, NAME src_encoding_name, NAME dest_encoding_name)
     554                 :             :  */
     555                 :             : Datum
     556                 :         287 : pg_convert(PG_FUNCTION_ARGS)
     557                 :             : {
     558                 :         287 :         bytea      *string = PG_GETARG_BYTEA_PP(0);
     559                 :         287 :         char       *src_encoding_name = NameStr(*PG_GETARG_NAME(1));
     560                 :         287 :         int                     src_encoding = pg_char_to_encoding(src_encoding_name);
     561                 :         287 :         char       *dest_encoding_name = NameStr(*PG_GETARG_NAME(2));
     562                 :         287 :         int                     dest_encoding = pg_char_to_encoding(dest_encoding_name);
     563                 :         287 :         const char *src_str;
     564                 :         287 :         char       *dest_str;
     565                 :         287 :         bytea      *retval;
     566                 :         287 :         int                     len;
     567                 :             : 
     568         [ +  - ]:         287 :         if (src_encoding < 0)
     569   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     570                 :             :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     571                 :             :                                  errmsg("invalid source encoding name \"%s\"",
     572                 :             :                                                 src_encoding_name)));
     573         [ +  - ]:         287 :         if (dest_encoding < 0)
     574   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     575                 :             :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     576                 :             :                                  errmsg("invalid destination encoding name \"%s\"",
     577                 :             :                                                 dest_encoding_name)));
     578                 :             : 
     579                 :             :         /* make sure that source string is valid */
     580                 :         287 :         len = VARSIZE_ANY_EXHDR(string);
     581                 :         287 :         src_str = VARDATA_ANY(string);
     582                 :         287 :         (void) pg_verify_mbstr(src_encoding, src_str, len, false);
     583                 :             : 
     584                 :             :         /* perform conversion */
     585                 :         574 :         dest_str = (char *) pg_do_encoding_conversion((unsigned char *) unconstify(char *, src_str),
     586                 :         287 :                                                                                                   len,
     587                 :         287 :                                                                                                   src_encoding,
     588                 :         287 :                                                                                                   dest_encoding);
     589                 :             : 
     590                 :             : 
     591                 :             :         /* return source string if no conversion happened */
     592         [ +  + ]:         287 :         if (dest_str == src_str)
     593                 :         159 :                 PG_RETURN_BYTEA_P(string);
     594                 :             : 
     595                 :             :         /*
     596                 :             :          * build bytea data type structure.
     597                 :             :          */
     598                 :         128 :         len = strlen(dest_str);
     599                 :         128 :         retval = (bytea *) palloc(len + VARHDRSZ);
     600                 :         128 :         SET_VARSIZE(retval, len + VARHDRSZ);
     601                 :         128 :         memcpy(VARDATA(retval), dest_str, len);
     602                 :         128 :         pfree(dest_str);
     603                 :             : 
     604                 :             :         /* free memory if allocated by the toaster */
     605         [ +  - ]:         128 :         PG_FREE_IF_COPY(string, 0);
     606                 :             : 
     607                 :         128 :         PG_RETURN_BYTEA_P(retval);
     608                 :         287 : }
     609                 :             : 
     610                 :             : /*
     611                 :             :  * get the length of the string considered as text in the specified
     612                 :             :  * encoding. Raises an error if the data is not valid in that
     613                 :             :  * encoding.
     614                 :             :  *
     615                 :             :  * INT4 length (BYTEA string, NAME src_encoding_name)
     616                 :             :  */
     617                 :             : Datum
     618                 :           0 : length_in_encoding(PG_FUNCTION_ARGS)
     619                 :             : {
     620                 :           0 :         bytea      *string = PG_GETARG_BYTEA_PP(0);
     621                 :           0 :         char       *src_encoding_name = NameStr(*PG_GETARG_NAME(1));
     622                 :           0 :         int                     src_encoding = pg_char_to_encoding(src_encoding_name);
     623                 :           0 :         const char *src_str;
     624                 :           0 :         int                     len;
     625                 :           0 :         int                     retval;
     626                 :             : 
     627         [ #  # ]:           0 :         if (src_encoding < 0)
     628   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     629                 :             :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     630                 :             :                                  errmsg("invalid encoding name \"%s\"",
     631                 :             :                                                 src_encoding_name)));
     632                 :             : 
     633                 :           0 :         len = VARSIZE_ANY_EXHDR(string);
     634                 :           0 :         src_str = VARDATA_ANY(string);
     635                 :             : 
     636                 :           0 :         retval = pg_verify_mbstr_len(src_encoding, src_str, len, false);
     637                 :             : 
     638                 :           0 :         PG_RETURN_INT32(retval);
     639                 :           0 : }
     640                 :             : 
     641                 :             : /*
     642                 :             :  * Get maximum multibyte character length in the specified encoding.
     643                 :             :  *
     644                 :             :  * Note encoding is specified numerically, not by name as above.
     645                 :             :  */
     646                 :             : Datum
     647                 :           0 : pg_encoding_max_length_sql(PG_FUNCTION_ARGS)
     648                 :             : {
     649                 :           0 :         int                     encoding = PG_GETARG_INT32(0);
     650                 :             : 
     651   [ #  #  #  # ]:           0 :         if (PG_VALID_ENCODING(encoding))
     652                 :           0 :                 PG_RETURN_INT32(pg_wchar_table[encoding].maxmblen);
     653                 :             :         else
     654                 :           0 :                 PG_RETURN_NULL();
     655         [ #  # ]:           0 : }
     656                 :             : 
     657                 :             : /*
     658                 :             :  * Convert client encoding to server encoding.
     659                 :             :  *
     660                 :             :  * See the notes about string conversion functions at the top of this file.
     661                 :             :  */
     662                 :             : char *
     663                 :       59381 : pg_client_to_server(const char *s, int len)
     664                 :             : {
     665                 :       59381 :         return pg_any_to_server(s, len, ClientEncoding->encoding);
     666                 :             : }
     667                 :             : 
     668                 :             : /*
     669                 :             :  * Convert any encoding to server encoding.
     670                 :             :  *
     671                 :             :  * See the notes about string conversion functions at the top of this file.
     672                 :             :  *
     673                 :             :  * Unlike the other string conversion functions, this will apply validation
     674                 :             :  * even if encoding == DatabaseEncoding->encoding.  This is because this is
     675                 :             :  * used to process data coming in from outside the database, and we never
     676                 :             :  * want to just assume validity.
     677                 :             :  */
     678                 :             : char *
     679                 :       61876 : pg_any_to_server(const char *s, int len, int encoding)
     680                 :             : {
     681         [ +  + ]:       61876 :         if (len <= 0)
     682                 :         575 :                 return unconstify(char *, s);   /* empty string is always valid */
     683                 :             : 
     684   [ +  +  +  + ]:       61301 :         if (encoding == DatabaseEncoding->encoding ||
     685                 :         277 :                 encoding == PG_SQL_ASCII)
     686                 :             :         {
     687                 :             :                 /*
     688                 :             :                  * No conversion is needed, but we must still validate the data.
     689                 :             :                  */
     690                 :       61297 :                 (void) pg_verify_mbstr(DatabaseEncoding->encoding, s, len, false);
     691                 :       61297 :                 return unconstify(char *, s);
     692                 :             :         }
     693                 :             : 
     694         [ +  - ]:           4 :         if (DatabaseEncoding->encoding == PG_SQL_ASCII)
     695                 :             :         {
     696                 :             :                 /*
     697                 :             :                  * No conversion is possible, but we must still validate the data,
     698                 :             :                  * because the client-side code might have done string escaping using
     699                 :             :                  * the selected client_encoding.  If the client encoding is ASCII-safe
     700                 :             :                  * then we just do a straight validation under that encoding.  For an
     701                 :             :                  * ASCII-unsafe encoding we have a problem: we dare not pass such data
     702                 :             :                  * to the parser but we have no way to convert it.  We compromise by
     703                 :             :                  * rejecting the data if it contains any non-ASCII characters.
     704                 :             :                  */
     705   [ #  #  #  # ]:           0 :                 if (PG_VALID_BE_ENCODING(encoding))
     706                 :           0 :                         (void) pg_verify_mbstr(encoding, s, len, false);
     707                 :             :                 else
     708                 :             :                 {
     709                 :           0 :                         int                     i;
     710                 :             : 
     711         [ #  # ]:           0 :                         for (i = 0; i < len; i++)
     712                 :             :                         {
     713         [ #  # ]:           0 :                                 if (s[i] == '\0' || IS_HIGHBIT_SET(s[i]))
     714   [ #  #  #  # ]:           0 :                                         ereport(ERROR,
     715                 :             :                                                         (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE),
     716                 :             :                                                          errmsg("invalid byte value for encoding \"%s\": 0x%02x",
     717                 :             :                                                                         pg_enc2name_tbl[PG_SQL_ASCII].name,
     718                 :             :                                                                         (unsigned char) s[i])));
     719                 :           0 :                         }
     720                 :           0 :                 }
     721                 :           0 :                 return unconstify(char *, s);
     722                 :             :         }
     723                 :             : 
     724                 :             :         /* Fast path if we can use cached conversion function */
     725         [ +  - ]:           4 :         if (encoding == ClientEncoding->encoding)
     726                 :           4 :                 return perform_default_encoding_conversion(s, len, true);
     727                 :             : 
     728                 :             :         /* General case ... will not work outside transactions */
     729                 :           0 :         return (char *) pg_do_encoding_conversion((unsigned char *) unconstify(char *, s),
     730                 :           0 :                                                                                           len,
     731                 :           0 :                                                                                           encoding,
     732                 :           0 :                                                                                           DatabaseEncoding->encoding);
     733                 :       61876 : }
     734                 :             : 
     735                 :             : /*
     736                 :             :  * Convert server encoding to client encoding.
     737                 :             :  *
     738                 :             :  * See the notes about string conversion functions at the top of this file.
     739                 :             :  */
     740                 :             : char *
     741                 :      354262 : pg_server_to_client(const char *s, int len)
     742                 :             : {
     743                 :      354262 :         return pg_server_to_any(s, len, ClientEncoding->encoding);
     744                 :             : }
     745                 :             : 
     746                 :             : /*
     747                 :             :  * Convert server encoding to any encoding.
     748                 :             :  *
     749                 :             :  * See the notes about string conversion functions at the top of this file.
     750                 :             :  */
     751                 :             : char *
     752                 :      357295 : pg_server_to_any(const char *s, int len, int encoding)
     753                 :             : {
     754         [ +  + ]:      357295 :         if (len <= 0)
     755                 :        4741 :                 return unconstify(char *, s);   /* empty string is always valid */
     756                 :             : 
     757   [ +  +  -  + ]:      352554 :         if (encoding == DatabaseEncoding->encoding ||
     758                 :          12 :                 encoding == PG_SQL_ASCII)
     759                 :      352542 :                 return unconstify(char *, s);   /* assume data is valid */
     760                 :             : 
     761         [ +  - ]:          12 :         if (DatabaseEncoding->encoding == PG_SQL_ASCII)
     762                 :             :         {
     763                 :             :                 /* No conversion is possible, but we must validate the result */
     764                 :           0 :                 (void) pg_verify_mbstr(encoding, s, len, false);
     765                 :           0 :                 return unconstify(char *, s);
     766                 :             :         }
     767                 :             : 
     768                 :             :         /* Fast path if we can use cached conversion function */
     769         [ +  - ]:          12 :         if (encoding == ClientEncoding->encoding)
     770                 :          12 :                 return perform_default_encoding_conversion(s, len, false);
     771                 :             : 
     772                 :             :         /* General case ... will not work outside transactions */
     773                 :           0 :         return (char *) pg_do_encoding_conversion((unsigned char *) unconstify(char *, s),
     774                 :           0 :                                                                                           len,
     775                 :           0 :                                                                                           DatabaseEncoding->encoding,
     776                 :           0 :                                                                                           encoding);
     777                 :      357295 : }
     778                 :             : 
     779                 :             : /*
     780                 :             :  *      Perform default encoding conversion using cached FmgrInfo. Since
     781                 :             :  *      this function does not access database at all, it is safe to call
     782                 :             :  *      outside transactions.  If the conversion has not been set up by
     783                 :             :  *      SetClientEncoding(), no conversion is performed.
     784                 :             :  */
     785                 :             : static char *
     786                 :          16 : perform_default_encoding_conversion(const char *src, int len,
     787                 :             :                                                                         bool is_client_to_server)
     788                 :             : {
     789                 :          16 :         char       *result;
     790                 :          16 :         int                     src_encoding,
     791                 :             :                                 dest_encoding;
     792                 :          16 :         FmgrInfo   *flinfo;
     793                 :             : 
     794         [ +  + ]:          16 :         if (is_client_to_server)
     795                 :             :         {
     796                 :           4 :                 src_encoding = ClientEncoding->encoding;
     797                 :           4 :                 dest_encoding = DatabaseEncoding->encoding;
     798                 :           4 :                 flinfo = ToServerConvProc;
     799                 :           4 :         }
     800                 :             :         else
     801                 :             :         {
     802                 :          12 :                 src_encoding = DatabaseEncoding->encoding;
     803                 :          12 :                 dest_encoding = ClientEncoding->encoding;
     804                 :          12 :                 flinfo = ToClientConvProc;
     805                 :             :         }
     806                 :             : 
     807         [ +  - ]:          16 :         if (flinfo == NULL)
     808                 :           0 :                 return unconstify(char *, src);
     809                 :             : 
     810                 :             :         /*
     811                 :             :          * Allocate space for conversion result, being wary of integer overflow.
     812                 :             :          * See comments in pg_do_encoding_conversion.
     813                 :             :          */
     814         [ +  - ]:          16 :         if ((Size) len >= (MaxAllocHugeSize / (Size) MAX_CONVERSION_GROWTH))
     815   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     816                 :             :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     817                 :             :                                  errmsg("out of memory"),
     818                 :             :                                  errdetail("String of %d bytes is too long for encoding conversion.",
     819                 :             :                                                    len)));
     820                 :             : 
     821                 :          16 :         result = (char *)
     822                 :          32 :                 MemoryContextAllocHuge(CurrentMemoryContext,
     823                 :          16 :                                                            (Size) len * MAX_CONVERSION_GROWTH + 1);
     824                 :             : 
     825                 :          16 :         FunctionCall6(flinfo,
     826                 :             :                                   Int32GetDatum(src_encoding),
     827                 :             :                                   Int32GetDatum(dest_encoding),
     828                 :             :                                   CStringGetDatum(src),
     829                 :             :                                   CStringGetDatum(result),
     830                 :             :                                   Int32GetDatum(len),
     831                 :             :                                   BoolGetDatum(false));
     832                 :             : 
     833                 :             :         /*
     834                 :             :          * Release extra space if there might be a lot --- see comments in
     835                 :             :          * pg_do_encoding_conversion.
     836                 :             :          */
     837         [ +  - ]:          16 :         if (len > 1000000)
     838                 :             :         {
     839                 :           0 :                 Size            resultlen = strlen(result);
     840                 :             : 
     841         [ #  # ]:           0 :                 if (resultlen >= MaxAllocSize)
     842   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     843                 :             :                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     844                 :             :                                          errmsg("out of memory"),
     845                 :             :                                          errdetail("String of %d bytes is too long for encoding conversion.",
     846                 :             :                                                            len)));
     847                 :             : 
     848                 :           0 :                 result = (char *) repalloc(result, resultlen + 1);
     849                 :           0 :         }
     850                 :             : 
     851                 :          16 :         return result;
     852                 :          16 : }
     853                 :             : 
     854                 :             : /*
     855                 :             :  * Convert a single Unicode code point into a string in the server encoding.
     856                 :             :  *
     857                 :             :  * The code point given by "c" is converted and stored at *s, which must
     858                 :             :  * have at least MAX_UNICODE_EQUIVALENT_STRING+1 bytes available.
     859                 :             :  * The output will have a trailing '\0'.  Throws error if the conversion
     860                 :             :  * cannot be performed.
     861                 :             :  *
     862                 :             :  * Note that this relies on having previously looked up any required
     863                 :             :  * conversion function.  That's partly for speed but mostly because the parser
     864                 :             :  * may call this outside any transaction, or in an aborted transaction.
     865                 :             :  */
     866                 :             : void
     867                 :         142 : pg_unicode_to_server(char32_t c, unsigned char *s)
     868                 :             : {
     869                 :         142 :         unsigned char c_as_utf8[MAX_MULTIBYTE_CHAR_LEN + 1];
     870                 :         142 :         int                     c_as_utf8_len;
     871                 :         142 :         int                     server_encoding;
     872                 :             : 
     873                 :             :         /*
     874                 :             :          * Complain if invalid Unicode code point.  The choice of errcode here is
     875                 :             :          * debatable, but really our caller should have checked this anyway.
     876                 :             :          */
     877         [ +  - ]:         142 :         if (!is_valid_unicode_codepoint(c))
     878   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     879                 :             :                                 (errcode(ERRCODE_SYNTAX_ERROR),
     880                 :             :                                  errmsg("invalid Unicode code point")));
     881                 :             : 
     882                 :             :         /* Otherwise, if it's in ASCII range, conversion is trivial */
     883         [ +  + ]:         142 :         if (c <= 0x7F)
     884                 :             :         {
     885                 :          50 :                 s[0] = (unsigned char) c;
     886                 :          50 :                 s[1] = '\0';
     887                 :          50 :                 return;
     888                 :             :         }
     889                 :             : 
     890                 :             :         /* If the server encoding is UTF-8, we just need to reformat the code */
     891                 :          92 :         server_encoding = GetDatabaseEncoding();
     892         [ +  - ]:          92 :         if (server_encoding == PG_UTF8)
     893                 :             :         {
     894                 :          92 :                 unicode_to_utf8(c, s);
     895                 :          92 :                 s[pg_utf_mblen(s)] = '\0';
     896                 :          92 :                 return;
     897                 :             :         }
     898                 :             : 
     899                 :             :         /* For all other cases, we must have a conversion function available */
     900         [ #  # ]:           0 :         if (Utf8ToServerConvProc == NULL)
     901   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     902                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     903                 :             :                                  errmsg("conversion between %s and %s is not supported",
     904                 :             :                                                 pg_enc2name_tbl[PG_UTF8].name,
     905                 :             :                                                 GetDatabaseEncodingName())));
     906                 :             : 
     907                 :             :         /* Construct UTF-8 source string */
     908                 :           0 :         unicode_to_utf8(c, c_as_utf8);
     909                 :           0 :         c_as_utf8_len = pg_utf_mblen(c_as_utf8);
     910                 :           0 :         c_as_utf8[c_as_utf8_len] = '\0';
     911                 :             : 
     912                 :             :         /* Convert, or throw error if we can't */
     913                 :           0 :         FunctionCall6(Utf8ToServerConvProc,
     914                 :             :                                   Int32GetDatum(PG_UTF8),
     915                 :             :                                   Int32GetDatum(server_encoding),
     916                 :             :                                   CStringGetDatum((char *) c_as_utf8),
     917                 :             :                                   CStringGetDatum((char *) s),
     918                 :             :                                   Int32GetDatum(c_as_utf8_len),
     919                 :             :                                   BoolGetDatum(false));
     920         [ -  + ]:         142 : }
     921                 :             : 
     922                 :             : /*
     923                 :             :  * Convert a single Unicode code point into a string in the server encoding.
     924                 :             :  *
     925                 :             :  * Same as pg_unicode_to_server(), except that we don't throw errors,
     926                 :             :  * but simply return false on conversion failure.
     927                 :             :  */
     928                 :             : bool
     929                 :          14 : pg_unicode_to_server_noerror(char32_t c, unsigned char *s)
     930                 :             : {
     931                 :          14 :         unsigned char c_as_utf8[MAX_MULTIBYTE_CHAR_LEN + 1];
     932                 :          14 :         int                     c_as_utf8_len;
     933                 :          14 :         int                     converted_len;
     934                 :          14 :         int                     server_encoding;
     935                 :             : 
     936                 :             :         /* Fail if invalid Unicode code point */
     937         [ -  + ]:          14 :         if (!is_valid_unicode_codepoint(c))
     938                 :           0 :                 return false;
     939                 :             : 
     940                 :             :         /* Otherwise, if it's in ASCII range, conversion is trivial */
     941         [ +  + ]:          14 :         if (c <= 0x7F)
     942                 :             :         {
     943                 :           4 :                 s[0] = (unsigned char) c;
     944                 :           4 :                 s[1] = '\0';
     945                 :           4 :                 return true;
     946                 :             :         }
     947                 :             : 
     948                 :             :         /* If the server encoding is UTF-8, we just need to reformat the code */
     949                 :          10 :         server_encoding = GetDatabaseEncoding();
     950         [ +  - ]:          10 :         if (server_encoding == PG_UTF8)
     951                 :             :         {
     952                 :          10 :                 unicode_to_utf8(c, s);
     953                 :          10 :                 s[pg_utf_mblen(s)] = '\0';
     954                 :          10 :                 return true;
     955                 :             :         }
     956                 :             : 
     957                 :             :         /* For all other cases, we must have a conversion function available */
     958         [ #  # ]:           0 :         if (Utf8ToServerConvProc == NULL)
     959                 :           0 :                 return false;
     960                 :             : 
     961                 :             :         /* Construct UTF-8 source string */
     962                 :           0 :         unicode_to_utf8(c, c_as_utf8);
     963                 :           0 :         c_as_utf8_len = pg_utf_mblen(c_as_utf8);
     964                 :           0 :         c_as_utf8[c_as_utf8_len] = '\0';
     965                 :             : 
     966                 :             :         /* Convert, but without throwing error if we can't */
     967                 :           0 :         converted_len = DatumGetInt32(FunctionCall6(Utf8ToServerConvProc,
     968                 :             :                                                                                                 Int32GetDatum(PG_UTF8),
     969                 :             :                                                                                                 Int32GetDatum(server_encoding),
     970                 :             :                                                                                                 CStringGetDatum((char *) c_as_utf8),
     971                 :             :                                                                                                 CStringGetDatum((char *) s),
     972                 :             :                                                                                                 Int32GetDatum(c_as_utf8_len),
     973                 :             :                                                                                                 BoolGetDatum(true)));
     974                 :             : 
     975                 :             :         /* Conversion was successful iff it consumed the whole input */
     976                 :           0 :         return (converted_len == c_as_utf8_len);
     977                 :          14 : }
     978                 :             : 
     979                 :             : 
     980                 :             : /* convert a multibyte string to a wchar */
     981                 :             : int
     982                 :           0 : pg_mb2wchar(const char *from, pg_wchar *to)
     983                 :             : {
     984                 :           0 :         return pg_wchar_table[DatabaseEncoding->encoding].mb2wchar_with_len((const unsigned char *) from, to, strlen(from));
     985                 :             : }
     986                 :             : 
     987                 :             : /* convert a multibyte string to a wchar with a limited length */
     988                 :             : int
     989                 :     1145458 : pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len)
     990                 :             : {
     991                 :     1145458 :         return pg_wchar_table[DatabaseEncoding->encoding].mb2wchar_with_len((const unsigned char *) from, to, len);
     992                 :             : }
     993                 :             : 
     994                 :             : /* same, with any encoding */
     995                 :             : int
     996                 :        3033 : pg_encoding_mb2wchar_with_len(int encoding,
     997                 :             :                                                           const char *from, pg_wchar *to, int len)
     998                 :             : {
     999                 :        3033 :         return pg_wchar_table[encoding].mb2wchar_with_len((const unsigned char *) from, to, len);
    1000                 :             : }
    1001                 :             : 
    1002                 :             : /* convert a wchar string to a multibyte */
    1003                 :             : int
    1004                 :           0 : pg_wchar2mb(const pg_wchar *from, char *to)
    1005                 :             : {
    1006                 :           0 :         return pg_wchar_table[DatabaseEncoding->encoding].wchar2mb_with_len(from, (unsigned char *) to, pg_wchar_strlen(from));
    1007                 :             : }
    1008                 :             : 
    1009                 :             : /* convert a wchar string to a multibyte with a limited length */
    1010                 :             : int
    1011                 :       18424 : pg_wchar2mb_with_len(const pg_wchar *from, char *to, int len)
    1012                 :             : {
    1013                 :       18424 :         return pg_wchar_table[DatabaseEncoding->encoding].wchar2mb_with_len(from, (unsigned char *) to, len);
    1014                 :             : }
    1015                 :             : 
    1016                 :             : /* same, with any encoding */
    1017                 :             : int
    1018                 :           0 : pg_encoding_wchar2mb_with_len(int encoding,
    1019                 :             :                                                           const pg_wchar *from, char *to, int len)
    1020                 :             : {
    1021                 :           0 :         return pg_wchar_table[encoding].wchar2mb_with_len(from, (unsigned char *) to, len);
    1022                 :             : }
    1023                 :             : 
    1024                 :             : /* returns the byte length of a multibyte character */
    1025                 :             : int
    1026                 :    34114179 : pg_mblen(const char *mbstr)
    1027                 :             : {
    1028                 :    34114179 :         return pg_wchar_table[DatabaseEncoding->encoding].mblen((const unsigned char *) mbstr);
    1029                 :             : }
    1030                 :             : 
    1031                 :             : /* returns the display length of a multibyte character */
    1032                 :             : int
    1033                 :        1454 : pg_dsplen(const char *mbstr)
    1034                 :             : {
    1035                 :        1454 :         return pg_wchar_table[DatabaseEncoding->encoding].dsplen((const unsigned char *) mbstr);
    1036                 :             : }
    1037                 :             : 
    1038                 :             : /* returns the length (counted in wchars) of a multibyte string */
    1039                 :             : int
    1040                 :         117 : pg_mbstrlen(const char *mbstr)
    1041                 :             : {
    1042                 :         117 :         int                     len = 0;
    1043                 :             : 
    1044                 :             :         /* optimization for single byte encoding */
    1045         [ -  + ]:         117 :         if (pg_database_encoding_max_length() == 1)
    1046                 :           0 :                 return strlen(mbstr);
    1047                 :             : 
    1048         [ +  + ]:         271 :         while (*mbstr)
    1049                 :             :         {
    1050                 :         154 :                 mbstr += pg_mblen(mbstr);
    1051                 :         154 :                 len++;
    1052                 :             :         }
    1053                 :         117 :         return len;
    1054                 :         117 : }
    1055                 :             : 
    1056                 :             : /* returns the length (counted in wchars) of a multibyte string
    1057                 :             :  * (not necessarily NULL terminated)
    1058                 :             :  */
    1059                 :             : int
    1060                 :      118334 : pg_mbstrlen_with_len(const char *mbstr, int limit)
    1061                 :             : {
    1062                 :      118334 :         int                     len = 0;
    1063                 :             : 
    1064                 :             :         /* optimization for single byte encoding */
    1065         [ -  + ]:      118334 :         if (pg_database_encoding_max_length() == 1)
    1066                 :           0 :                 return limit;
    1067                 :             : 
    1068   [ +  +  +  + ]:    31526192 :         while (limit > 0 && *mbstr)
    1069                 :             :         {
    1070                 :    31407858 :                 int                     l = pg_mblen(mbstr);
    1071                 :             : 
    1072                 :    31407858 :                 limit -= l;
    1073                 :    31407858 :                 mbstr += l;
    1074                 :    31407858 :                 len++;
    1075                 :    31407858 :         }
    1076                 :      118334 :         return len;
    1077                 :      118334 : }
    1078                 :             : 
    1079                 :             : /*
    1080                 :             :  * returns the byte length of a multibyte string
    1081                 :             :  * (not necessarily NULL terminated)
    1082                 :             :  * that is no longer than limit.
    1083                 :             :  * this function does not break multibyte character boundary.
    1084                 :             :  */
    1085                 :             : int
    1086                 :       20393 : pg_mbcliplen(const char *mbstr, int len, int limit)
    1087                 :             : {
    1088                 :       40786 :         return pg_encoding_mbcliplen(DatabaseEncoding->encoding, mbstr,
    1089                 :       20393 :                                                                  len, limit);
    1090                 :             : }
    1091                 :             : 
    1092                 :             : /*
    1093                 :             :  * pg_mbcliplen with specified encoding; string must be valid in encoding
    1094                 :             :  */
    1095                 :             : int
    1096                 :       20393 : pg_encoding_mbcliplen(int encoding, const char *mbstr,
    1097                 :             :                                           int len, int limit)
    1098                 :             : {
    1099                 :       20393 :         mblen_converter mblen_fn;
    1100                 :       20393 :         int                     clen = 0;
    1101                 :       20393 :         int                     l;
    1102                 :             : 
    1103                 :             :         /* optimization for single byte encoding */
    1104         [ +  + ]:       20393 :         if (pg_encoding_max_length(encoding) == 1)
    1105                 :         130 :                 return cliplen(mbstr, len, limit);
    1106                 :             : 
    1107                 :       20263 :         mblen_fn = pg_wchar_table[encoding].mblen;
    1108                 :             : 
    1109   [ +  +  +  + ]:      155939 :         while (len > 0 && *mbstr)
    1110                 :             :         {
    1111                 :      148401 :                 l = (*mblen_fn) ((const unsigned char *) mbstr);
    1112         [ +  + ]:      148401 :                 if ((clen + l) > limit)
    1113                 :          12 :                         break;
    1114                 :      148389 :                 clen += l;
    1115         [ +  + ]:      148389 :                 if (clen == limit)
    1116                 :       12713 :                         break;
    1117                 :      135676 :                 len -= l;
    1118                 :      135676 :                 mbstr += l;
    1119                 :             :         }
    1120                 :       20263 :         return clen;
    1121                 :       20393 : }
    1122                 :             : 
    1123                 :             : /*
    1124                 :             :  * Similar to pg_mbcliplen except the limit parameter specifies the
    1125                 :             :  * character length, not the byte length.
    1126                 :             :  */
    1127                 :             : int
    1128                 :          88 : pg_mbcharcliplen(const char *mbstr, int len, int limit)
    1129                 :             : {
    1130                 :          88 :         int                     clen = 0;
    1131                 :          88 :         int                     nch = 0;
    1132                 :          88 :         int                     l;
    1133                 :             : 
    1134                 :             :         /* optimization for single byte encoding */
    1135         [ -  + ]:          88 :         if (pg_database_encoding_max_length() == 1)
    1136                 :           0 :                 return cliplen(mbstr, len, limit);
    1137                 :             : 
    1138   [ +  +  +  + ]:         388 :         while (len > 0 && *mbstr)
    1139                 :             :         {
    1140                 :         385 :                 l = pg_mblen(mbstr);
    1141                 :         385 :                 nch++;
    1142         [ +  + ]:         385 :                 if (nch > limit)
    1143                 :          85 :                         break;
    1144                 :         300 :                 clen += l;
    1145                 :         300 :                 len -= l;
    1146                 :         300 :                 mbstr += l;
    1147                 :             :         }
    1148                 :          88 :         return clen;
    1149                 :          88 : }
    1150                 :             : 
    1151                 :             : /* mbcliplen for any single-byte encoding */
    1152                 :             : static int
    1153                 :         130 : cliplen(const char *str, int len, int limit)
    1154                 :             : {
    1155                 :         130 :         int                     l = 0;
    1156                 :             : 
    1157         [ +  + ]:         130 :         len = Min(len, limit);
    1158   [ +  +  +  + ]:         922 :         while (l < len && str[l])
    1159                 :         792 :                 l++;
    1160                 :         260 :         return l;
    1161                 :         130 : }
    1162                 :             : 
    1163                 :             : void
    1164                 :         795 : SetDatabaseEncoding(int encoding)
    1165                 :             : {
    1166         [ +  - ]:         795 :         if (!PG_VALID_BE_ENCODING(encoding))
    1167   [ #  #  #  # ]:           0 :                 elog(ERROR, "invalid database encoding: %d", encoding);
    1168                 :             : 
    1169                 :         795 :         DatabaseEncoding = &pg_enc2name_tbl[encoding];
    1170         [ +  - ]:         795 :         Assert(DatabaseEncoding->encoding == encoding);
    1171                 :         795 : }
    1172                 :             : 
    1173                 :             : void
    1174                 :         803 : SetMessageEncoding(int encoding)
    1175                 :             : {
    1176                 :             :         /* Some calls happen before we can elog()! */
    1177         [ +  - ]:         803 :         Assert(PG_VALID_ENCODING(encoding));
    1178                 :             : 
    1179                 :         803 :         MessageEncoding = &pg_enc2name_tbl[encoding];
    1180         [ +  - ]:         803 :         Assert(MessageEncoding->encoding == encoding);
    1181                 :         803 : }
    1182                 :             : 
    1183                 :             : #ifdef ENABLE_NLS
    1184                 :             : /*
    1185                 :             :  * Make one bind_textdomain_codeset() call, translating a pg_enc to a gettext
    1186                 :             :  * codeset.  Fails for MULE_INTERNAL, an encoding unknown to gettext; can also
    1187                 :             :  * fail for gettext-internal causes like out-of-memory.
    1188                 :             :  */
    1189                 :             : static bool
    1190                 :           0 : raw_pg_bind_textdomain_codeset(const char *domainname, int encoding)
    1191                 :             : {
    1192                 :           0 :         bool            elog_ok = (CurrentMemoryContext != NULL);
    1193                 :             : 
    1194   [ #  #  #  #  :           0 :         if (!PG_VALID_ENCODING(encoding) || pg_enc2gettext_tbl[encoding] == NULL)
                   #  # ]
    1195                 :           0 :                 return false;
    1196                 :             : 
    1197                 :           0 :         if (bind_textdomain_codeset(domainname,
    1198   [ #  #  #  # ]:           0 :                                                                 pg_enc2gettext_tbl[encoding]) != NULL)
    1199                 :           0 :                 return true;
    1200                 :             : 
    1201         [ #  # ]:           0 :         if (elog_ok)
    1202   [ #  #  #  # ]:           0 :                 elog(LOG, "bind_textdomain_codeset failed");
    1203                 :             :         else
    1204                 :           0 :                 write_stderr("bind_textdomain_codeset failed");
    1205                 :             : 
    1206                 :           0 :         return false;
    1207                 :           0 : }
    1208                 :             : 
    1209                 :             : /*
    1210                 :             :  * Bind a gettext message domain to the codeset corresponding to the database
    1211                 :             :  * encoding.  For SQL_ASCII, instead bind to the codeset implied by LC_CTYPE.
    1212                 :             :  * Return the MessageEncoding implied by the new settings.
    1213                 :             :  *
    1214                 :             :  * On most platforms, gettext defaults to the codeset implied by LC_CTYPE.
    1215                 :             :  * When that matches the database encoding, we don't need to do anything.  In
    1216                 :             :  * CREATE DATABASE, we enforce or trust that the locale's codeset matches the
    1217                 :             :  * database encoding, except for the C locale.  (On Windows, we also permit a
    1218                 :             :  * discrepancy under the UTF8 encoding.)  For the C locale, explicitly bind
    1219                 :             :  * gettext to the right codeset.
    1220                 :             :  *
    1221                 :             :  * On Windows, gettext defaults to the Windows ANSI code page.  This is a
    1222                 :             :  * convenient departure for software that passes the strings to Windows ANSI
    1223                 :             :  * APIs, but we don't do that.  Compel gettext to use database encoding or,
    1224                 :             :  * failing that, the LC_CTYPE encoding as it would on other platforms.
    1225                 :             :  *
    1226                 :             :  * This function is called before elog() and palloc() are usable.
    1227                 :             :  */
    1228                 :             : int
    1229                 :        1276 : pg_bind_textdomain_codeset(const char *domainname)
    1230                 :             : {
    1231                 :        1276 :         bool            elog_ok = (CurrentMemoryContext != NULL);
    1232                 :        1276 :         int                     encoding = GetDatabaseEncoding();
    1233                 :        1276 :         int                     new_msgenc;
    1234                 :             : 
    1235                 :             : #ifndef WIN32
    1236                 :        1276 :         const char *ctype = setlocale(LC_CTYPE, NULL);
    1237                 :             : 
    1238   [ +  -  +  - ]:        1276 :         if (pg_strcasecmp(ctype, "C") == 0 || pg_strcasecmp(ctype, "POSIX") == 0)
    1239                 :             : #endif
    1240   [ #  #  #  # ]:           0 :                 if (encoding != PG_SQL_ASCII &&
    1241                 :           0 :                         raw_pg_bind_textdomain_codeset(domainname, encoding))
    1242                 :           0 :                         return encoding;
    1243                 :             : 
    1244                 :        1276 :         new_msgenc = pg_get_encoding_from_locale(NULL, elog_ok);
    1245         [ +  - ]:        1276 :         if (new_msgenc < 0)
    1246                 :           0 :                 new_msgenc = PG_SQL_ASCII;
    1247                 :             : 
    1248                 :             : #ifdef WIN32
    1249                 :             :         if (!raw_pg_bind_textdomain_codeset(domainname, new_msgenc))
    1250                 :             :                 /* On failure, the old message encoding remains valid. */
    1251                 :             :                 return GetMessageEncoding();
    1252                 :             : #endif
    1253                 :             : 
    1254                 :        1276 :         return new_msgenc;
    1255                 :        1276 : }
    1256                 :             : #endif
    1257                 :             : 
    1258                 :             : /*
    1259                 :             :  * The database encoding, also called the server encoding, represents the
    1260                 :             :  * encoding of data stored in text-like data types.  Affected types include
    1261                 :             :  * cstring, text, varchar, name, xml, and json.
    1262                 :             :  */
    1263                 :             : int
    1264                 :     1585596 : GetDatabaseEncoding(void)
    1265                 :             : {
    1266                 :     1585596 :         return DatabaseEncoding->encoding;
    1267                 :             : }
    1268                 :             : 
    1269                 :             : const char *
    1270                 :        1597 : GetDatabaseEncodingName(void)
    1271                 :             : {
    1272                 :        1597 :         return DatabaseEncoding->name;
    1273                 :             : }
    1274                 :             : 
    1275                 :             : Datum
    1276                 :          13 : getdatabaseencoding(PG_FUNCTION_ARGS)
    1277                 :             : {
    1278                 :          13 :         return DirectFunctionCall1(namein, CStringGetDatum(DatabaseEncoding->name));
    1279                 :             : }
    1280                 :             : 
    1281                 :             : Datum
    1282                 :           0 : pg_client_encoding(PG_FUNCTION_ARGS)
    1283                 :             : {
    1284                 :           0 :         return DirectFunctionCall1(namein, CStringGetDatum(ClientEncoding->name));
    1285                 :             : }
    1286                 :             : 
    1287                 :             : Datum
    1288                 :           6 : PG_char_to_encoding(PG_FUNCTION_ARGS)
    1289                 :             : {
    1290                 :           6 :         Name            s = PG_GETARG_NAME(0);
    1291                 :             : 
    1292                 :          12 :         PG_RETURN_INT32(pg_char_to_encoding(NameStr(*s)));
    1293                 :           6 : }
    1294                 :             : 
    1295                 :             : Datum
    1296                 :         512 : PG_encoding_to_char(PG_FUNCTION_ARGS)
    1297                 :             : {
    1298                 :         512 :         int32           encoding = PG_GETARG_INT32(0);
    1299                 :         512 :         const char *encoding_name = pg_encoding_to_char(encoding);
    1300                 :             : 
    1301                 :        1024 :         return DirectFunctionCall1(namein, CStringGetDatum(encoding_name));
    1302                 :         512 : }
    1303                 :             : 
    1304                 :             : /*
    1305                 :             :  * gettext() returns messages in this encoding.  This often matches the
    1306                 :             :  * database encoding, but it differs for SQL_ASCII databases, for processes
    1307                 :             :  * not attached to a database, and under a database encoding lacking iconv
    1308                 :             :  * support (MULE_INTERNAL).
    1309                 :             :  */
    1310                 :             : int
    1311                 :           0 : GetMessageEncoding(void)
    1312                 :             : {
    1313                 :           0 :         return MessageEncoding->encoding;
    1314                 :             : }
    1315                 :             : 
    1316                 :             : 
    1317                 :             : /*
    1318                 :             :  * Generic character incrementer function.
    1319                 :             :  *
    1320                 :             :  * Not knowing anything about the properties of the encoding in use, we just
    1321                 :             :  * keep incrementing the last byte until we get a validly-encoded result,
    1322                 :             :  * or we run out of values to try.  We don't bother to try incrementing
    1323                 :             :  * higher-order bytes, so there's no growth in runtime for wider characters.
    1324                 :             :  * (If we did try to do that, we'd need to consider the likelihood that 255
    1325                 :             :  * is not a valid final byte in the encoding.)
    1326                 :             :  */
    1327                 :             : static bool
    1328                 :           0 : pg_generic_charinc(unsigned char *charptr, int len)
    1329                 :             : {
    1330                 :           0 :         unsigned char *lastbyte = charptr + len - 1;
    1331                 :           0 :         mbchar_verifier mbverify;
    1332                 :             : 
    1333                 :             :         /* We can just invoke the character verifier directly. */
    1334                 :           0 :         mbverify = pg_wchar_table[GetDatabaseEncoding()].mbverifychar;
    1335                 :             : 
    1336         [ #  # ]:           0 :         while (*lastbyte < (unsigned char) 255)
    1337                 :             :         {
    1338                 :           0 :                 (*lastbyte)++;
    1339         [ #  # ]:           0 :                 if ((*mbverify) (charptr, len) == len)
    1340                 :           0 :                         return true;
    1341                 :             :         }
    1342                 :             : 
    1343                 :           0 :         return false;
    1344                 :           0 : }
    1345                 :             : 
    1346                 :             : /*
    1347                 :             :  * UTF-8 character incrementer function.
    1348                 :             :  *
    1349                 :             :  * For a one-byte character less than 0x7F, we just increment the byte.
    1350                 :             :  *
    1351                 :             :  * For a multibyte character, every byte but the first must fall between 0x80
    1352                 :             :  * and 0xBF; and the first byte must be between 0xC0 and 0xF4.  We increment
    1353                 :             :  * the last byte that's not already at its maximum value.  If we can't find a
    1354                 :             :  * byte that's less than the maximum allowable value, we simply fail.  We also
    1355                 :             :  * need some special-case logic to skip regions used for surrogate pair
    1356                 :             :  * handling, as those should not occur in valid UTF-8.
    1357                 :             :  *
    1358                 :             :  * Note that we don't reset lower-order bytes back to their minimums, since
    1359                 :             :  * we can't afford to make an exhaustive search (see make_greater_string).
    1360                 :             :  */
    1361                 :             : static bool
    1362                 :         231 : pg_utf8_increment(unsigned char *charptr, int length)
    1363                 :             : {
    1364                 :         231 :         unsigned char a;
    1365                 :         231 :         unsigned char limit;
    1366                 :             : 
    1367   [ -  -  +  -  :         231 :         switch (length)
                      - ]
    1368                 :             :         {
    1369                 :             :                 default:
    1370                 :             :                         /* reject lengths 5 and 6 for now */
    1371                 :           0 :                         return false;
    1372                 :             :                 case 4:
    1373                 :           0 :                         a = charptr[3];
    1374         [ #  # ]:           0 :                         if (a < 0xBF)
    1375                 :             :                         {
    1376                 :           0 :                                 charptr[3]++;
    1377                 :           0 :                                 break;
    1378                 :             :                         }
    1379                 :             :                         /* FALL THRU */
    1380                 :             :                 case 3:
    1381                 :           0 :                         a = charptr[2];
    1382         [ #  # ]:           0 :                         if (a < 0xBF)
    1383                 :             :                         {
    1384                 :           0 :                                 charptr[2]++;
    1385                 :           0 :                                 break;
    1386                 :             :                         }
    1387                 :             :                         /* FALL THRU */
    1388                 :             :                 case 2:
    1389                 :           0 :                         a = charptr[1];
    1390      [ #  #  # ]:           0 :                         switch (*charptr)
    1391                 :             :                         {
    1392                 :             :                                 case 0xED:
    1393                 :           0 :                                         limit = 0x9F;
    1394                 :           0 :                                         break;
    1395                 :             :                                 case 0xF4:
    1396                 :           0 :                                         limit = 0x8F;
    1397                 :           0 :                                         break;
    1398                 :             :                                 default:
    1399                 :           0 :                                         limit = 0xBF;
    1400                 :           0 :                                         break;
    1401                 :             :                         }
    1402         [ #  # ]:           0 :                         if (a < limit)
    1403                 :             :                         {
    1404                 :           0 :                                 charptr[1]++;
    1405                 :           0 :                                 break;
    1406                 :             :                         }
    1407                 :             :                         /* FALL THRU */
    1408                 :             :                 case 1:
    1409                 :         231 :                         a = *charptr;
    1410   [ +  -  +  -  :         231 :                         if (a == 0x7F || a == 0xDF || a == 0xEF || a == 0xF4)
             +  -  -  + ]
    1411                 :           0 :                                 return false;
    1412                 :         231 :                         charptr[0]++;
    1413                 :         231 :                         break;
    1414                 :             :         }
    1415                 :             : 
    1416                 :         231 :         return true;
    1417                 :         231 : }
    1418                 :             : 
    1419                 :             : /*
    1420                 :             :  * EUC-JP character incrementer function.
    1421                 :             :  *
    1422                 :             :  * If the sequence starts with SS2 (0x8e), it must be a two-byte sequence
    1423                 :             :  * representing JIS X 0201 characters with the second byte ranging between
    1424                 :             :  * 0xa1 and 0xdf.  We just increment the last byte if it's less than 0xdf,
    1425                 :             :  * and otherwise rewrite the whole sequence to 0xa1 0xa1.
    1426                 :             :  *
    1427                 :             :  * If the sequence starts with SS3 (0x8f), it must be a three-byte sequence
    1428                 :             :  * in which the last two bytes range between 0xa1 and 0xfe.  The last byte
    1429                 :             :  * is incremented if possible, otherwise the second-to-last byte.
    1430                 :             :  *
    1431                 :             :  * If the sequence starts with a value other than the above and its MSB
    1432                 :             :  * is set, it must be a two-byte sequence representing JIS X 0208 characters
    1433                 :             :  * with both bytes ranging between 0xa1 and 0xfe.  The last byte is
    1434                 :             :  * incremented if possible, otherwise the second-to-last byte.
    1435                 :             :  *
    1436                 :             :  * Otherwise, the sequence is a single-byte ASCII character. It is
    1437                 :             :  * incremented up to 0x7f.
    1438                 :             :  */
    1439                 :             : static bool
    1440                 :           0 : pg_eucjp_increment(unsigned char *charptr, int length)
    1441                 :             : {
    1442                 :           0 :         unsigned char c1,
    1443                 :             :                                 c2;
    1444                 :           0 :         int                     i;
    1445                 :             : 
    1446                 :           0 :         c1 = *charptr;
    1447                 :             : 
    1448      [ #  #  # ]:           0 :         switch (c1)
    1449                 :             :         {
    1450                 :             :                 case SS2:                               /* JIS X 0201 */
    1451         [ #  # ]:           0 :                         if (length != 2)
    1452                 :           0 :                                 return false;
    1453                 :             : 
    1454                 :           0 :                         c2 = charptr[1];
    1455                 :             : 
    1456         [ #  # ]:           0 :                         if (c2 >= 0xdf)
    1457                 :           0 :                                 charptr[0] = charptr[1] = 0xa1;
    1458         [ #  # ]:           0 :                         else if (c2 < 0xa1)
    1459                 :           0 :                                 charptr[1] = 0xa1;
    1460                 :             :                         else
    1461                 :           0 :                                 charptr[1]++;
    1462                 :           0 :                         break;
    1463                 :             : 
    1464                 :             :                 case SS3:                               /* JIS X 0212 */
    1465         [ #  # ]:           0 :                         if (length != 3)
    1466                 :           0 :                                 return false;
    1467                 :             : 
    1468         [ #  # ]:           0 :                         for (i = 2; i > 0; i--)
    1469                 :             :                         {
    1470                 :           0 :                                 c2 = charptr[i];
    1471         [ #  # ]:           0 :                                 if (c2 < 0xa1)
    1472                 :             :                                 {
    1473                 :           0 :                                         charptr[i] = 0xa1;
    1474                 :           0 :                                         return true;
    1475                 :             :                                 }
    1476         [ #  # ]:           0 :                                 else if (c2 < 0xfe)
    1477                 :             :                                 {
    1478                 :           0 :                                         charptr[i]++;
    1479                 :           0 :                                         return true;
    1480                 :             :                                 }
    1481                 :           0 :                         }
    1482                 :             : 
    1483                 :             :                         /* Out of 3-byte code region */
    1484                 :           0 :                         return false;
    1485                 :             : 
    1486                 :             :                 default:
    1487         [ #  # ]:           0 :                         if (IS_HIGHBIT_SET(c1)) /* JIS X 0208? */
    1488                 :             :                         {
    1489         [ #  # ]:           0 :                                 if (length != 2)
    1490                 :           0 :                                         return false;
    1491                 :             : 
    1492         [ #  # ]:           0 :                                 for (i = 1; i >= 0; i--)
    1493                 :             :                                 {
    1494                 :           0 :                                         c2 = charptr[i];
    1495         [ #  # ]:           0 :                                         if (c2 < 0xa1)
    1496                 :             :                                         {
    1497                 :           0 :                                                 charptr[i] = 0xa1;
    1498                 :           0 :                                                 return true;
    1499                 :             :                                         }
    1500         [ #  # ]:           0 :                                         else if (c2 < 0xfe)
    1501                 :             :                                         {
    1502                 :           0 :                                                 charptr[i]++;
    1503                 :           0 :                                                 return true;
    1504                 :             :                                         }
    1505                 :           0 :                                 }
    1506                 :             : 
    1507                 :             :                                 /* Out of 2 byte code region */
    1508                 :           0 :                                 return false;
    1509                 :             :                         }
    1510                 :             :                         else
    1511                 :             :                         {                                       /* ASCII, single byte */
    1512         [ #  # ]:           0 :                                 if (c1 > 0x7e)
    1513                 :           0 :                                         return false;
    1514                 :           0 :                                 (*charptr)++;
    1515                 :             :                         }
    1516                 :           0 :                         break;
    1517                 :             :         }
    1518                 :             : 
    1519                 :           0 :         return true;
    1520                 :           0 : }
    1521                 :             : 
    1522                 :             : /*
    1523                 :             :  * get the character incrementer for the encoding for the current database
    1524                 :             :  */
    1525                 :             : mbcharacter_incrementer
    1526                 :         231 : pg_database_encoding_character_incrementer(void)
    1527                 :             : {
    1528                 :             :         /*
    1529                 :             :          * Eventually it might be best to add a field to pg_wchar_table[], but for
    1530                 :             :          * now we just use a switch.
    1531                 :             :          */
    1532      [ -  -  + ]:         231 :         switch (GetDatabaseEncoding())
    1533                 :             :         {
    1534                 :             :                 case PG_UTF8:
    1535                 :         231 :                         return pg_utf8_increment;
    1536                 :             : 
    1537                 :             :                 case PG_EUC_JP:
    1538                 :           0 :                         return pg_eucjp_increment;
    1539                 :             : 
    1540                 :             :                 default:
    1541                 :           0 :                         return pg_generic_charinc;
    1542                 :             :         }
    1543                 :         231 : }
    1544                 :             : 
    1545                 :             : /*
    1546                 :             :  * fetch maximum length of the encoding for the current database
    1547                 :             :  */
    1548                 :             : int
    1549                 :      951732 : pg_database_encoding_max_length(void)
    1550                 :             : {
    1551                 :      951732 :         return pg_wchar_table[GetDatabaseEncoding()].maxmblen;
    1552                 :             : }
    1553                 :             : 
    1554                 :             : /*
    1555                 :             :  * Verify mbstr to make sure that it is validly encoded in the current
    1556                 :             :  * database encoding.  Otherwise same as pg_verify_mbstr().
    1557                 :             :  */
    1558                 :             : bool
    1559                 :       50010 : pg_verifymbstr(const char *mbstr, int len, bool noError)
    1560                 :             : {
    1561                 :       50010 :         return pg_verify_mbstr(GetDatabaseEncoding(), mbstr, len, noError);
    1562                 :             : }
    1563                 :             : 
    1564                 :             : /*
    1565                 :             :  * Verify mbstr to make sure that it is validly encoded in the specified
    1566                 :             :  * encoding.
    1567                 :             :  */
    1568                 :             : bool
    1569                 :      111598 : pg_verify_mbstr(int encoding, const char *mbstr, int len, bool noError)
    1570                 :             : {
    1571                 :      111598 :         int                     oklen;
    1572                 :             : 
    1573         [ +  - ]:      111598 :         Assert(PG_VALID_ENCODING(encoding));
    1574                 :             : 
    1575                 :      111598 :         oklen = pg_wchar_table[encoding].mbverifystr((const unsigned char *) mbstr, len);
    1576         [ +  + ]:      111598 :         if (oklen != len)
    1577                 :             :         {
    1578         [ -  + ]:           1 :                 if (noError)
    1579                 :           0 :                         return false;
    1580                 :           1 :                 report_invalid_encoding(encoding, mbstr + oklen, len - oklen);
    1581                 :             :         }
    1582                 :      111597 :         return true;
    1583                 :      111597 : }
    1584                 :             : 
    1585                 :             : /*
    1586                 :             :  * Verify mbstr to make sure that it is validly encoded in the specified
    1587                 :             :  * encoding.
    1588                 :             :  *
    1589                 :             :  * mbstr is not necessarily zero terminated; length of mbstr is
    1590                 :             :  * specified by len.
    1591                 :             :  *
    1592                 :             :  * If OK, return length of string in the encoding.
    1593                 :             :  * If a problem is found, return -1 when noError is
    1594                 :             :  * true; when noError is false, ereport() a descriptive message.
    1595                 :             :  *
    1596                 :             :  * Note: We cannot use the faster encoding-specific mbverifystr() function
    1597                 :             :  * here, because we need to count the number of characters in the string.
    1598                 :             :  */
    1599                 :             : int
    1600                 :           0 : pg_verify_mbstr_len(int encoding, const char *mbstr, int len, bool noError)
    1601                 :             : {
    1602                 :           0 :         mbchar_verifier mbverifychar;
    1603                 :           0 :         int                     mb_len;
    1604                 :             : 
    1605         [ #  # ]:           0 :         Assert(PG_VALID_ENCODING(encoding));
    1606                 :             : 
    1607                 :             :         /*
    1608                 :             :          * In single-byte encodings, we need only reject nulls (\0).
    1609                 :             :          */
    1610         [ #  # ]:           0 :         if (pg_encoding_max_length(encoding) <= 1)
    1611                 :             :         {
    1612                 :           0 :                 const char *nullpos = memchr(mbstr, 0, len);
    1613                 :             : 
    1614         [ #  # ]:           0 :                 if (nullpos == NULL)
    1615                 :           0 :                         return len;
    1616         [ #  # ]:           0 :                 if (noError)
    1617                 :           0 :                         return -1;
    1618                 :           0 :                 report_invalid_encoding(encoding, nullpos, 1);
    1619                 :           0 :         }
    1620                 :             : 
    1621                 :             :         /* fetch function pointer just once */
    1622                 :           0 :         mbverifychar = pg_wchar_table[encoding].mbverifychar;
    1623                 :             : 
    1624                 :           0 :         mb_len = 0;
    1625                 :             : 
    1626         [ #  # ]:           0 :         while (len > 0)
    1627                 :             :         {
    1628                 :           0 :                 int                     l;
    1629                 :             : 
    1630                 :             :                 /* fast path for ASCII-subset characters */
    1631         [ #  # ]:           0 :                 if (!IS_HIGHBIT_SET(*mbstr))
    1632                 :             :                 {
    1633         [ #  # ]:           0 :                         if (*mbstr != '\0')
    1634                 :             :                         {
    1635                 :           0 :                                 mb_len++;
    1636                 :           0 :                                 mbstr++;
    1637                 :           0 :                                 len--;
    1638                 :           0 :                                 continue;
    1639                 :             :                         }
    1640         [ #  # ]:           0 :                         if (noError)
    1641                 :           0 :                                 return -1;
    1642                 :           0 :                         report_invalid_encoding(encoding, mbstr, len);
    1643                 :             :                 }
    1644                 :             : 
    1645                 :           0 :                 l = (*mbverifychar) ((const unsigned char *) mbstr, len);
    1646                 :             : 
    1647         [ #  # ]:           0 :                 if (l < 0)
    1648                 :             :                 {
    1649         [ #  # ]:           0 :                         if (noError)
    1650                 :           0 :                                 return -1;
    1651                 :           0 :                         report_invalid_encoding(encoding, mbstr, len);
    1652                 :             :                 }
    1653                 :             : 
    1654                 :           0 :                 mbstr += l;
    1655                 :           0 :                 len -= l;
    1656                 :           0 :                 mb_len++;
    1657      [ #  #  # ]:           0 :         }
    1658                 :           0 :         return mb_len;
    1659                 :           0 : }
    1660                 :             : 
    1661                 :             : /*
    1662                 :             :  * check_encoding_conversion_args: check arguments of a conversion function
    1663                 :             :  *
    1664                 :             :  * "expected" arguments can be either an encoding ID or -1 to indicate that
    1665                 :             :  * the caller will check whether it accepts the ID.
    1666                 :             :  *
    1667                 :             :  * Note: the errors here are not really user-facing, so elog instead of
    1668                 :             :  * ereport seems sufficient.  Also, we trust that the "expected" encoding
    1669                 :             :  * arguments are valid encoding IDs, but we don't trust the actuals.
    1670                 :             :  */
    1671                 :             : void
    1672                 :        1122 : check_encoding_conversion_args(int src_encoding,
    1673                 :             :                                                            int dest_encoding,
    1674                 :             :                                                            int len,
    1675                 :             :                                                            int expected_src_encoding,
    1676                 :             :                                                            int expected_dest_encoding)
    1677                 :             : {
    1678         [ +  - ]:        1122 :         if (!PG_VALID_ENCODING(src_encoding))
    1679   [ #  #  #  # ]:           0 :                 elog(ERROR, "invalid source encoding ID: %d", src_encoding);
    1680   [ +  +  +  - ]:        1122 :         if (src_encoding != expected_src_encoding && expected_src_encoding >= 0)
    1681   [ #  #  #  # ]:           0 :                 elog(ERROR, "expected source encoding \"%s\", but got \"%s\"",
    1682                 :             :                          pg_enc2name_tbl[expected_src_encoding].name,
    1683                 :             :                          pg_enc2name_tbl[src_encoding].name);
    1684         [ +  - ]:        1122 :         if (!PG_VALID_ENCODING(dest_encoding))
    1685   [ #  #  #  # ]:           0 :                 elog(ERROR, "invalid destination encoding ID: %d", dest_encoding);
    1686   [ +  +  +  - ]:        1122 :         if (dest_encoding != expected_dest_encoding && expected_dest_encoding >= 0)
    1687   [ #  #  #  # ]:           0 :                 elog(ERROR, "expected destination encoding \"%s\", but got \"%s\"",
    1688                 :             :                          pg_enc2name_tbl[expected_dest_encoding].name,
    1689                 :             :                          pg_enc2name_tbl[dest_encoding].name);
    1690         [ +  - ]:        1122 :         if (len < 0)
    1691   [ #  #  #  # ]:           0 :                 elog(ERROR, "encoding conversion length must not be negative");
    1692                 :        1122 : }
    1693                 :             : 
    1694                 :             : /*
    1695                 :             :  * report_invalid_encoding: complain about invalid multibyte character
    1696                 :             :  *
    1697                 :             :  * note: len is remaining length of string, not length of character;
    1698                 :             :  * len must be greater than zero (or we'd neglect initializing "buf").
    1699                 :             :  */
    1700                 :             : void
    1701                 :         498 : report_invalid_encoding(int encoding, const char *mbstr, int len)
    1702                 :             : {
    1703                 :         498 :         int                     l = pg_encoding_mblen_or_incomplete(encoding, mbstr, len);
    1704                 :         498 :         char            buf[8 * 5 + 1];
    1705                 :         498 :         char       *p = buf;
    1706                 :         498 :         int                     j,
    1707                 :             :                                 jlimit;
    1708                 :             : 
    1709         [ +  + ]:         498 :         jlimit = Min(l, len);
    1710         [ +  - ]:         498 :         jlimit = Min(jlimit, 8);        /* prevent buffer overrun */
    1711                 :             : 
    1712         [ +  + ]:        1537 :         for (j = 0; j < jlimit; j++)
    1713                 :             :         {
    1714                 :        1039 :                 p += sprintf(p, "0x%02x", (unsigned char) mbstr[j]);
    1715         [ +  + ]:        1039 :                 if (j < jlimit - 1)
    1716                 :         541 :                         p += sprintf(p, " ");
    1717                 :        1039 :         }
    1718                 :             : 
    1719   [ -  +  +  - ]:         498 :         ereport(ERROR,
    1720                 :             :                         (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE),
    1721                 :             :                          errmsg("invalid byte sequence for encoding \"%s\": %s",
    1722                 :             :                                         pg_enc2name_tbl[encoding].name,
    1723                 :             :                                         buf)));
    1724                 :           0 : }
    1725                 :             : 
    1726                 :             : /*
    1727                 :             :  * report_untranslatable_char: complain about untranslatable character
    1728                 :             :  *
    1729                 :             :  * note: len is remaining length of string, not length of character;
    1730                 :             :  * len must be greater than zero (or we'd neglect initializing "buf").
    1731                 :             :  */
    1732                 :             : void
    1733                 :         156 : report_untranslatable_char(int src_encoding, int dest_encoding,
    1734                 :             :                                                    const char *mbstr, int len)
    1735                 :             : {
    1736                 :         156 :         int                     l;
    1737                 :         156 :         char            buf[8 * 5 + 1];
    1738                 :         156 :         char       *p = buf;
    1739                 :         156 :         int                     j,
    1740                 :             :                                 jlimit;
    1741                 :             : 
    1742                 :             :         /*
    1743                 :             :          * We probably could use plain pg_encoding_mblen(), because
    1744                 :             :          * gb18030_to_utf8() verifies before it converts.  All conversions should.
    1745                 :             :          * For src_encoding!=GB18030, len>0 meets pg_encoding_mblen() needs.  Even
    1746                 :             :          * so, be defensive, since a buggy conversion might pass invalid data.
    1747                 :             :          * This is not a performance-critical path.
    1748                 :             :          */
    1749                 :         156 :         l = pg_encoding_mblen_or_incomplete(src_encoding, mbstr, len);
    1750         [ +  + ]:         156 :         jlimit = Min(l, len);
    1751         [ +  - ]:         156 :         jlimit = Min(jlimit, 8);        /* prevent buffer overrun */
    1752                 :             : 
    1753         [ +  + ]:         588 :         for (j = 0; j < jlimit; j++)
    1754                 :             :         {
    1755                 :         432 :                 p += sprintf(p, "0x%02x", (unsigned char) mbstr[j]);
    1756         [ +  + ]:         432 :                 if (j < jlimit - 1)
    1757                 :         276 :                         p += sprintf(p, " ");
    1758                 :         432 :         }
    1759                 :             : 
    1760   [ -  +  +  - ]:         156 :         ereport(ERROR,
    1761                 :             :                         (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
    1762                 :             :                          errmsg("character with byte sequence %s in encoding \"%s\" has no equivalent in encoding \"%s\"",
    1763                 :             :                                         buf,
    1764                 :             :                                         pg_enc2name_tbl[src_encoding].name,
    1765                 :             :                                         pg_enc2name_tbl[dest_encoding].name)));
    1766                 :           0 : }
    1767                 :             : 
    1768                 :             : 
    1769                 :             : #ifdef WIN32
    1770                 :             : /*
    1771                 :             :  * Convert from MessageEncoding to a palloc'ed, null-terminated utf16
    1772                 :             :  * string. The character length is also passed to utf16len if not
    1773                 :             :  * null. Returns NULL iff failed. Before MessageEncoding initialization, "str"
    1774                 :             :  * should be ASCII-only; this will function as though MessageEncoding is UTF8.
    1775                 :             :  */
    1776                 :             : WCHAR *
    1777                 :             : pgwin32_message_to_UTF16(const char *str, int len, int *utf16len)
    1778                 :             : {
    1779                 :             :         int                     msgenc = GetMessageEncoding();
    1780                 :             :         WCHAR      *utf16;
    1781                 :             :         int                     dstlen;
    1782                 :             :         UINT            codepage;
    1783                 :             : 
    1784                 :             :         if (msgenc == PG_SQL_ASCII)
    1785                 :             :                 /* No conversion is possible, and SQL_ASCII is never utf16. */
    1786                 :             :                 return NULL;
    1787                 :             : 
    1788                 :             :         codepage = pg_enc2name_tbl[msgenc].codepage;
    1789                 :             : 
    1790                 :             :         /*
    1791                 :             :          * Use MultiByteToWideChar directly if there is a corresponding codepage,
    1792                 :             :          * or double conversion through UTF8 if not.  Double conversion is needed,
    1793                 :             :          * for example, in an ENCODING=LATIN8, LC_CTYPE=C database.
    1794                 :             :          */
    1795                 :             :         if (codepage != 0)
    1796                 :             :         {
    1797                 :             :                 utf16 = palloc_array(WCHAR, len + 1);
    1798                 :             :                 dstlen = MultiByteToWideChar(codepage, 0, str, len, utf16, len);
    1799                 :             :                 utf16[dstlen] = (WCHAR) 0;
    1800                 :             :         }
    1801                 :             :         else
    1802                 :             :         {
    1803                 :             :                 char       *utf8;
    1804                 :             : 
    1805                 :             :                 /*
    1806                 :             :                  * XXX pg_do_encoding_conversion() requires a transaction.  In the
    1807                 :             :                  * absence of one, hope for the input to be valid UTF8.
    1808                 :             :                  */
    1809                 :             :                 if (IsTransactionState())
    1810                 :             :                 {
    1811                 :             :                         utf8 = (char *) pg_do_encoding_conversion((unsigned char *) str,
    1812                 :             :                                                                                                           len,
    1813                 :             :                                                                                                           msgenc,
    1814                 :             :                                                                                                           PG_UTF8);
    1815                 :             :                         if (utf8 != str)
    1816                 :             :                                 len = strlen(utf8);
    1817                 :             :                 }
    1818                 :             :                 else
    1819                 :             :                         utf8 = (char *) str;
    1820                 :             : 
    1821                 :             :                 utf16 = palloc_array(WCHAR, len + 1);
    1822                 :             :                 dstlen = MultiByteToWideChar(CP_UTF8, 0, utf8, len, utf16, len);
    1823                 :             :                 utf16[dstlen] = (WCHAR) 0;
    1824                 :             : 
    1825                 :             :                 if (utf8 != str)
    1826                 :             :                         pfree(utf8);
    1827                 :             :         }
    1828                 :             : 
    1829                 :             :         if (dstlen == 0 && len > 0)
    1830                 :             :         {
    1831                 :             :                 pfree(utf16);
    1832                 :             :                 return NULL;                    /* error */
    1833                 :             :         }
    1834                 :             : 
    1835                 :             :         if (utf16len)
    1836                 :             :                 *utf16len = dstlen;
    1837                 :             :         return utf16;
    1838                 :             : }
    1839                 :             : 
    1840                 :             : #endif                                                  /* WIN32 */
        

Generated by: LCOV version 2.3.2-1