LCOV - code coverage report
Current view: top level - src/backend/utils/adt - varchar.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 78.3 % 383 300
Test Date: 2026-02-17 17:20:33 Functions: 78.3 % 46 36
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * varchar.c
       4              :  *    Functions for the built-in types char(n) and varchar(n).
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/backend/utils/adt/varchar.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : #include "postgres.h"
      16              : 
      17              : #include "access/detoast.h"
      18              : #include "access/htup_details.h"
      19              : #include "catalog/pg_collation.h"
      20              : #include "catalog/pg_type.h"
      21              : #include "common/hashfn.h"
      22              : #include "libpq/pqformat.h"
      23              : #include "mb/pg_wchar.h"
      24              : #include "nodes/nodeFuncs.h"
      25              : #include "nodes/supportnodes.h"
      26              : #include "utils/array.h"
      27              : #include "utils/builtins.h"
      28              : #include "utils/pg_locale.h"
      29              : #include "utils/varlena.h"
      30              : 
      31              : /* common code for bpchartypmodin and varchartypmodin */
      32              : static int32
      33         1849 : anychar_typmodin(ArrayType *ta, const char *typename)
      34              : {
      35              :     int32       typmod;
      36              :     int32      *tl;
      37              :     int         n;
      38              : 
      39         1849 :     tl = ArrayGetIntegerTypmods(ta, &n);
      40              : 
      41              :     /*
      42              :      * we're not too tense about good error message here because grammar
      43              :      * shouldn't allow wrong number of modifiers for CHAR
      44              :      */
      45         1849 :     if (n != 1)
      46            0 :         ereport(ERROR,
      47              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      48              :                  errmsg("invalid type modifier")));
      49              : 
      50         1849 :     if (*tl < 1)
      51            0 :         ereport(ERROR,
      52              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      53              :                  errmsg("length for type %s must be at least 1", typename)));
      54         1849 :     if (*tl > MaxAttrSize)
      55            0 :         ereport(ERROR,
      56              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      57              :                  errmsg("length for type %s cannot exceed %d",
      58              :                         typename, MaxAttrSize)));
      59              : 
      60              :     /*
      61              :      * For largely historical reasons, the typmod is VARHDRSZ plus the number
      62              :      * of characters; there is enough client-side code that knows about that
      63              :      * that we'd better not change it.
      64              :      */
      65         1849 :     typmod = VARHDRSZ + *tl;
      66              : 
      67         1849 :     return typmod;
      68              : }
      69              : 
      70              : /* common code for bpchartypmodout and varchartypmodout */
      71              : static char *
      72          524 : anychar_typmodout(int32 typmod)
      73              : {
      74          524 :     char       *res = (char *) palloc(64);
      75              : 
      76          524 :     if (typmod > VARHDRSZ)
      77          524 :         snprintf(res, 64, "(%d)", (int) (typmod - VARHDRSZ));
      78              :     else
      79            0 :         *res = '\0';
      80              : 
      81          524 :     return res;
      82              : }
      83              : 
      84              : 
      85              : /*
      86              :  * CHAR() and VARCHAR() types are part of the SQL standard. CHAR()
      87              :  * is for blank-padded string whose length is specified in CREATE TABLE.
      88              :  * VARCHAR is for storing string whose length is at most the length specified
      89              :  * at CREATE TABLE time.
      90              :  *
      91              :  * It's hard to implement these types because we cannot figure out
      92              :  * the length of the type from the type itself. I changed (hopefully all) the
      93              :  * fmgr calls that invoke input functions of a data type to supply the
      94              :  * length also. (eg. in INSERTs, we have the tupleDescriptor which contains
      95              :  * the length of the attributes and hence the exact length of the char() or
      96              :  * varchar(). We pass this to bpcharin() or varcharin().) In the case where
      97              :  * we cannot determine the length, we pass in -1 instead and the input
      98              :  * converter does not enforce any length check.
      99              :  *
     100              :  * We actually implement this as a varlena so that we don't have to pass in
     101              :  * the length for the comparison functions. (The difference between these
     102              :  * types and "text" is that we truncate and possibly blank-pad the string
     103              :  * at insertion time.)
     104              :  *
     105              :  *                                                            - ay 6/95
     106              :  */
     107              : 
     108              : 
     109              : /*****************************************************************************
     110              :  *   bpchar - char()                                                         *
     111              :  *****************************************************************************/
     112              : 
     113              : /*
     114              :  * bpchar_input -- common guts of bpcharin and bpcharrecv
     115              :  *
     116              :  * s is the input text of length len (may not be null-terminated)
     117              :  * atttypmod is the typmod value to apply
     118              :  *
     119              :  * Note that atttypmod is measured in characters, which
     120              :  * is not necessarily the same as the number of bytes.
     121              :  *
     122              :  * If the input string is too long, raise an error, unless the extra
     123              :  * characters are spaces, in which case they're truncated.  (per SQL)
     124              :  *
     125              :  * If escontext points to an ErrorSaveContext node, that is filled instead
     126              :  * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
     127              :  * to detect errors.
     128              :  */
     129              : static BpChar *
     130       210994 : bpchar_input(const char *s, size_t len, int32 atttypmod, Node *escontext)
     131              : {
     132              :     BpChar     *result;
     133              :     char       *r;
     134              :     size_t      maxlen;
     135              : 
     136              :     /* If typmod is -1 (or invalid), use the actual string length */
     137       210994 :     if (atttypmod < (int32) VARHDRSZ)
     138         4495 :         maxlen = len;
     139              :     else
     140              :     {
     141              :         size_t      charlen;    /* number of CHARACTERS in the input */
     142              : 
     143       206499 :         maxlen = atttypmod - VARHDRSZ;
     144       206499 :         charlen = pg_mbstrlen_with_len(s, len);
     145       206499 :         if (charlen > maxlen)
     146              :         {
     147              :             /* Verify that extra characters are spaces, and clip them off */
     148           99 :             size_t      mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
     149              :             size_t      j;
     150              : 
     151              :             /*
     152              :              * at this point, len is the actual BYTE length of the input
     153              :              * string, maxlen is the max number of CHARACTERS allowed for this
     154              :              * bpchar type, mbmaxlen is the length in BYTES of those chars.
     155              :              */
     156          105 :             for (j = mbmaxlen; j < len; j++)
     157              :             {
     158          102 :                 if (s[j] != ' ')
     159           96 :                     ereturn(escontext, NULL,
     160              :                             (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
     161              :                              errmsg("value too long for type character(%zu)",
     162              :                                     maxlen)));
     163              :             }
     164              : 
     165              :             /*
     166              :              * Now we set maxlen to the necessary byte length, not the number
     167              :              * of CHARACTERS!
     168              :              */
     169            3 :             maxlen = len = mbmaxlen;
     170              :         }
     171              :         else
     172              :         {
     173              :             /*
     174              :              * Now we set maxlen to the necessary byte length, not the number
     175              :              * of CHARACTERS!
     176              :              */
     177       206400 :             maxlen = len + (maxlen - charlen);
     178              :         }
     179              :     }
     180              : 
     181       210898 :     result = (BpChar *) palloc(maxlen + VARHDRSZ);
     182       210898 :     SET_VARSIZE(result, maxlen + VARHDRSZ);
     183       210898 :     r = VARDATA(result);
     184       210898 :     memcpy(r, s, len);
     185              : 
     186              :     /* blank pad the string if necessary */
     187       210898 :     if (maxlen > len)
     188       201122 :         memset(r + len, ' ', maxlen - len);
     189              : 
     190       210898 :     return result;
     191              : }
     192              : 
     193              : /*
     194              :  * Convert a C string to CHARACTER internal representation.  atttypmod
     195              :  * is the declared length of the type plus VARHDRSZ.
     196              :  */
     197              : Datum
     198       210994 : bpcharin(PG_FUNCTION_ARGS)
     199              : {
     200       210994 :     char       *s = PG_GETARG_CSTRING(0);
     201              : #ifdef NOT_USED
     202              :     Oid         typelem = PG_GETARG_OID(1);
     203              : #endif
     204       210994 :     int32       atttypmod = PG_GETARG_INT32(2);
     205              :     BpChar     *result;
     206              : 
     207       210994 :     result = bpchar_input(s, strlen(s), atttypmod, fcinfo->context);
     208       210958 :     PG_RETURN_BPCHAR_P(result);
     209              : }
     210              : 
     211              : 
     212              : /*
     213              :  * Convert a CHARACTER value to a C string.
     214              :  *
     215              :  * Uses the text conversion functions, which is only appropriate if BpChar
     216              :  * and text are equivalent types.
     217              :  */
     218              : Datum
     219        22698 : bpcharout(PG_FUNCTION_ARGS)
     220              : {
     221        22698 :     Datum       txt = PG_GETARG_DATUM(0);
     222              : 
     223        22698 :     PG_RETURN_CSTRING(TextDatumGetCString(txt));
     224              : }
     225              : 
     226              : /*
     227              :  *      bpcharrecv          - converts external binary format to bpchar
     228              :  */
     229              : Datum
     230            0 : bpcharrecv(PG_FUNCTION_ARGS)
     231              : {
     232            0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     233              : #ifdef NOT_USED
     234              :     Oid         typelem = PG_GETARG_OID(1);
     235              : #endif
     236            0 :     int32       atttypmod = PG_GETARG_INT32(2);
     237              :     BpChar     *result;
     238              :     char       *str;
     239              :     int         nbytes;
     240              : 
     241            0 :     str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
     242            0 :     result = bpchar_input(str, nbytes, atttypmod, NULL);
     243            0 :     pfree(str);
     244            0 :     PG_RETURN_BPCHAR_P(result);
     245              : }
     246              : 
     247              : /*
     248              :  *      bpcharsend          - converts bpchar to binary format
     249              :  */
     250              : Datum
     251            2 : bpcharsend(PG_FUNCTION_ARGS)
     252              : {
     253              :     /* Exactly the same as textsend, so share code */
     254            2 :     return textsend(fcinfo);
     255              : }
     256              : 
     257              : 
     258              : /*
     259              :  * Converts a CHARACTER type to the specified size.
     260              :  *
     261              :  * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes.
     262              :  * isExplicit is true if this is for an explicit cast to char(N).
     263              :  *
     264              :  * Truncation rules: for an explicit cast, silently truncate to the given
     265              :  * length; for an implicit cast, raise error unless extra characters are
     266              :  * all spaces.  (This is sort-of per SQL: the spec would actually have us
     267              :  * raise a "completion condition" for the explicit cast case, but Postgres
     268              :  * hasn't got such a concept.)
     269              :  */
     270              : Datum
     271         6130 : bpchar(PG_FUNCTION_ARGS)
     272              : {
     273         6130 :     BpChar     *source = PG_GETARG_BPCHAR_PP(0);
     274         6130 :     int32       maxlen = PG_GETARG_INT32(1);
     275         6130 :     bool        isExplicit = PG_GETARG_BOOL(2);
     276              :     BpChar     *result;
     277              :     int32       len;
     278              :     char       *r;
     279              :     char       *s;
     280              :     int         i;
     281              :     int         charlen;        /* number of characters in the input string +
     282              :                                  * VARHDRSZ */
     283              : 
     284              :     /* No work if typmod is invalid */
     285         6130 :     if (maxlen < (int32) VARHDRSZ)
     286            0 :         PG_RETURN_BPCHAR_P(source);
     287              : 
     288         6130 :     maxlen -= VARHDRSZ;
     289              : 
     290         6130 :     len = VARSIZE_ANY_EXHDR(source);
     291         6130 :     s = VARDATA_ANY(source);
     292              : 
     293         6130 :     charlen = pg_mbstrlen_with_len(s, len);
     294              : 
     295              :     /* No work if supplied data matches typmod already */
     296         6130 :     if (charlen == maxlen)
     297         2859 :         PG_RETURN_BPCHAR_P(source);
     298              : 
     299         3271 :     if (charlen > maxlen)
     300              :     {
     301              :         /* Verify that extra characters are spaces, and clip them off */
     302              :         size_t      maxmblen;
     303              : 
     304           21 :         maxmblen = pg_mbcharcliplen(s, len, maxlen);
     305              : 
     306           21 :         if (!isExplicit)
     307              :         {
     308           45 :             for (i = maxmblen; i < len; i++)
     309           39 :                 if (s[i] != ' ')
     310           12 :                     ereport(ERROR,
     311              :                             (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
     312              :                              errmsg("value too long for type character(%d)",
     313              :                                     maxlen)));
     314              :         }
     315              : 
     316            9 :         len = maxmblen;
     317              : 
     318              :         /*
     319              :          * At this point, maxlen is the necessary byte length, not the number
     320              :          * of CHARACTERS!
     321              :          */
     322            9 :         maxlen = len;
     323              :     }
     324              :     else
     325              :     {
     326              :         /*
     327              :          * At this point, maxlen is the necessary byte length, not the number
     328              :          * of CHARACTERS!
     329              :          */
     330         3250 :         maxlen = len + (maxlen - charlen);
     331              :     }
     332              : 
     333              :     Assert(maxlen >= len);
     334              : 
     335         3259 :     result = palloc(maxlen + VARHDRSZ);
     336         3259 :     SET_VARSIZE(result, maxlen + VARHDRSZ);
     337         3259 :     r = VARDATA(result);
     338              : 
     339         3259 :     memcpy(r, s, len);
     340              : 
     341              :     /* blank pad the string if necessary */
     342         3259 :     if (maxlen > len)
     343         3250 :         memset(r + len, ' ', maxlen - len);
     344              : 
     345         3259 :     PG_RETURN_BPCHAR_P(result);
     346              : }
     347              : 
     348              : 
     349              : /* char_bpchar()
     350              :  * Convert char to bpchar(1).
     351              :  */
     352              : Datum
     353            0 : char_bpchar(PG_FUNCTION_ARGS)
     354              : {
     355            0 :     char        c = PG_GETARG_CHAR(0);
     356              :     BpChar     *result;
     357              : 
     358            0 :     result = (BpChar *) palloc(VARHDRSZ + 1);
     359              : 
     360            0 :     SET_VARSIZE(result, VARHDRSZ + 1);
     361            0 :     *(VARDATA(result)) = c;
     362              : 
     363            0 :     PG_RETURN_BPCHAR_P(result);
     364              : }
     365              : 
     366              : 
     367              : /* bpchar_name()
     368              :  * Converts a bpchar() type to a NameData type.
     369              :  */
     370              : Datum
     371            0 : bpchar_name(PG_FUNCTION_ARGS)
     372              : {
     373            0 :     BpChar     *s = PG_GETARG_BPCHAR_PP(0);
     374              :     char       *s_data;
     375              :     Name        result;
     376              :     int         len;
     377              : 
     378            0 :     len = VARSIZE_ANY_EXHDR(s);
     379            0 :     s_data = VARDATA_ANY(s);
     380              : 
     381              :     /* Truncate oversize input */
     382            0 :     if (len >= NAMEDATALEN)
     383            0 :         len = pg_mbcliplen(s_data, len, NAMEDATALEN - 1);
     384              : 
     385              :     /* Remove trailing blanks */
     386            0 :     while (len > 0)
     387              :     {
     388            0 :         if (s_data[len - 1] != ' ')
     389            0 :             break;
     390            0 :         len--;
     391              :     }
     392              : 
     393              :     /* We use palloc0 here to ensure result is zero-padded */
     394            0 :     result = (Name) palloc0(NAMEDATALEN);
     395            0 :     memcpy(NameStr(*result), s_data, len);
     396              : 
     397            0 :     PG_RETURN_NAME(result);
     398              : }
     399              : 
     400              : /* name_bpchar()
     401              :  * Converts a NameData type to a bpchar type.
     402              :  *
     403              :  * Uses the text conversion functions, which is only appropriate if BpChar
     404              :  * and text are equivalent types.
     405              :  */
     406              : Datum
     407            3 : name_bpchar(PG_FUNCTION_ARGS)
     408              : {
     409            3 :     Name        s = PG_GETARG_NAME(0);
     410              :     BpChar     *result;
     411              : 
     412            3 :     result = (BpChar *) cstring_to_text(NameStr(*s));
     413            3 :     PG_RETURN_BPCHAR_P(result);
     414              : }
     415              : 
     416              : Datum
     417         1126 : bpchartypmodin(PG_FUNCTION_ARGS)
     418              : {
     419         1126 :     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
     420              : 
     421         1126 :     PG_RETURN_INT32(anychar_typmodin(ta, "char"));
     422              : }
     423              : 
     424              : Datum
     425          418 : bpchartypmodout(PG_FUNCTION_ARGS)
     426              : {
     427          418 :     int32       typmod = PG_GETARG_INT32(0);
     428              : 
     429          418 :     PG_RETURN_CSTRING(anychar_typmodout(typmod));
     430              : }
     431              : 
     432              : 
     433              : /*****************************************************************************
     434              :  *   varchar - varchar(n)
     435              :  *
     436              :  * Note: varchar piggybacks on type text for most operations, and so has no
     437              :  * C-coded functions except for I/O and typmod checking.
     438              :  *****************************************************************************/
     439              : 
     440              : /*
     441              :  * varchar_input -- common guts of varcharin and varcharrecv
     442              :  *
     443              :  * s is the input text of length len (may not be null-terminated)
     444              :  * atttypmod is the typmod value to apply
     445              :  *
     446              :  * Note that atttypmod is measured in characters, which
     447              :  * is not necessarily the same as the number of bytes.
     448              :  *
     449              :  * If the input string is too long, raise an error, unless the extra
     450              :  * characters are spaces, in which case they're truncated.  (per SQL)
     451              :  *
     452              :  * If escontext points to an ErrorSaveContext node, that is filled instead
     453              :  * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
     454              :  * to detect errors.
     455              :  */
     456              : static VarChar *
     457       296352 : varchar_input(const char *s, size_t len, int32 atttypmod, Node *escontext)
     458              : {
     459              :     VarChar    *result;
     460              :     size_t      maxlen;
     461              : 
     462       296352 :     maxlen = atttypmod - VARHDRSZ;
     463              : 
     464       296352 :     if (atttypmod >= (int32) VARHDRSZ && len > maxlen)
     465              :     {
     466              :         /* Verify that extra characters are spaces, and clip them off */
     467           33 :         size_t      mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
     468              :         size_t      j;
     469              : 
     470           39 :         for (j = mbmaxlen; j < len; j++)
     471              :         {
     472           36 :             if (s[j] != ' ')
     473           30 :                 ereturn(escontext, NULL,
     474              :                         (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
     475              :                          errmsg("value too long for type character varying(%zu)",
     476              :                                 maxlen)));
     477              :         }
     478              : 
     479            3 :         len = mbmaxlen;
     480              :     }
     481              : 
     482              :     /*
     483              :      * We can use cstring_to_text_with_len because VarChar and text are
     484              :      * binary-compatible types.
     485              :      */
     486       296322 :     result = (VarChar *) cstring_to_text_with_len(s, len);
     487       296322 :     return result;
     488              : }
     489              : 
     490              : /*
     491              :  * Convert a C string to VARCHAR internal representation.  atttypmod
     492              :  * is the declared length of the type plus VARHDRSZ.
     493              :  */
     494              : Datum
     495       296351 : varcharin(PG_FUNCTION_ARGS)
     496              : {
     497       296351 :     char       *s = PG_GETARG_CSTRING(0);
     498              : #ifdef NOT_USED
     499              :     Oid         typelem = PG_GETARG_OID(1);
     500              : #endif
     501       296351 :     int32       atttypmod = PG_GETARG_INT32(2);
     502              :     VarChar    *result;
     503              : 
     504       296351 :     result = varchar_input(s, strlen(s), atttypmod, fcinfo->context);
     505       296345 :     PG_RETURN_VARCHAR_P(result);
     506              : }
     507              : 
     508              : 
     509              : /*
     510              :  * Convert a VARCHAR value to a C string.
     511              :  *
     512              :  * Uses the text to C string conversion function, which is only appropriate
     513              :  * if VarChar and text are equivalent types.
     514              :  */
     515              : Datum
     516        94479 : varcharout(PG_FUNCTION_ARGS)
     517              : {
     518        94479 :     Datum       txt = PG_GETARG_DATUM(0);
     519              : 
     520        94479 :     PG_RETURN_CSTRING(TextDatumGetCString(txt));
     521              : }
     522              : 
     523              : /*
     524              :  *      varcharrecv         - converts external binary format to varchar
     525              :  */
     526              : Datum
     527            1 : varcharrecv(PG_FUNCTION_ARGS)
     528              : {
     529            1 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     530              : #ifdef NOT_USED
     531              :     Oid         typelem = PG_GETARG_OID(1);
     532              : #endif
     533            1 :     int32       atttypmod = PG_GETARG_INT32(2);
     534              :     VarChar    *result;
     535              :     char       *str;
     536              :     int         nbytes;
     537              : 
     538            1 :     str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
     539            1 :     result = varchar_input(str, nbytes, atttypmod, NULL);
     540            1 :     pfree(str);
     541            1 :     PG_RETURN_VARCHAR_P(result);
     542              : }
     543              : 
     544              : /*
     545              :  *      varcharsend         - converts varchar to binary format
     546              :  */
     547              : Datum
     548            1 : varcharsend(PG_FUNCTION_ARGS)
     549              : {
     550              :     /* Exactly the same as textsend, so share code */
     551            1 :     return textsend(fcinfo);
     552              : }
     553              : 
     554              : 
     555              : /*
     556              :  * varchar_support()
     557              :  *
     558              :  * Planner support function for the varchar() length coercion function.
     559              :  *
     560              :  * Currently, the only interesting thing we can do is flatten calls that set
     561              :  * the new maximum length >= the previous maximum length.  We can ignore the
     562              :  * isExplicit argument, since that only affects truncation cases.
     563              :  */
     564              : Datum
     565         1179 : varchar_support(PG_FUNCTION_ARGS)
     566              : {
     567         1179 :     Node       *rawreq = (Node *) PG_GETARG_POINTER(0);
     568         1179 :     Node       *ret = NULL;
     569              : 
     570         1179 :     if (IsA(rawreq, SupportRequestSimplify))
     571              :     {
     572          518 :         SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
     573          518 :         FuncExpr   *expr = req->fcall;
     574              :         Node       *typmod;
     575              : 
     576              :         Assert(list_length(expr->args) >= 2);
     577              : 
     578          518 :         typmod = (Node *) lsecond(expr->args);
     579              : 
     580          518 :         if (IsA(typmod, Const) && !((Const *) typmod)->constisnull)
     581              :         {
     582          518 :             Node       *source = (Node *) linitial(expr->args);
     583          518 :             int32       old_typmod = exprTypmod(source);
     584          518 :             int32       new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
     585          518 :             int32       old_max = old_typmod - VARHDRSZ;
     586          518 :             int32       new_max = new_typmod - VARHDRSZ;
     587              : 
     588          518 :             if (new_typmod < 0 || (old_typmod >= 0 && old_max <= new_max))
     589           15 :                 ret = relabel_to_typmod(source, new_typmod);
     590              :         }
     591              :     }
     592              : 
     593         1179 :     PG_RETURN_POINTER(ret);
     594              : }
     595              : 
     596              : /*
     597              :  * Converts a VARCHAR type to the specified size.
     598              :  *
     599              :  * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes.
     600              :  * isExplicit is true if this is for an explicit cast to varchar(N).
     601              :  *
     602              :  * Truncation rules: for an explicit cast, silently truncate to the given
     603              :  * length; for an implicit cast, raise error unless extra characters are
     604              :  * all spaces.  (This is sort-of per SQL: the spec would actually have us
     605              :  * raise a "completion condition" for the explicit cast case, but Postgres
     606              :  * hasn't got such a concept.)
     607              :  */
     608              : Datum
     609        13049 : varchar(PG_FUNCTION_ARGS)
     610              : {
     611        13049 :     VarChar    *source = PG_GETARG_VARCHAR_PP(0);
     612        13049 :     int32       typmod = PG_GETARG_INT32(1);
     613        13049 :     bool        isExplicit = PG_GETARG_BOOL(2);
     614              :     int32       len,
     615              :                 maxlen;
     616              :     size_t      maxmblen;
     617              :     int         i;
     618              :     char       *s_data;
     619              : 
     620        13049 :     len = VARSIZE_ANY_EXHDR(source);
     621        13049 :     s_data = VARDATA_ANY(source);
     622        13049 :     maxlen = typmod - VARHDRSZ;
     623              : 
     624              :     /* No work if typmod is invalid or supplied data fits it already */
     625        13049 :     if (maxlen < 0 || len <= maxlen)
     626        12986 :         PG_RETURN_VARCHAR_P(source);
     627              : 
     628              :     /* only reach here if string is too long... */
     629              : 
     630              :     /* truncate multibyte string preserving multibyte boundary */
     631           63 :     maxmblen = pg_mbcharcliplen(s_data, len, maxlen);
     632              : 
     633           63 :     if (!isExplicit)
     634              :     {
     635           78 :         for (i = maxmblen; i < len; i++)
     636           72 :             if (s_data[i] != ' ')
     637           42 :                 ereport(ERROR,
     638              :                         (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
     639              :                          errmsg("value too long for type character varying(%d)",
     640              :                                 maxlen)));
     641              :     }
     642              : 
     643           21 :     PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len(s_data,
     644              :                                                              maxmblen));
     645              : }
     646              : 
     647              : Datum
     648          723 : varchartypmodin(PG_FUNCTION_ARGS)
     649              : {
     650          723 :     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
     651              : 
     652          723 :     PG_RETURN_INT32(anychar_typmodin(ta, "varchar"));
     653              : }
     654              : 
     655              : Datum
     656          106 : varchartypmodout(PG_FUNCTION_ARGS)
     657              : {
     658          106 :     int32       typmod = PG_GETARG_INT32(0);
     659              : 
     660          106 :     PG_RETURN_CSTRING(anychar_typmodout(typmod));
     661              : }
     662              : 
     663              : 
     664              : /*****************************************************************************
     665              :  * Exported functions
     666              :  *****************************************************************************/
     667              : 
     668              : /* "True" length (not counting trailing blanks) of a BpChar */
     669              : static inline int
     670       155670 : bcTruelen(BpChar *arg)
     671              : {
     672       155670 :     return bpchartruelen(VARDATA_ANY(arg), VARSIZE_ANY_EXHDR(arg));
     673              : }
     674              : 
     675              : int
     676       255583 : bpchartruelen(char *s, int len)
     677              : {
     678              :     int         i;
     679              : 
     680              :     /*
     681              :      * Note that we rely on the assumption that ' ' is a singleton unit on
     682              :      * every supported multibyte server encoding.
     683              :      */
     684      6891770 :     for (i = len - 1; i >= 0; i--)
     685              :     {
     686      6813497 :         if (s[i] != ' ')
     687       177310 :             break;
     688              :     }
     689       255583 :     return i + 1;
     690              : }
     691              : 
     692              : Datum
     693            9 : bpcharlen(PG_FUNCTION_ARGS)
     694              : {
     695            9 :     BpChar     *arg = PG_GETARG_BPCHAR_PP(0);
     696              :     int         len;
     697              : 
     698              :     /* get number of bytes, ignoring trailing spaces */
     699            9 :     len = bcTruelen(arg);
     700              : 
     701              :     /* in multibyte encoding, convert to number of characters */
     702            9 :     if (pg_database_encoding_max_length() != 1)
     703            9 :         len = pg_mbstrlen_with_len(VARDATA_ANY(arg), len);
     704              : 
     705            9 :     PG_RETURN_INT32(len);
     706              : }
     707              : 
     708              : Datum
     709            0 : bpcharoctetlen(PG_FUNCTION_ARGS)
     710              : {
     711            0 :     Datum       arg = PG_GETARG_DATUM(0);
     712              : 
     713              :     /* We need not detoast the input at all */
     714            0 :     PG_RETURN_INT32(toast_raw_datum_size(arg) - VARHDRSZ);
     715              : }
     716              : 
     717              : 
     718              : /*****************************************************************************
     719              :  *  Comparison Functions used for bpchar
     720              :  *
     721              :  * Note: btree indexes need these routines not to leak memory; therefore,
     722              :  * be careful to free working copies of toasted datums.  Most places don't
     723              :  * need to be so careful.
     724              :  *****************************************************************************/
     725              : 
     726              : static void
     727        12941 : check_collation_set(Oid collid)
     728              : {
     729        12941 :     if (!OidIsValid(collid))
     730              :     {
     731              :         /*
     732              :          * This typically means that the parser could not resolve a conflict
     733              :          * of implicit collations, so report it that way.
     734              :          */
     735            0 :         ereport(ERROR,
     736              :                 (errcode(ERRCODE_INDETERMINATE_COLLATION),
     737              :                  errmsg("could not determine which collation to use for string comparison"),
     738              :                  errhint("Use the COLLATE clause to set the collation explicitly.")));
     739              :     }
     740        12941 : }
     741              : 
     742              : Datum
     743         9719 : bpchareq(PG_FUNCTION_ARGS)
     744              : {
     745         9719 :     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
     746         9719 :     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
     747              :     int         len1,
     748              :                 len2;
     749              :     bool        result;
     750         9719 :     Oid         collid = PG_GET_COLLATION();
     751              :     pg_locale_t mylocale;
     752              : 
     753         9719 :     check_collation_set(collid);
     754              : 
     755         9719 :     len1 = bcTruelen(arg1);
     756         9719 :     len2 = bcTruelen(arg2);
     757              : 
     758         9719 :     mylocale = pg_newlocale_from_collation(collid);
     759              : 
     760         9719 :     if (mylocale->deterministic)
     761              :     {
     762              :         /*
     763              :          * Since we only care about equality or not-equality, we can avoid all
     764              :          * the expense of strcoll() here, and just do bitwise comparison.
     765              :          */
     766         9635 :         if (len1 != len2)
     767         1334 :             result = false;
     768              :         else
     769         8301 :             result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) == 0);
     770              :     }
     771              :     else
     772              :     {
     773           84 :         result = (varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
     774              :                              collid) == 0);
     775              :     }
     776              : 
     777         9719 :     PG_FREE_IF_COPY(arg1, 0);
     778         9719 :     PG_FREE_IF_COPY(arg2, 1);
     779              : 
     780         9719 :     PG_RETURN_BOOL(result);
     781              : }
     782              : 
     783              : Datum
     784         3222 : bpcharne(PG_FUNCTION_ARGS)
     785              : {
     786         3222 :     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
     787         3222 :     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
     788              :     int         len1,
     789              :                 len2;
     790              :     bool        result;
     791         3222 :     Oid         collid = PG_GET_COLLATION();
     792              :     pg_locale_t mylocale;
     793              : 
     794         3222 :     check_collation_set(collid);
     795              : 
     796         3222 :     len1 = bcTruelen(arg1);
     797         3222 :     len2 = bcTruelen(arg2);
     798              : 
     799         3222 :     mylocale = pg_newlocale_from_collation(collid);
     800              : 
     801         3222 :     if (mylocale->deterministic)
     802              :     {
     803              :         /*
     804              :          * Since we only care about equality or not-equality, we can avoid all
     805              :          * the expense of strcoll() here, and just do bitwise comparison.
     806              :          */
     807         3210 :         if (len1 != len2)
     808         1023 :             result = true;
     809              :         else
     810         2187 :             result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) != 0);
     811              :     }
     812              :     else
     813              :     {
     814           12 :         result = (varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
     815              :                              collid) != 0);
     816              :     }
     817              : 
     818         3222 :     PG_FREE_IF_COPY(arg1, 0);
     819         3222 :     PG_FREE_IF_COPY(arg2, 1);
     820              : 
     821         3222 :     PG_RETURN_BOOL(result);
     822              : }
     823              : 
     824              : Datum
     825         3068 : bpcharlt(PG_FUNCTION_ARGS)
     826              : {
     827         3068 :     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
     828         3068 :     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
     829              :     int         len1,
     830              :                 len2;
     831              :     int         cmp;
     832              : 
     833         3068 :     len1 = bcTruelen(arg1);
     834         3068 :     len2 = bcTruelen(arg2);
     835              : 
     836         3068 :     cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
     837              :                      PG_GET_COLLATION());
     838              : 
     839         3068 :     PG_FREE_IF_COPY(arg1, 0);
     840         3068 :     PG_FREE_IF_COPY(arg2, 1);
     841              : 
     842         3068 :     PG_RETURN_BOOL(cmp < 0);
     843              : }
     844              : 
     845              : Datum
     846         2915 : bpcharle(PG_FUNCTION_ARGS)
     847              : {
     848         2915 :     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
     849         2915 :     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
     850              :     int         len1,
     851              :                 len2;
     852              :     int         cmp;
     853              : 
     854         2915 :     len1 = bcTruelen(arg1);
     855         2915 :     len2 = bcTruelen(arg2);
     856              : 
     857         2915 :     cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
     858              :                      PG_GET_COLLATION());
     859              : 
     860         2915 :     PG_FREE_IF_COPY(arg1, 0);
     861         2915 :     PG_FREE_IF_COPY(arg2, 1);
     862              : 
     863         2915 :     PG_RETURN_BOOL(cmp <= 0);
     864              : }
     865              : 
     866              : Datum
     867         3154 : bpchargt(PG_FUNCTION_ARGS)
     868              : {
     869         3154 :     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
     870         3154 :     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
     871              :     int         len1,
     872              :                 len2;
     873              :     int         cmp;
     874              : 
     875         3154 :     len1 = bcTruelen(arg1);
     876         3154 :     len2 = bcTruelen(arg2);
     877              : 
     878         3154 :     cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
     879              :                      PG_GET_COLLATION());
     880              : 
     881         3154 :     PG_FREE_IF_COPY(arg1, 0);
     882         3154 :     PG_FREE_IF_COPY(arg2, 1);
     883              : 
     884         3154 :     PG_RETURN_BOOL(cmp > 0);
     885              : }
     886              : 
     887              : Datum
     888         2916 : bpcharge(PG_FUNCTION_ARGS)
     889              : {
     890         2916 :     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
     891         2916 :     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
     892              :     int         len1,
     893              :                 len2;
     894              :     int         cmp;
     895              : 
     896         2916 :     len1 = bcTruelen(arg1);
     897         2916 :     len2 = bcTruelen(arg2);
     898              : 
     899         2916 :     cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
     900              :                      PG_GET_COLLATION());
     901              : 
     902         2916 :     PG_FREE_IF_COPY(arg1, 0);
     903         2916 :     PG_FREE_IF_COPY(arg2, 1);
     904              : 
     905         2916 :     PG_RETURN_BOOL(cmp >= 0);
     906              : }
     907              : 
     908              : Datum
     909        51663 : bpcharcmp(PG_FUNCTION_ARGS)
     910              : {
     911        51663 :     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
     912        51663 :     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
     913              :     int         len1,
     914              :                 len2;
     915              :     int         cmp;
     916              : 
     917        51663 :     len1 = bcTruelen(arg1);
     918        51663 :     len2 = bcTruelen(arg2);
     919              : 
     920        51663 :     cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
     921              :                      PG_GET_COLLATION());
     922              : 
     923        51663 :     PG_FREE_IF_COPY(arg1, 0);
     924        51663 :     PG_FREE_IF_COPY(arg2, 1);
     925              : 
     926        51663 :     PG_RETURN_INT32(cmp);
     927              : }
     928              : 
     929              : Datum
     930          458 : bpchar_sortsupport(PG_FUNCTION_ARGS)
     931              : {
     932          458 :     SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
     933          458 :     Oid         collid = ssup->ssup_collation;
     934              :     MemoryContext oldcontext;
     935              : 
     936          458 :     oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
     937              : 
     938              :     /* Use generic string SortSupport */
     939          458 :     varstr_sortsupport(ssup, BPCHAROID, collid);
     940              : 
     941          458 :     MemoryContextSwitchTo(oldcontext);
     942              : 
     943          458 :     PG_RETURN_VOID();
     944              : }
     945              : 
     946              : Datum
     947            0 : bpchar_larger(PG_FUNCTION_ARGS)
     948              : {
     949            0 :     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
     950            0 :     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
     951              :     int         len1,
     952              :                 len2;
     953              :     int         cmp;
     954              : 
     955            0 :     len1 = bcTruelen(arg1);
     956            0 :     len2 = bcTruelen(arg2);
     957              : 
     958            0 :     cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
     959              :                      PG_GET_COLLATION());
     960              : 
     961            0 :     PG_RETURN_BPCHAR_P((cmp >= 0) ? arg1 : arg2);
     962              : }
     963              : 
     964              : Datum
     965            0 : bpchar_smaller(PG_FUNCTION_ARGS)
     966              : {
     967            0 :     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
     968            0 :     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
     969              :     int         len1,
     970              :                 len2;
     971              :     int         cmp;
     972              : 
     973            0 :     len1 = bcTruelen(arg1);
     974            0 :     len2 = bcTruelen(arg2);
     975              : 
     976            0 :     cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
     977              :                      PG_GET_COLLATION());
     978              : 
     979            0 :     PG_RETURN_BPCHAR_P((cmp <= 0) ? arg1 : arg2);
     980              : }
     981              : 
     982              : 
     983              : /*
     984              :  * bpchar needs a specialized hash function because we want to ignore
     985              :  * trailing blanks in comparisons.
     986              :  */
     987              : Datum
     988         2191 : hashbpchar(PG_FUNCTION_ARGS)
     989              : {
     990         2191 :     BpChar     *key = PG_GETARG_BPCHAR_PP(0);
     991         2191 :     Oid         collid = PG_GET_COLLATION();
     992              :     char       *keydata;
     993              :     int         keylen;
     994              :     pg_locale_t mylocale;
     995              :     Datum       result;
     996              : 
     997         2191 :     if (!collid)
     998            0 :         ereport(ERROR,
     999              :                 (errcode(ERRCODE_INDETERMINATE_COLLATION),
    1000              :                  errmsg("could not determine which collation to use for string hashing"),
    1001              :                  errhint("Use the COLLATE clause to set the collation explicitly.")));
    1002              : 
    1003         2191 :     keydata = VARDATA_ANY(key);
    1004         2191 :     keylen = bcTruelen(key);
    1005              : 
    1006         2191 :     mylocale = pg_newlocale_from_collation(collid);
    1007              : 
    1008         2191 :     if (mylocale->deterministic)
    1009              :     {
    1010         2107 :         result = hash_any((unsigned char *) keydata, keylen);
    1011              :     }
    1012              :     else
    1013              :     {
    1014              :         Size        bsize,
    1015              :                     rsize;
    1016              :         char       *buf;
    1017              : 
    1018           84 :         bsize = pg_strnxfrm(NULL, 0, keydata, keylen, mylocale);
    1019           84 :         buf = palloc(bsize + 1);
    1020              : 
    1021           84 :         rsize = pg_strnxfrm(buf, bsize + 1, keydata, keylen, mylocale);
    1022              : 
    1023              :         /* the second call may return a smaller value than the first */
    1024           84 :         if (rsize > bsize)
    1025            0 :             elog(ERROR, "pg_strnxfrm() returned unexpected result");
    1026              : 
    1027              :         /*
    1028              :          * In principle, there's no reason to include the terminating NUL
    1029              :          * character in the hash, but it was done before and the behavior must
    1030              :          * be preserved.
    1031              :          */
    1032           84 :         result = hash_any((uint8_t *) buf, bsize + 1);
    1033              : 
    1034           84 :         pfree(buf);
    1035              :     }
    1036              : 
    1037              :     /* Avoid leaking memory for toasted inputs */
    1038         2191 :     PG_FREE_IF_COPY(key, 0);
    1039              : 
    1040         2191 :     return result;
    1041              : }
    1042              : 
    1043              : Datum
    1044           42 : hashbpcharextended(PG_FUNCTION_ARGS)
    1045              : {
    1046           42 :     BpChar     *key = PG_GETARG_BPCHAR_PP(0);
    1047           42 :     Oid         collid = PG_GET_COLLATION();
    1048              :     char       *keydata;
    1049              :     int         keylen;
    1050              :     pg_locale_t mylocale;
    1051              :     Datum       result;
    1052              : 
    1053           42 :     if (!collid)
    1054            0 :         ereport(ERROR,
    1055              :                 (errcode(ERRCODE_INDETERMINATE_COLLATION),
    1056              :                  errmsg("could not determine which collation to use for string hashing"),
    1057              :                  errhint("Use the COLLATE clause to set the collation explicitly.")));
    1058              : 
    1059           42 :     keydata = VARDATA_ANY(key);
    1060           42 :     keylen = bcTruelen(key);
    1061              : 
    1062           42 :     mylocale = pg_newlocale_from_collation(collid);
    1063              : 
    1064           42 :     if (mylocale->deterministic)
    1065              :     {
    1066           36 :         result = hash_any_extended((unsigned char *) keydata, keylen,
    1067           36 :                                    PG_GETARG_INT64(1));
    1068              :     }
    1069              :     else
    1070              :     {
    1071              :         Size        bsize,
    1072              :                     rsize;
    1073              :         char       *buf;
    1074              : 
    1075            6 :         bsize = pg_strnxfrm(NULL, 0, keydata, keylen, mylocale);
    1076            6 :         buf = palloc(bsize + 1);
    1077              : 
    1078            6 :         rsize = pg_strnxfrm(buf, bsize + 1, keydata, keylen, mylocale);
    1079              : 
    1080              :         /* the second call may return a smaller value than the first */
    1081            6 :         if (rsize > bsize)
    1082            0 :             elog(ERROR, "pg_strnxfrm() returned unexpected result");
    1083              : 
    1084              :         /*
    1085              :          * In principle, there's no reason to include the terminating NUL
    1086              :          * character in the hash, but it was done before and the behavior must
    1087              :          * be preserved.
    1088              :          */
    1089            6 :         result = hash_any_extended((uint8_t *) buf, bsize + 1,
    1090            6 :                                    PG_GETARG_INT64(1));
    1091              : 
    1092            6 :         pfree(buf);
    1093              :     }
    1094              : 
    1095           42 :     PG_FREE_IF_COPY(key, 0);
    1096              : 
    1097           42 :     return result;
    1098              : }
    1099              : 
    1100              : /*
    1101              :  * The following operators support character-by-character comparison
    1102              :  * of bpchar datums, to allow building indexes suitable for LIKE clauses.
    1103              :  * Note that the regular bpchareq/bpcharne comparison operators, and
    1104              :  * regular support functions 1 and 2 with "C" collation are assumed to be
    1105              :  * compatible with these!
    1106              :  */
    1107              : 
    1108              : static int
    1109           57 : internal_bpchar_pattern_compare(BpChar *arg1, BpChar *arg2)
    1110              : {
    1111              :     int         result;
    1112              :     int         len1,
    1113              :                 len2;
    1114              : 
    1115           57 :     len1 = bcTruelen(arg1);
    1116           57 :     len2 = bcTruelen(arg2);
    1117              : 
    1118           57 :     result = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
    1119           57 :     if (result != 0)
    1120           33 :         return result;
    1121           24 :     else if (len1 < len2)
    1122            0 :         return -1;
    1123           24 :     else if (len1 > len2)
    1124            0 :         return 1;
    1125              :     else
    1126           24 :         return 0;
    1127              : }
    1128              : 
    1129              : 
    1130              : Datum
    1131            0 : bpchar_pattern_lt(PG_FUNCTION_ARGS)
    1132              : {
    1133            0 :     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
    1134            0 :     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
    1135              :     int         result;
    1136              : 
    1137            0 :     result = internal_bpchar_pattern_compare(arg1, arg2);
    1138              : 
    1139            0 :     PG_FREE_IF_COPY(arg1, 0);
    1140            0 :     PG_FREE_IF_COPY(arg2, 1);
    1141              : 
    1142            0 :     PG_RETURN_BOOL(result < 0);
    1143              : }
    1144              : 
    1145              : 
    1146              : Datum
    1147            0 : bpchar_pattern_le(PG_FUNCTION_ARGS)
    1148              : {
    1149            0 :     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
    1150            0 :     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
    1151              :     int         result;
    1152              : 
    1153            0 :     result = internal_bpchar_pattern_compare(arg1, arg2);
    1154              : 
    1155            0 :     PG_FREE_IF_COPY(arg1, 0);
    1156            0 :     PG_FREE_IF_COPY(arg2, 1);
    1157              : 
    1158            0 :     PG_RETURN_BOOL(result <= 0);
    1159              : }
    1160              : 
    1161              : 
    1162              : Datum
    1163            0 : bpchar_pattern_ge(PG_FUNCTION_ARGS)
    1164              : {
    1165            0 :     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
    1166            0 :     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
    1167              :     int         result;
    1168              : 
    1169            0 :     result = internal_bpchar_pattern_compare(arg1, arg2);
    1170              : 
    1171            0 :     PG_FREE_IF_COPY(arg1, 0);
    1172            0 :     PG_FREE_IF_COPY(arg2, 1);
    1173              : 
    1174            0 :     PG_RETURN_BOOL(result >= 0);
    1175              : }
    1176              : 
    1177              : 
    1178              : Datum
    1179            0 : bpchar_pattern_gt(PG_FUNCTION_ARGS)
    1180              : {
    1181            0 :     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
    1182            0 :     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
    1183              :     int         result;
    1184              : 
    1185            0 :     result = internal_bpchar_pattern_compare(arg1, arg2);
    1186              : 
    1187            0 :     PG_FREE_IF_COPY(arg1, 0);
    1188            0 :     PG_FREE_IF_COPY(arg2, 1);
    1189              : 
    1190            0 :     PG_RETURN_BOOL(result > 0);
    1191              : }
    1192              : 
    1193              : 
    1194              : Datum
    1195           57 : btbpchar_pattern_cmp(PG_FUNCTION_ARGS)
    1196              : {
    1197           57 :     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
    1198           57 :     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
    1199              :     int         result;
    1200              : 
    1201           57 :     result = internal_bpchar_pattern_compare(arg1, arg2);
    1202              : 
    1203           57 :     PG_FREE_IF_COPY(arg1, 0);
    1204           57 :     PG_FREE_IF_COPY(arg2, 1);
    1205              : 
    1206           57 :     PG_RETURN_INT32(result);
    1207              : }
    1208              : 
    1209              : 
    1210              : Datum
    1211            6 : btbpchar_pattern_sortsupport(PG_FUNCTION_ARGS)
    1212              : {
    1213            6 :     SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
    1214              :     MemoryContext oldcontext;
    1215              : 
    1216            6 :     oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
    1217              : 
    1218              :     /* Use generic string SortSupport, forcing "C" collation */
    1219            6 :     varstr_sortsupport(ssup, BPCHAROID, C_COLLATION_OID);
    1220              : 
    1221            6 :     MemoryContextSwitchTo(oldcontext);
    1222              : 
    1223            6 :     PG_RETURN_VOID();
    1224              : }
        

Generated by: LCOV version 2.0-1