LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - varlena.c (source / functions) Coverage Total Hit UNC LBC UBC GBC GNC CBC DUB DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 89.7 % 2237 2006 4 2 225 4 56 1946 1 18
Current Date: 2024-04-14 14:21:10 Functions: 92.4 % 172 159 13 13 146
Baseline: 16@8cea358b128 Branches: 54.5 % 2453 1337 35 2 1079 6 29 1302
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 81.2 % 16 13 3 13
(120,180] days: 94.7 % 19 18 1 18
(180,240] days: 100.0 % 25 25 22 3
(240..) days: 89.6 % 2177 1950 2 225 4 3 1943
Function coverage date bins:
[..60] days: 100.0 % 1 1 1
(120,180] days: 100.0 % 3 3 3
(180,240] days: 100.0 % 7 7 7
(240..) days: 91.9 % 161 148 13 2 146
Branch coverage date bins:
[..60] days: 50.0 % 22 11 11 11
(120,180] days: 35.3 % 34 12 22 12
(180,240] days: 50.0 % 4 2 2 2
(240..) days: 54.8 % 2393 1312 2 1079 6 4 1302

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * varlena.c
                                  4                 :                :  *    Functions for the variable-length built-in types.
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
                                  7                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :                :  *
                                  9                 :                :  *
                                 10                 :                :  * IDENTIFICATION
                                 11                 :                :  *    src/backend/utils/adt/varlena.c
                                 12                 :                :  *
                                 13                 :                :  *-------------------------------------------------------------------------
                                 14                 :                :  */
                                 15                 :                : #include "postgres.h"
                                 16                 :                : 
                                 17                 :                : #include <ctype.h>
                                 18                 :                : #include <limits.h>
                                 19                 :                : 
                                 20                 :                : #include "access/detoast.h"
                                 21                 :                : #include "access/toast_compression.h"
                                 22                 :                : #include "catalog/pg_collation.h"
                                 23                 :                : #include "catalog/pg_type.h"
                                 24                 :                : #include "common/hashfn.h"
                                 25                 :                : #include "common/int.h"
                                 26                 :                : #include "common/unicode_category.h"
                                 27                 :                : #include "common/unicode_norm.h"
                                 28                 :                : #include "common/unicode_version.h"
                                 29                 :                : #include "funcapi.h"
                                 30                 :                : #include "lib/hyperloglog.h"
                                 31                 :                : #include "libpq/pqformat.h"
                                 32                 :                : #include "miscadmin.h"
                                 33                 :                : #include "nodes/execnodes.h"
                                 34                 :                : #include "parser/scansup.h"
                                 35                 :                : #include "port/pg_bswap.h"
                                 36                 :                : #include "regex/regex.h"
                                 37                 :                : #include "utils/builtins.h"
                                 38                 :                : #include "utils/bytea.h"
                                 39                 :                : #include "utils/guc.h"
                                 40                 :                : #include "utils/lsyscache.h"
                                 41                 :                : #include "utils/memutils.h"
                                 42                 :                : #include "utils/pg_locale.h"
                                 43                 :                : #include "utils/sortsupport.h"
                                 44                 :                : #include "utils/varlena.h"
                                 45                 :                : 
                                 46                 :                : 
                                 47                 :                : /* GUC variable */
                                 48                 :                : int         bytea_output = BYTEA_OUTPUT_HEX;
                                 49                 :                : 
                                 50                 :                : typedef struct varlena VarString;
                                 51                 :                : 
                                 52                 :                : /*
                                 53                 :                :  * State for text_position_* functions.
                                 54                 :                :  */
                                 55                 :                : typedef struct
                                 56                 :                : {
                                 57                 :                :     bool        is_multibyte_char_in_char;  /* need to check char boundaries? */
                                 58                 :                : 
                                 59                 :                :     char       *str1;           /* haystack string */
                                 60                 :                :     char       *str2;           /* needle string */
                                 61                 :                :     int         len1;           /* string lengths in bytes */
                                 62                 :                :     int         len2;
                                 63                 :                : 
                                 64                 :                :     /* Skip table for Boyer-Moore-Horspool search algorithm: */
                                 65                 :                :     int         skiptablemask;  /* mask for ANDing with skiptable subscripts */
                                 66                 :                :     int         skiptable[256]; /* skip distance for given mismatched char */
                                 67                 :                : 
                                 68                 :                :     char       *last_match;     /* pointer to last match in 'str1' */
                                 69                 :                : 
                                 70                 :                :     /*
                                 71                 :                :      * Sometimes we need to convert the byte position of a match to a
                                 72                 :                :      * character position.  These store the last position that was converted,
                                 73                 :                :      * so that on the next call, we can continue from that point, rather than
                                 74                 :                :      * count characters from the very beginning.
                                 75                 :                :      */
                                 76                 :                :     char       *refpoint;       /* pointer within original haystack string */
                                 77                 :                :     int         refpos;         /* 0-based character offset of the same point */
                                 78                 :                : } TextPositionState;
                                 79                 :                : 
                                 80                 :                : typedef struct
                                 81                 :                : {
                                 82                 :                :     char       *buf1;           /* 1st string, or abbreviation original string
                                 83                 :                :                                  * buf */
                                 84                 :                :     char       *buf2;           /* 2nd string, or abbreviation strxfrm() buf */
                                 85                 :                :     int         buflen1;        /* Allocated length of buf1 */
                                 86                 :                :     int         buflen2;        /* Allocated length of buf2 */
                                 87                 :                :     int         last_len1;      /* Length of last buf1 string/strxfrm() input */
                                 88                 :                :     int         last_len2;      /* Length of last buf2 string/strxfrm() blob */
                                 89                 :                :     int         last_returned;  /* Last comparison result (cache) */
                                 90                 :                :     bool        cache_blob;     /* Does buf2 contain strxfrm() blob, etc? */
                                 91                 :                :     bool        collate_c;
                                 92                 :                :     Oid         typid;          /* Actual datatype (text/bpchar/bytea/name) */
                                 93                 :                :     hyperLogLogState abbr_card; /* Abbreviated key cardinality state */
                                 94                 :                :     hyperLogLogState full_card; /* Full key cardinality state */
                                 95                 :                :     double      prop_card;      /* Required cardinality proportion */
                                 96                 :                :     pg_locale_t locale;
                                 97                 :                : } VarStringSortSupport;
                                 98                 :                : 
                                 99                 :                : /*
                                100                 :                :  * Output data for split_text(): we output either to an array or a table.
                                101                 :                :  * tupstore and tupdesc must be set up in advance to output to a table.
                                102                 :                :  */
                                103                 :                : typedef struct
                                104                 :                : {
                                105                 :                :     ArrayBuildState *astate;
                                106                 :                :     Tuplestorestate *tupstore;
                                107                 :                :     TupleDesc   tupdesc;
                                108                 :                : } SplitTextOutputData;
                                109                 :                : 
                                110                 :                : /*
                                111                 :                :  * This should be large enough that most strings will fit, but small enough
                                112                 :                :  * that we feel comfortable putting it on the stack
                                113                 :                :  */
                                114                 :                : #define TEXTBUFLEN      1024
                                115                 :                : 
                                116                 :                : #define DatumGetVarStringP(X)       ((VarString *) PG_DETOAST_DATUM(X))
                                117                 :                : #define DatumGetVarStringPP(X)      ((VarString *) PG_DETOAST_DATUM_PACKED(X))
                                118                 :                : 
                                119                 :                : static int  varstrfastcmp_c(Datum x, Datum y, SortSupport ssup);
                                120                 :                : static int  bpcharfastcmp_c(Datum x, Datum y, SortSupport ssup);
                                121                 :                : static int  namefastcmp_c(Datum x, Datum y, SortSupport ssup);
                                122                 :                : static int  varlenafastcmp_locale(Datum x, Datum y, SortSupport ssup);
                                123                 :                : static int  namefastcmp_locale(Datum x, Datum y, SortSupport ssup);
                                124                 :                : static int  varstrfastcmp_locale(char *a1p, int len1, char *a2p, int len2, SortSupport ssup);
                                125                 :                : static Datum varstr_abbrev_convert(Datum original, SortSupport ssup);
                                126                 :                : static bool varstr_abbrev_abort(int memtupcount, SortSupport ssup);
                                127                 :                : static int32 text_length(Datum str);
                                128                 :                : static text *text_catenate(text *t1, text *t2);
                                129                 :                : static text *text_substring(Datum str,
                                130                 :                :                             int32 start,
                                131                 :                :                             int32 length,
                                132                 :                :                             bool length_not_specified);
                                133                 :                : static text *text_overlay(text *t1, text *t2, int sp, int sl);
                                134                 :                : static int  text_position(text *t1, text *t2, Oid collid);
                                135                 :                : static void text_position_setup(text *t1, text *t2, Oid collid, TextPositionState *state);
                                136                 :                : static bool text_position_next(TextPositionState *state);
                                137                 :                : static char *text_position_next_internal(char *start_ptr, TextPositionState *state);
                                138                 :                : static char *text_position_get_match_ptr(TextPositionState *state);
                                139                 :                : static int  text_position_get_match_pos(TextPositionState *state);
                                140                 :                : static void text_position_cleanup(TextPositionState *state);
                                141                 :                : static void check_collation_set(Oid collid);
                                142                 :                : static int  text_cmp(text *arg1, text *arg2, Oid collid);
                                143                 :                : static bytea *bytea_catenate(bytea *t1, bytea *t2);
                                144                 :                : static bytea *bytea_substring(Datum str,
                                145                 :                :                               int S,
                                146                 :                :                               int L,
                                147                 :                :                               bool length_not_specified);
                                148                 :                : static bytea *bytea_overlay(bytea *t1, bytea *t2, int sp, int sl);
                                149                 :                : static void appendStringInfoText(StringInfo str, const text *t);
                                150                 :                : static bool split_text(FunctionCallInfo fcinfo, SplitTextOutputData *tstate);
                                151                 :                : static void split_text_accum_result(SplitTextOutputData *tstate,
                                152                 :                :                                     text *field_value,
                                153                 :                :                                     text *null_string,
                                154                 :                :                                     Oid collation);
                                155                 :                : static text *array_to_text_internal(FunctionCallInfo fcinfo, ArrayType *v,
                                156                 :                :                                     const char *fldsep, const char *null_string);
                                157                 :                : static StringInfo makeStringAggState(FunctionCallInfo fcinfo);
                                158                 :                : static bool text_format_parse_digits(const char **ptr, const char *end_ptr,
                                159                 :                :                                      int *value);
                                160                 :                : static const char *text_format_parse_format(const char *start_ptr,
                                161                 :                :                                             const char *end_ptr,
                                162                 :                :                                             int *argpos, int *widthpos,
                                163                 :                :                                             int *flags, int *width);
                                164                 :                : static void text_format_string_conversion(StringInfo buf, char conversion,
                                165                 :                :                                           FmgrInfo *typOutputInfo,
                                166                 :                :                                           Datum value, bool isNull,
                                167                 :                :                                           int flags, int width);
                                168                 :                : static void text_format_append_string(StringInfo buf, const char *str,
                                169                 :                :                                       int flags, int width);
                                170                 :                : 
                                171                 :                : 
                                172                 :                : /*****************************************************************************
                                173                 :                :  *   CONVERSION ROUTINES EXPORTED FOR USE BY C CODE                          *
                                174                 :                :  *****************************************************************************/
                                175                 :                : 
                                176                 :                : /*
                                177                 :                :  * cstring_to_text
                                178                 :                :  *
                                179                 :                :  * Create a text value from a null-terminated C string.
                                180                 :                :  *
                                181                 :                :  * The new text value is freshly palloc'd with a full-size VARHDR.
                                182                 :                :  */
                                183                 :                : text *
 5864 tgl@sss.pgh.pa.us         184                 :CBC    11979272 : cstring_to_text(const char *s)
                                185                 :                : {
                                186                 :       11979272 :     return cstring_to_text_with_len(s, strlen(s));
                                187                 :                : }
                                188                 :                : 
                                189                 :                : /*
                                190                 :                :  * cstring_to_text_with_len
                                191                 :                :  *
                                192                 :                :  * Same as cstring_to_text except the caller specifies the string length;
                                193                 :                :  * the string need not be null_terminated.
                                194                 :                :  */
                                195                 :                : text *
                                196                 :       13258025 : cstring_to_text_with_len(const char *s, int len)
                                197                 :                : {
                                198                 :       13258025 :     text       *result = (text *) palloc(len + VARHDRSZ);
                                199                 :                : 
                                200                 :       13258025 :     SET_VARSIZE(result, len + VARHDRSZ);
                                201                 :       13258025 :     memcpy(VARDATA(result), s, len);
                                202                 :                : 
                                203                 :       13258025 :     return result;
                                204                 :                : }
                                205                 :                : 
                                206                 :                : /*
                                207                 :                :  * text_to_cstring
                                208                 :                :  *
                                209                 :                :  * Create a palloc'd, null-terminated C string from a text value.
                                210                 :                :  *
                                211                 :                :  * We support being passed a compressed or toasted text value.
                                212                 :                :  * This is a bit bogus since such values shouldn't really be referred to as
                                213                 :                :  * "text *", but it seems useful for robustness.  If we didn't handle that
                                214                 :                :  * case here, we'd need another routine that did, anyway.
                                215                 :                :  */
                                216                 :                : char *
                                217                 :        7413524 : text_to_cstring(const text *t)
                                218                 :                : {
                                219                 :                :     /* must cast away the const, unfortunately */
 1998 peter_e@gmx.net           220                 :        7413524 :     text       *tunpacked = pg_detoast_datum_packed(unconstify(text *, t));
 5864 tgl@sss.pgh.pa.us         221   [ -  +  -  -  :        7413524 :     int         len = VARSIZE_ANY_EXHDR(tunpacked);
                                     -  -  -  -  +  
                                                 + ]
                                222                 :                :     char       *result;
                                223                 :                : 
                                224                 :        7413524 :     result = (char *) palloc(len + 1);
                                225         [ +  + ]:        7413524 :     memcpy(result, VARDATA_ANY(tunpacked), len);
                                226                 :        7413524 :     result[len] = '\0';
                                227                 :                : 
                                228         [ +  + ]:        7413524 :     if (tunpacked != t)
                                229                 :          17645 :         pfree(tunpacked);
                                230                 :                : 
                                231                 :        7413524 :     return result;
                                232                 :                : }
                                233                 :                : 
                                234                 :                : /*
                                235                 :                :  * text_to_cstring_buffer
                                236                 :                :  *
                                237                 :                :  * Copy a text value into a caller-supplied buffer of size dst_len.
                                238                 :                :  *
                                239                 :                :  * The text string is truncated if necessary to fit.  The result is
                                240                 :                :  * guaranteed null-terminated (unless dst_len == 0).
                                241                 :                :  *
                                242                 :                :  * We support being passed a compressed or toasted text value.
                                243                 :                :  * This is a bit bogus since such values shouldn't really be referred to as
                                244                 :                :  * "text *", but it seems useful for robustness.  If we didn't handle that
                                245                 :                :  * case here, we'd need another routine that did, anyway.
                                246                 :                :  */
                                247                 :                : void
                                248                 :            470 : text_to_cstring_buffer(const text *src, char *dst, size_t dst_len)
                                249                 :                : {
                                250                 :                :     /* must cast away the const, unfortunately */
 1998 peter_e@gmx.net           251                 :            470 :     text       *srcunpacked = pg_detoast_datum_packed(unconstify(text *, src));
 5864 tgl@sss.pgh.pa.us         252   [ -  +  -  -  :            470 :     size_t      src_len = VARSIZE_ANY_EXHDR(srcunpacked);
                                     -  -  -  -  -  
                                                 + ]
                                253                 :                : 
                                254         [ +  - ]:            470 :     if (dst_len > 0)
                                255                 :                :     {
                                256                 :            470 :         dst_len--;
                                257         [ +  - ]:            470 :         if (dst_len >= src_len)
                                258                 :            470 :             dst_len = src_len;
                                259                 :                :         else                    /* ensure truncation is encoding-safe */
 5864 tgl@sss.pgh.pa.us         260         [ #  # ]:UBC           0 :             dst_len = pg_mbcliplen(VARDATA_ANY(srcunpacked), src_len, dst_len);
 5864 tgl@sss.pgh.pa.us         261         [ -  + ]:CBC         470 :         memcpy(dst, VARDATA_ANY(srcunpacked), dst_len);
                                262                 :            470 :         dst[dst_len] = '\0';
                                263                 :                :     }
                                264                 :                : 
                                265         [ -  + ]:            470 :     if (srcunpacked != src)
 5864 tgl@sss.pgh.pa.us         266                 :UBC           0 :         pfree(srcunpacked);
 5864 tgl@sss.pgh.pa.us         267                 :CBC         470 : }
                                268                 :                : 
                                269                 :                : 
                                270                 :                : /*****************************************************************************
                                271                 :                :  *   USER I/O ROUTINES                                                       *
                                272                 :                :  *****************************************************************************/
                                273                 :                : 
                                274                 :                : 
                                275                 :                : #define VAL(CH)         ((CH) - '0')
                                276                 :                : #define DIG(VAL)        ((VAL) + '0')
                                277                 :                : 
                                278                 :                : /*
                                279                 :                :  *      byteain         - converts from printable representation of byte array
                                280                 :                :  *
                                281                 :                :  *      Non-printable characters must be passed as '\nnn' (octal) and are
                                282                 :                :  *      converted to internal form.  '\' must be passed as '\\'.
                                283                 :                :  *      ereport(ERROR, ...) if bad form.
                                284                 :                :  *
                                285                 :                :  *      BUGS:
                                286                 :                :  *              The input is scanned twice.
                                287                 :                :  *              The error checking of input is minimal.
                                288                 :                :  */
                                289                 :                : Datum
 8660                           290                 :         491448 : byteain(PG_FUNCTION_ARGS)
                                291                 :                : {
                                292                 :         491448 :     char       *inputText = PG_GETARG_CSTRING(0);
  487                           293                 :         491448 :     Node       *escontext = fcinfo->context;
                                294                 :                :     char       *tp;
                                295                 :                :     char       *rp;
                                296                 :                :     int         bc;
                                297                 :                :     bytea      *result;
                                298                 :                : 
                                299                 :                :     /* Recognize hex input */
 5367                           300   [ +  +  +  + ]:         491448 :     if (inputText[0] == '\\' && inputText[1] == 'x')
                                301                 :                :     {
 5161 bruce@momjian.us          302                 :          55608 :         size_t      len = strlen(inputText);
                                303                 :                : 
  969 michael@paquier.xyz       304                 :          55608 :         bc = (len - 2) / 2 + VARHDRSZ;  /* maximum possible length */
 5367 tgl@sss.pgh.pa.us         305                 :          55608 :         result = palloc(bc);
  487                           306                 :          55608 :         bc = hex_decode_safe(inputText + 2, len - 2, VARDATA(result),
                                307                 :                :                              escontext);
 2489                           308                 :          55602 :         SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */
                                309                 :                : 
 5367                           310                 :          55602 :         PG_RETURN_BYTEA_P(result);
                                311                 :                :     }
                                312                 :                : 
                                313                 :                :     /* Else, it's the traditional escaped style */
                                314         [ +  + ]:        4033015 :     for (bc = 0, tp = inputText; *tp != '\0'; bc++)
                                315                 :                :     {
 8248 bruce@momjian.us          316         [ +  + ]:        3597181 :         if (tp[0] != '\\')
                                317                 :        3596635 :             tp++;
 8207                           318         [ +  - ]:            546 :         else if ((tp[0] == '\\') &&
                                319   [ +  -  +  + ]:            546 :                  (tp[1] >= '0' && tp[1] <= '3') &&
                                320   [ +  -  +  - ]:            540 :                  (tp[2] >= '0' && tp[2] <= '7') &&
                                321   [ +  -  +  - ]:            540 :                  (tp[3] >= '0' && tp[3] <= '7'))
 8248                           322                 :            540 :             tp += 4;
 8207                           323         [ +  - ]:              6 :         else if ((tp[0] == '\\') &&
                                324         [ -  + ]:              6 :                  (tp[1] == '\\'))
 8248 bruce@momjian.us          325                 :UBC           0 :             tp += 2;
                                326                 :                :         else
                                327                 :                :         {
                                328                 :                :             /*
                                329                 :                :              * one backslash, not followed by another or ### valid octal
                                330                 :                :              */
  487 tgl@sss.pgh.pa.us         331         [ +  - ]:CBC           6 :             ereturn(escontext, (Datum) 0,
                                332                 :                :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                                333                 :                :                      errmsg("invalid input syntax for type %s", "bytea")));
                                334                 :                :         }
                                335                 :                :     }
                                336                 :                : 
 5367                           337                 :         435834 :     bc += VARHDRSZ;
                                338                 :                : 
                                339                 :         435834 :     result = (bytea *) palloc(bc);
                                340                 :         435834 :     SET_VARSIZE(result, bc);
                                341                 :                : 
 8660                           342                 :         435834 :     tp = inputText;
 7646                           343                 :         435834 :     rp = VARDATA(result);
 9716 bruce@momjian.us          344         [ +  + ]:        4032994 :     while (*tp != '\0')
                                345                 :                :     {
 8248                           346         [ +  + ]:        3597160 :         if (tp[0] != '\\')
 9716                           347                 :        3596620 :             *rp++ = *tp++;
 8207                           348         [ +  - ]:            540 :         else if ((tp[0] == '\\') &&
                                349   [ +  -  +  - ]:            540 :                  (tp[1] >= '0' && tp[1] <= '3') &&
                                350   [ +  -  +  - ]:            540 :                  (tp[2] >= '0' && tp[2] <= '7') &&
                                351   [ +  -  +  - ]:            540 :                  (tp[3] >= '0' && tp[3] <= '7'))
                                352                 :                :         {
 5367 tgl@sss.pgh.pa.us         353                 :            540 :             bc = VAL(tp[1]);
                                354                 :            540 :             bc <<= 3;
                                355                 :            540 :             bc += VAL(tp[2]);
                                356                 :            540 :             bc <<= 3;
                                357                 :            540 :             *rp++ = bc + VAL(tp[3]);
                                358                 :                : 
 8248 bruce@momjian.us          359                 :            540 :             tp += 4;
                                360                 :                :         }
 8207 bruce@momjian.us          361         [ #  # ]:UBC           0 :         else if ((tp[0] == '\\') &&
                                362         [ #  # ]:              0 :                  (tp[1] == '\\'))
                                363                 :                :         {
 8248                           364                 :              0 :             *rp++ = '\\';
                                365                 :              0 :             tp += 2;
                                366                 :                :         }
                                367                 :                :         else
                                368                 :                :         {
                                369                 :                :             /*
                                370                 :                :              * We should never get here. The first pass should not allow it.
                                371                 :                :              */
  487 tgl@sss.pgh.pa.us         372         [ #  # ]:              0 :             ereturn(escontext, (Datum) 0,
                                373                 :                :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                                374                 :                :                      errmsg("invalid input syntax for type %s", "bytea")));
                                375                 :                :         }
                                376                 :                :     }
                                377                 :                : 
 8660 tgl@sss.pgh.pa.us         378                 :CBC      435834 :     PG_RETURN_BYTEA_P(result);
                                379                 :                : }
                                380                 :                : 
                                381                 :                : /*
                                382                 :                :  *      byteaout        - converts to printable representation of byte array
                                383                 :                :  *
                                384                 :                :  *      In the traditional escaped format, non-printable characters are
                                385                 :                :  *      printed as '\nnn' (octal) and '\' as '\\'.
                                386                 :                :  */
                                387                 :                : Datum
                                388                 :          79390 : byteaout(PG_FUNCTION_ARGS)
                                389                 :                : {
 6218                           390                 :          79390 :     bytea      *vlena = PG_GETARG_BYTEA_PP(0);
                                391                 :                :     char       *result;
                                392                 :                :     char       *rp;
                                393                 :                : 
 5367                           394         [ +  + ]:          79390 :     if (bytea_output == BYTEA_OUTPUT_HEX)
                                395                 :                :     {
                                396                 :                :         /* Print hex format */
  969 michael@paquier.xyz       397   [ -  +  -  -  :          79199 :         rp = result = palloc(VARSIZE_ANY_EXHDR(vlena) * 2 + 2 + 1);
                                     -  -  -  -  +  
                                                 + ]
 5367 tgl@sss.pgh.pa.us         398                 :          79199 :         *rp++ = '\\';
                                399                 :          79199 :         *rp++ = 'x';
  969 michael@paquier.xyz       400   [ -  +  -  -  :          79199 :         rp += hex_encode(VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena), rp);
                                     -  -  -  -  +  
                                           +  +  + ]
                                401                 :                :     }
 5367 tgl@sss.pgh.pa.us         402         [ +  - ]:            191 :     else if (bytea_output == BYTEA_OUTPUT_ESCAPE)
                                403                 :                :     {
                                404                 :                :         /* Print traditional escaped format */
                                405                 :                :         char       *vp;
                                406                 :                :         uint64      len;
                                407                 :                :         int         i;
                                408                 :                : 
 5161 bruce@momjian.us          409                 :            191 :         len = 1;                /* empty string has 1 char */
                                410         [ +  + ]:            191 :         vp = VARDATA_ANY(vlena);
                                411   [ -  +  -  -  :         108825 :         for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++)
                                     -  -  -  -  +  
                                           +  +  + ]
                                412                 :                :         {
                                413         [ -  + ]:         108634 :             if (*vp == '\\')
 5161 bruce@momjian.us          414                 :UBC           0 :                 len += 2;
 5161 bruce@momjian.us          415   [ +  +  +  + ]:CBC      108634 :             else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e)
                                416                 :            246 :                 len += 4;
                                417                 :                :             else
                                418                 :         108388 :                 len++;
                                419                 :                :         }
                                420                 :                : 
                                421                 :                :         /*
                                422                 :                :          * In principle len can't overflow uint32 if the input fit in 1GB, but
                                423                 :                :          * for safety let's check rather than relying on palloc's internal
                                424                 :                :          * check.
                                425                 :                :          */
 1468 tgl@sss.pgh.pa.us         426         [ -  + ]:            191 :         if (len > MaxAllocSize)
 1468 tgl@sss.pgh.pa.us         427         [ #  # ]:UBC           0 :             ereport(ERROR,
                                428                 :                :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                429                 :                :                      errmsg_internal("result of bytea output conversion is too large")));
 5161 bruce@momjian.us          430                 :CBC         191 :         rp = result = (char *) palloc(len);
                                431                 :                : 
                                432         [ +  + ]:            191 :         vp = VARDATA_ANY(vlena);
                                433   [ -  +  -  -  :         108825 :         for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++)
                                     -  -  -  -  +  
                                           +  +  + ]
                                434                 :                :         {
                                435         [ -  + ]:         108634 :             if (*vp == '\\')
                                436                 :                :             {
 5161 bruce@momjian.us          437                 :UBC           0 :                 *rp++ = '\\';
                                438                 :              0 :                 *rp++ = '\\';
                                439                 :                :             }
 5161 bruce@momjian.us          440   [ +  +  +  + ]:CBC      108634 :             else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e)
                                441                 :            246 :             {
                                442                 :                :                 int         val;    /* holds unprintable chars */
                                443                 :                : 
                                444                 :            246 :                 val = *vp;
                                445                 :            246 :                 rp[0] = '\\';
                                446                 :            246 :                 rp[3] = DIG(val & 07);
                                447                 :            246 :                 val >>= 3;
                                448                 :            246 :                 rp[2] = DIG(val & 07);
                                449                 :            246 :                 val >>= 3;
                                450                 :            246 :                 rp[1] = DIG(val & 03);
                                451                 :            246 :                 rp += 4;
                                452                 :                :             }
                                453                 :                :             else
                                454                 :         108388 :                 *rp++ = *vp;
                                455                 :                :         }
                                456                 :                :     }
                                457                 :                :     else
                                458                 :                :     {
 5367 tgl@sss.pgh.pa.us         459         [ #  # ]:UBC           0 :         elog(ERROR, "unrecognized bytea_output setting: %d",
                                460                 :                :              bytea_output);
                                461                 :                :         rp = result = NULL;     /* keep compiler quiet */
                                462                 :                :     }
 9716 bruce@momjian.us          463                 :CBC       79390 :     *rp = '\0';
 8660 tgl@sss.pgh.pa.us         464                 :          79390 :     PG_RETURN_CSTRING(result);
                                465                 :                : }
                                466                 :                : 
                                467                 :                : /*
                                468                 :                :  *      bytearecv           - converts external binary format to bytea
                                469                 :                :  */
                                470                 :                : Datum
 7646                           471                 :          53842 : bytearecv(PG_FUNCTION_ARGS)
                                472                 :                : {
                                473                 :          53842 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
                                474                 :                :     bytea      *result;
                                475                 :                :     int         nbytes;
                                476                 :                : 
                                477                 :          53842 :     nbytes = buf->len - buf->cursor;
                                478                 :          53842 :     result = (bytea *) palloc(nbytes + VARHDRSZ);
 6256                           479                 :          53842 :     SET_VARSIZE(result, nbytes + VARHDRSZ);
 7646                           480                 :          53842 :     pq_copymsgbytes(buf, VARDATA(result), nbytes);
                                481                 :          53842 :     PG_RETURN_BYTEA_P(result);
                                482                 :                : }
                                483                 :                : 
                                484                 :                : /*
                                485                 :                :  *      byteasend           - converts bytea to binary format
                                486                 :                :  *
                                487                 :                :  * This is a special case: just copy the input...
                                488                 :                :  */
                                489                 :                : Datum
                                490                 :          34485 : byteasend(PG_FUNCTION_ARGS)
                                491                 :                : {
                                492                 :          34485 :     bytea      *vlena = PG_GETARG_BYTEA_P_COPY(0);
                                493                 :                : 
                                494                 :          34485 :     PG_RETURN_BYTEA_P(vlena);
                                495                 :                : }
                                496                 :                : 
                                497                 :                : Datum
 4384 peter_e@gmx.net           498                 :         129387 : bytea_string_agg_transfn(PG_FUNCTION_ARGS)
                                499                 :                : {
                                500                 :                :     StringInfo  state;
                                501                 :                : 
 4496 rhaas@postgresql.org      502         [ +  + ]:         129387 :     state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);
                                503                 :                : 
                                504                 :                :     /* Append the value unless null, preceding it with the delimiter. */
                                505         [ +  + ]:         129387 :     if (!PG_ARGISNULL(1))
                                506                 :                :     {
                                507                 :         121887 :         bytea      *value = PG_GETARG_BYTEA_PP(1);
  447 drowley@postgresql.o      508                 :         121887 :         bool        isfirst = false;
                                509                 :                : 
                                510                 :                :         /*
                                511                 :                :          * You might think we can just throw away the first delimiter, however
                                512                 :                :          * we must keep it as we may be a parallel worker doing partial
                                513                 :                :          * aggregation building a state to send to the main process.  We need
                                514                 :                :          * to keep the delimiter of every aggregation so that the combine
                                515                 :                :          * function can properly join up the strings of two separately
                                516                 :                :          * partially aggregated results.  The first delimiter is only stripped
                                517                 :                :          * off in the final function.  To know how much to strip off the front
                                518                 :                :          * of the string, we store the length of the first delimiter in the
                                519                 :                :          * StringInfo's cursor field, which we don't otherwise need here.
                                520                 :                :          */
 4496 rhaas@postgresql.org      521         [ +  + ]:         121887 :         if (state == NULL)
                                522                 :                :         {
                                523                 :            104 :             state = makeStringAggState(fcinfo);
  447 drowley@postgresql.o      524                 :            104 :             isfirst = true;
                                525                 :                :         }
                                526                 :                : 
                                527         [ +  + ]:         121887 :         if (!PG_ARGISNULL(2))
                                528                 :                :         {
 4384 peter_e@gmx.net           529                 :         121881 :             bytea      *delim = PG_GETARG_BYTEA_PP(2);
                                530                 :                : 
  447 drowley@postgresql.o      531         [ -  + ]:         121881 :             appendBinaryStringInfo(state, VARDATA_ANY(delim),
                                532   [ -  +  -  -  :         121881 :                                    VARSIZE_ANY_EXHDR(delim));
                                     -  -  -  -  -  
                                                 + ]
                                533         [ +  + ]:         121881 :             if (isfirst)
                                534   [ -  +  -  -  :            101 :                 state->cursor = VARSIZE_ANY_EXHDR(delim);
                                     -  -  -  -  -  
                                                 + ]
                                535                 :                :         }
                                536                 :                : 
                                537         [ +  + ]:         121887 :         appendBinaryStringInfo(state, VARDATA_ANY(value),
                                538   [ -  +  -  -  :         121887 :                                VARSIZE_ANY_EXHDR(value));
                                     -  -  -  -  +  
                                                 + ]
                                539                 :                :     }
                                540                 :                : 
                                541                 :                :     /*
                                542                 :                :      * The transition type for string_agg() is declared to be "internal",
                                543                 :                :      * which is a pass-by-value type the same size as a pointer.
                                544                 :                :      */
                                545         [ +  + ]:         129387 :     if (state)
                                546                 :         129361 :         PG_RETURN_POINTER(state);
                                547                 :             26 :     PG_RETURN_NULL();
                                548                 :                : }
                                549                 :                : 
                                550                 :                : Datum
 4384 peter_e@gmx.net           551                 :             77 : bytea_string_agg_finalfn(PG_FUNCTION_ARGS)
                                552                 :                : {
                                553                 :                :     StringInfo  state;
                                554                 :                : 
                                555                 :                :     /* cannot be called directly because of internal-type argument */
 4496 rhaas@postgresql.org      556         [ -  + ]:             77 :     Assert(AggCheckCallContext(fcinfo, NULL));
                                557                 :                : 
                                558         [ +  + ]:             77 :     state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);
                                559                 :                : 
                                560         [ +  + ]:             77 :     if (state != NULL)
                                561                 :                :     {
                                562                 :                :         /* As per comment in transfn, strip data before the cursor position */
                                563                 :                :         bytea      *result;
  447 drowley@postgresql.o      564                 :             74 :         int         strippedlen = state->len - state->cursor;
                                565                 :                : 
                                566                 :             74 :         result = (bytea *) palloc(strippedlen + VARHDRSZ);
                                567                 :             74 :         SET_VARSIZE(result, strippedlen + VARHDRSZ);
                                568                 :             74 :         memcpy(VARDATA(result), &state->data[state->cursor], strippedlen);
 4496 rhaas@postgresql.org      569                 :             74 :         PG_RETURN_BYTEA_P(result);
                                570                 :                :     }
                                571                 :                :     else
                                572                 :              3 :         PG_RETURN_NULL();
                                573                 :                : }
                                574                 :                : 
                                575                 :                : /*
                                576                 :                :  *      textin          - converts cstring to internal representation
                                577                 :                :  */
                                578                 :                : Datum
 8684 tgl@sss.pgh.pa.us         579                 :       10417599 : textin(PG_FUNCTION_ARGS)
                                580                 :                : {
                                581                 :       10417599 :     char       *inputText = PG_GETARG_CSTRING(0);
                                582                 :                : 
 5864                           583                 :       10417599 :     PG_RETURN_TEXT_P(cstring_to_text(inputText));
                                584                 :                : }
                                585                 :                : 
                                586                 :                : /*
                                587                 :                :  *      textout         - converts internal representation to cstring
                                588                 :                :  */
                                589                 :                : Datum
 8684                           590                 :        3570289 : textout(PG_FUNCTION_ARGS)
                                591                 :                : {
 5864                           592                 :        3570289 :     Datum       txt = PG_GETARG_DATUM(0);
                                593                 :                : 
                                594                 :        3570289 :     PG_RETURN_CSTRING(TextDatumGetCString(txt));
                                595                 :                : }
                                596                 :                : 
                                597                 :                : /*
                                598                 :                :  *      textrecv            - converts external binary format to text
                                599                 :                :  */
                                600                 :                : Datum
 7646                           601                 :             24 : textrecv(PG_FUNCTION_ARGS)
                                602                 :                : {
                                603                 :             24 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
                                604                 :                :     text       *result;
                                605                 :                :     char       *str;
                                606                 :                :     int         nbytes;
                                607                 :                : 
                                608                 :             24 :     str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
                                609                 :                : 
 5864                           610                 :             24 :     result = cstring_to_text_with_len(str, nbytes);
 7646                           611                 :             24 :     pfree(str);
                                612                 :             24 :     PG_RETURN_TEXT_P(result);
                                613                 :                : }
                                614                 :                : 
                                615                 :                : /*
                                616                 :                :  *      textsend            - converts text to binary format
                                617                 :                :  */
                                618                 :                : Datum
                                619                 :           2453 : textsend(PG_FUNCTION_ARGS)
                                620                 :                : {
 6218                           621                 :           2453 :     text       *t = PG_GETARG_TEXT_PP(0);
                                622                 :                :     StringInfoData buf;
                                623                 :                : 
 7646                           624                 :           2453 :     pq_begintypsend(&buf);
 6218                           625   [ -  +  -  -  :           2453 :     pq_sendtext(&buf, VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t));
                                     -  -  -  -  +  
                                           +  +  + ]
 7646                           626                 :           2453 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
                                627                 :                : }
                                628                 :                : 
                                629                 :                : 
                                630                 :                : /*
                                631                 :                :  *      unknownin           - converts cstring to internal representation
                                632                 :                :  */
                                633                 :                : Datum
 8026 bruce@momjian.us          634                 :UBC           0 : unknownin(PG_FUNCTION_ARGS)
                                635                 :                : {
 6894 tgl@sss.pgh.pa.us         636                 :              0 :     char       *str = PG_GETARG_CSTRING(0);
                                637                 :                : 
                                638                 :                :     /* representation is same as cstring */
                                639                 :              0 :     PG_RETURN_CSTRING(pstrdup(str));
                                640                 :                : }
                                641                 :                : 
                                642                 :                : /*
                                643                 :                :  *      unknownout          - converts internal representation to cstring
                                644                 :                :  */
                                645                 :                : Datum
 8026 bruce@momjian.us          646                 :CBC         340 : unknownout(PG_FUNCTION_ARGS)
                                647                 :                : {
                                648                 :                :     /* representation is same as cstring */
 6894 tgl@sss.pgh.pa.us         649                 :            340 :     char       *str = PG_GETARG_CSTRING(0);
                                650                 :                : 
                                651                 :            340 :     PG_RETURN_CSTRING(pstrdup(str));
                                652                 :                : }
                                653                 :                : 
                                654                 :                : /*
                                655                 :                :  *      unknownrecv         - converts external binary format to unknown
                                656                 :                :  */
                                657                 :                : Datum
 7646 tgl@sss.pgh.pa.us         658                 :UBC           0 : unknownrecv(PG_FUNCTION_ARGS)
                                659                 :                : {
                                660                 :              0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
                                661                 :                :     char       *str;
                                662                 :                :     int         nbytes;
                                663                 :                : 
 6894                           664                 :              0 :     str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
                                665                 :                :     /* representation is same as cstring */
                                666                 :              0 :     PG_RETURN_CSTRING(str);
                                667                 :                : }
                                668                 :                : 
                                669                 :                : /*
                                670                 :                :  *      unknownsend         - converts unknown to binary format
                                671                 :                :  */
                                672                 :                : Datum
 7646                           673                 :              0 : unknownsend(PG_FUNCTION_ARGS)
                                674                 :                : {
                                675                 :                :     /* representation is same as cstring */
 6894                           676                 :              0 :     char       *str = PG_GETARG_CSTRING(0);
                                677                 :                :     StringInfoData buf;
                                678                 :                : 
                                679                 :              0 :     pq_begintypsend(&buf);
                                680                 :              0 :     pq_sendtext(&buf, str, strlen(str));
                                681                 :              0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
                                682                 :                : }
                                683                 :                : 
                                684                 :                : 
                                685                 :                : /* ========== PUBLIC ROUTINES ========== */
                                686                 :                : 
                                687                 :                : /*
                                688                 :                :  * textlen -
                                689                 :                :  *    returns the logical length of a text*
                                690                 :                :  *     (which is less than the VARSIZE of the text*)
                                691                 :                :  */
                                692                 :                : Datum
 8683 tgl@sss.pgh.pa.us         693                 :CBC      215302 : textlen(PG_FUNCTION_ARGS)
                                694                 :                : {
 7379                           695                 :         215302 :     Datum       str = PG_GETARG_DATUM(0);
                                696                 :                : 
                                697                 :                :     /* try to avoid decompressing argument */
                                698                 :         215302 :     PG_RETURN_INT32(text_length(str));
                                699                 :                : }
                                700                 :                : 
                                701                 :                : /*
                                702                 :                :  * text_length -
                                703                 :                :  *  Does the real work for textlen()
                                704                 :                :  *
                                705                 :                :  *  This is broken out so it can be called directly by other string processing
                                706                 :                :  *  functions.  Note that the argument is passed as a Datum, to indicate that
                                707                 :                :  *  it may still be in compressed form.  We can avoid decompressing it at all
                                708                 :                :  *  in some cases.
                                709                 :                :  */
                                710                 :                : static int32
 7906 bruce@momjian.us          711                 :         215308 : text_length(Datum str)
                                712                 :                : {
                                713                 :                :     /* fastpath when max encoding length is one */
                                714         [ +  + ]:         215308 :     if (pg_database_encoding_max_length() == 1)
                                715                 :             10 :         PG_RETURN_INT32(toast_raw_datum_size(str) - VARHDRSZ);
                                716                 :                :     else
                                717                 :                :     {
 6218 tgl@sss.pgh.pa.us         718                 :         215298 :         text       *t = DatumGetTextPP(str);
                                719                 :                : 
 5995 bruce@momjian.us          720   [ -  +  -  -  :         215298 :         PG_RETURN_INT32(pg_mbstrlen_with_len(VARDATA_ANY(t),
                                     -  -  -  -  +  
                                           +  +  + ]
                                721                 :                :                                              VARSIZE_ANY_EXHDR(t)));
                                722                 :                :     }
                                723                 :                : }
                                724                 :                : 
                                725                 :                : /*
                                726                 :                :  * textoctetlen -
                                727                 :                :  *    returns the physical length of a text*
                                728                 :                :  *     (which is less than the VARSIZE of the text*)
                                729                 :                :  */
                                730                 :                : Datum
 8683 tgl@sss.pgh.pa.us         731                 :             35 : textoctetlen(PG_FUNCTION_ARGS)
                                732                 :                : {
 7379                           733                 :             35 :     Datum       str = PG_GETARG_DATUM(0);
                                734                 :                : 
                                735                 :                :     /* We need not detoast the input at all */
                                736                 :             35 :     PG_RETURN_INT32(toast_raw_datum_size(str) - VARHDRSZ);
                                737                 :                : }
                                738                 :                : 
                                739                 :                : /*
                                740                 :                :  * textcat -
                                741                 :                :  *    takes two text* and returns a text* that is the concatenation of
                                742                 :                :  *    the two.
                                743                 :                :  *
                                744                 :                :  * Rewritten by Sapa, sapa@hq.icb.chel.su. 8-Jul-96.
                                745                 :                :  * Updated by Thomas, Thomas.Lockhart@jpl.nasa.gov 1997-07-10.
                                746                 :                :  * Allocate space for output in all cases.
                                747                 :                :  * XXX - thomas 1997-07-10
                                748                 :                :  */
                                749                 :                : Datum
 8683                           750                 :         929881 : textcat(PG_FUNCTION_ARGS)
                                751                 :                : {
 6218                           752                 :         929881 :     text       *t1 = PG_GETARG_TEXT_PP(0);
                                753                 :         929881 :     text       *t2 = PG_GETARG_TEXT_PP(1);
                                754                 :                : 
 5193                           755                 :         929881 :     PG_RETURN_TEXT_P(text_catenate(t1, t2));
                                756                 :                : }
                                757                 :                : 
                                758                 :                : /*
                                759                 :                :  * text_catenate
                                760                 :                :  *  Guts of textcat(), broken out so it can be used by other functions
                                761                 :                :  *
                                762                 :                :  * Arguments can be in short-header form, but not compressed or out-of-line
                                763                 :                :  */
                                764                 :                : static text *
                                765                 :         929921 : text_catenate(text *t1, text *t2)
                                766                 :                : {
                                767                 :                :     text       *result;
                                768                 :                :     int         len1,
                                769                 :                :                 len2,
                                770                 :                :                 len;
                                771                 :                :     char       *ptr;
                                772                 :                : 
 6218                           773   [ -  +  -  -  :         929921 :     len1 = VARSIZE_ANY_EXHDR(t1);
                                     -  -  -  -  +  
                                                 + ]
 5193                           774   [ -  +  -  -  :         929921 :     len2 = VARSIZE_ANY_EXHDR(t2);
                                     -  -  -  -  +  
                                                 + ]
                                775                 :                : 
                                776                 :                :     /* paranoia ... probably should throw error instead? */
 9716 bruce@momjian.us          777         [ -  + ]:         929921 :     if (len1 < 0)
 9716 bruce@momjian.us          778                 :UBC           0 :         len1 = 0;
 9716 bruce@momjian.us          779         [ -  + ]:CBC      929921 :     if (len2 < 0)
 9716 bruce@momjian.us          780                 :UBC           0 :         len2 = 0;
                                781                 :                : 
 9472 lockhart@fourpalms.o      782                 :CBC      929921 :     len = len1 + len2 + VARHDRSZ;
 8683 tgl@sss.pgh.pa.us         783                 :         929921 :     result = (text *) palloc(len);
                                784                 :                : 
                                785                 :                :     /* Set size of result string... */
 6256                           786                 :         929921 :     SET_VARSIZE(result, len);
                                787                 :                : 
                                788                 :                :     /* Fill data field of result string... */
 9716 bruce@momjian.us          789                 :         929921 :     ptr = VARDATA(result);
 9472 lockhart@fourpalms.o      790         [ +  + ]:         929921 :     if (len1 > 0)
 6218 tgl@sss.pgh.pa.us         791         [ +  + ]:         928277 :         memcpy(ptr, VARDATA_ANY(t1), len1);
 9472 lockhart@fourpalms.o      792         [ +  + ]:         929921 :     if (len2 > 0)
 6218 tgl@sss.pgh.pa.us         793         [ +  + ]:         929816 :         memcpy(ptr + len1, VARDATA_ANY(t2), len2);
                                794                 :                : 
 5193                           795                 :         929921 :     return result;
                                796                 :                : }
                                797                 :                : 
                                798                 :                : /*
                                799                 :                :  * charlen_to_bytelen()
                                800                 :                :  *  Compute the number of bytes occupied by n characters starting at *p
                                801                 :                :  *
                                802                 :                :  * It is caller's responsibility that there actually are n characters;
                                803                 :                :  * the string need not be null-terminated.
                                804                 :                :  */
                                805                 :                : static int
 6367                           806                 :           6643 : charlen_to_bytelen(const char *p, int n)
                                807                 :                : {
                                808         [ +  + ]:           6643 :     if (pg_database_encoding_max_length() == 1)
                                809                 :                :     {
                                810                 :                :         /* Optimization for single-byte encodings */
 6367 tgl@sss.pgh.pa.us         811                 :GBC          84 :         return n;
                                812                 :                :     }
                                813                 :                :     else
                                814                 :                :     {
                                815                 :                :         const char *s;
                                816                 :                : 
 6367 tgl@sss.pgh.pa.us         817         [ +  + ]:CBC     2977411 :         for (s = p; n > 0; n--)
                                818                 :        2970852 :             s += pg_mblen(s);
                                819                 :                : 
                                820                 :           6559 :         return s - p;
                                821                 :                :     }
                                822                 :                : }
                                823                 :                : 
                                824                 :                : /*
                                825                 :                :  * text_substr()
                                826                 :                :  * Return a substring starting at the specified position.
                                827                 :                :  * - thomas 1997-12-31
                                828                 :                :  *
                                829                 :                :  * Input:
                                830                 :                :  *  - string
                                831                 :                :  *  - starting position (is one-based)
                                832                 :                :  *  - string length
                                833                 :                :  *
                                834                 :                :  * If the starting position is zero or less, then return from the start of the string
                                835                 :                :  *  adjusting the length to be consistent with the "negative start" per SQL.
                                836                 :                :  * If the length is less than zero, return the remaining string.
                                837                 :                :  *
                                838                 :                :  * Added multibyte support.
                                839                 :                :  * - Tatsuo Ishii 1998-4-21
                                840                 :                :  * Changed behavior if starting position is less than one to conform to SQL behavior.
                                841                 :                :  * Formerly returned the entire string; now returns a portion.
                                842                 :                :  * - Thomas Lockhart 1998-12-10
                                843                 :                :  * Now uses faster TOAST-slicing interface
                                844                 :                :  * - John Gray 2002-02-22
                                845                 :                :  * Remove "#ifdef MULTIBYTE" and test for encoding_max_length instead. Change
                                846                 :                :  * behaviors conflicting with SQL to meet SQL (if E = S + L < S throw
                                847                 :                :  * error; if E < 1, return '', not entire string). Fixed MB related bug when
                                848                 :                :  * S > LC and < LC + 4 sometimes garbage characters are returned.
                                849                 :                :  * - Joe Conway 2002-08-10
                                850                 :                :  */
                                851                 :                : Datum
 8706                           852                 :         293333 : text_substr(PG_FUNCTION_ARGS)
                                853                 :                : {
 7906 bruce@momjian.us          854                 :         293333 :     PG_RETURN_TEXT_P(text_substring(PG_GETARG_DATUM(0),
                                855                 :                :                                     PG_GETARG_INT32(1),
                                856                 :                :                                     PG_GETARG_INT32(2),
                                857                 :                :                                     false));
                                858                 :                : }
                                859                 :                : 
                                860                 :                : /*
                                861                 :                :  * text_substr_no_len -
                                862                 :                :  *    Wrapper to avoid opr_sanity failure due to
                                863                 :                :  *    one function accepting a different number of args.
                                864                 :                :  */
                                865                 :                : Datum
                                866                 :             24 : text_substr_no_len(PG_FUNCTION_ARGS)
                                867                 :                : {
                                868                 :             24 :     PG_RETURN_TEXT_P(text_substring(PG_GETARG_DATUM(0),
                                869                 :                :                                     PG_GETARG_INT32(1),
                                870                 :                :                                     -1, true));
                                871                 :                : }
                                872                 :                : 
                                873                 :                : /*
                                874                 :                :  * text_substring -
                                875                 :                :  *  Does the real work for text_substr() and text_substr_no_len()
                                876                 :                :  *
                                877                 :                :  *  This is broken out so it can be called directly by other string processing
                                878                 :                :  *  functions.  Note that the argument is passed as a Datum, to indicate that
                                879                 :                :  *  it may still be in compressed/toasted form.  We can avoid detoasting all
                                880                 :                :  *  of it in some cases.
                                881                 :                :  *
                                882                 :                :  *  The result is always a freshly palloc'd datum.
                                883                 :                :  */
                                884                 :                : static text *
                                885                 :         313281 : text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
                                886                 :                : {
                                887                 :         313281 :     int32       eml = pg_database_encoding_max_length();
 7893                           888                 :         313281 :     int32       S = start;      /* start position */
                                889                 :                :     int32       S1;             /* adjusted start position */
                                890                 :                :     int32       L1;             /* adjusted substring length */
                                891                 :                :     int32       E;              /* end position */
                                892                 :                : 
                                893                 :                :     /*
                                894                 :                :      * SQL99 says S can be zero or negative (which we don't document), but we
                                895                 :                :      * still must fetch from the start of the string.
                                896                 :                :      * https://www.postgresql.org/message-id/170905442373.643.11536838320909376197%40wrigleys.postgresql.org
                                897                 :                :      */
 1196 tgl@sss.pgh.pa.us         898                 :         313281 :     S1 = Max(S, 1);
                                899                 :                : 
                                900                 :                :     /* life is easy if the encoding max length is 1 */
 7906 bruce@momjian.us          901         [ +  + ]:         313281 :     if (eml == 1)
                                902                 :                :     {
 2489 tgl@sss.pgh.pa.us         903         [ -  + ]:             11 :         if (length_not_specified)   /* special case - get length to end of
                                904                 :                :                                      * string */
 7906 bruce@momjian.us          905                 :UBC           0 :             L1 = -1;
 1196 tgl@sss.pgh.pa.us         906         [ -  + ]:CBC          11 :         else if (length < 0)
                                907                 :                :         {
                                908                 :                :             /* SQL99 says to throw an error for E < S, i.e., negative length */
 1196 tgl@sss.pgh.pa.us         909         [ #  # ]:UBC           0 :             ereport(ERROR,
                                910                 :                :                     (errcode(ERRCODE_SUBSTRING_ERROR),
                                911                 :                :                      errmsg("negative substring length not allowed")));
                                912                 :                :             L1 = -1;            /* silence stupider compilers */
                                913                 :                :         }
 1196 tgl@sss.pgh.pa.us         914         [ -  + ]:CBC          11 :         else if (pg_add_s32_overflow(S, length, &E))
                                915                 :                :         {
                                916                 :                :             /*
                                917                 :                :              * L could be large enough for S + L to overflow, in which case
                                918                 :                :              * the substring must run to end of string.
                                919                 :                :              */
 1196 tgl@sss.pgh.pa.us         920                 :UBC           0 :             L1 = -1;
                                921                 :                :         }
                                922                 :                :         else
                                923                 :                :         {
                                924                 :                :             /*
                                925                 :                :              * A zero or negative value for the end position can happen if the
                                926                 :                :              * start was negative or one. SQL99 says to return a zero-length
                                927                 :                :              * string.
                                928                 :                :              */
 7906 bruce@momjian.us          929         [ -  + ]:CBC          11 :             if (E < 1)
 5864 tgl@sss.pgh.pa.us         930                 :UBC           0 :                 return cstring_to_text("");
                                931                 :                : 
 7906 bruce@momjian.us          932                 :CBC          11 :             L1 = E - S1;
                                933                 :                :         }
                                934                 :                : 
                                935                 :                :         /*
                                936                 :                :          * If the start position is past the end of the string, SQL99 says to
                                937                 :                :          * return a zero-length string -- DatumGetTextPSlice() will do that
                                938                 :                :          * for us.  We need only convert S1 to zero-based starting position.
                                939                 :                :          */
                                940                 :             11 :         return DatumGetTextPSlice(str, S1 - 1, L1);
                                941                 :                :     }
                                942         [ +  - ]:         313270 :     else if (eml > 1)
                                943                 :                :     {
                                944                 :                :         /*
                                945                 :                :          * When encoding max length is > 1, we can't get LC without
                                946                 :                :          * detoasting, so we'll grab a conservatively large slice now and go
                                947                 :                :          * back later to do the right thing
                                948                 :                :          */
                                949                 :                :         int32       slice_start;
                                950                 :                :         int32       slice_size;
                                951                 :                :         int32       slice_strlen;
                                952                 :                :         text       *slice;
                                953                 :                :         int32       E1;
                                954                 :                :         int32       i;
                                955                 :                :         char       *p;
                                956                 :                :         char       *s;
                                957                 :                :         text       *ret;
                                958                 :                : 
                                959                 :                :         /*
                                960                 :                :          * We need to start at position zero because there is no way to know
                                961                 :                :          * in advance which byte offset corresponds to the supplied start
                                962                 :                :          * position.
                                963                 :                :          */
                                964                 :         313270 :         slice_start = 0;
                                965                 :                : 
 2489 tgl@sss.pgh.pa.us         966         [ +  + ]:         313270 :         if (length_not_specified)   /* special case - get length to end of
                                967                 :                :                                      * string */
 7906 bruce@momjian.us          968                 :             44 :             slice_size = L1 = -1;
 1196 tgl@sss.pgh.pa.us         969         [ +  + ]:         313226 :         else if (length < 0)
                                970                 :                :         {
                                971                 :                :             /* SQL99 says to throw an error for E < S, i.e., negative length */
                                972         [ +  - ]:              6 :             ereport(ERROR,
                                973                 :                :                     (errcode(ERRCODE_SUBSTRING_ERROR),
                                974                 :                :                      errmsg("negative substring length not allowed")));
                                975                 :                :             slice_size = L1 = -1;   /* silence stupider compilers */
                                976                 :                :         }
                                977         [ +  + ]:         313220 :         else if (pg_add_s32_overflow(S, length, &E))
                                978                 :                :         {
                                979                 :                :             /*
                                980                 :                :              * L could be large enough for S + L to overflow, in which case
                                981                 :                :              * the substring must run to end of string.
                                982                 :                :              */
                                983                 :              3 :             slice_size = L1 = -1;
                                984                 :                :         }
                                985                 :                :         else
                                986                 :                :         {
                                987                 :                :             /*
                                988                 :                :              * A zero or negative value for the end position can happen if the
                                989                 :                :              * start was negative or one. SQL99 says to return a zero-length
                                990                 :                :              * string.
                                991                 :                :              */
 7906 bruce@momjian.us          992         [ -  + ]:         313217 :             if (E < 1)
 5864 tgl@sss.pgh.pa.us         993                 :UBC           0 :                 return cstring_to_text("");
                                994                 :                : 
                                995                 :                :             /*
                                996                 :                :              * if E is past the end of the string, the tuple toaster will
                                997                 :                :              * truncate the length for us
                                998                 :                :              */
 7906 bruce@momjian.us          999                 :CBC      313217 :             L1 = E - S1;
                               1000                 :                : 
                               1001                 :                :             /*
                               1002                 :                :              * Total slice size in bytes can't be any longer than the start
                               1003                 :                :              * position plus substring length times the encoding max length.
                               1004                 :                :              * If that overflows, we can just use -1.
                               1005                 :                :              */
 1196 tgl@sss.pgh.pa.us        1006         [ +  + ]:         313217 :             if (pg_mul_s32_overflow(E, eml, &slice_size))
                               1007                 :              3 :                 slice_size = -1;
                               1008                 :                :         }
                               1009                 :                : 
                               1010                 :                :         /*
                               1011                 :                :          * If we're working with an untoasted source, no need to do an extra
                               1012                 :                :          * copying step.
                               1013                 :                :          */
 5698                          1014         [ +  + ]:         313264 :         if (VARATT_IS_COMPRESSED(DatumGetPointer(str)) ||
 5846                          1015         [ +  + ]:         313237 :             VARATT_IS_EXTERNAL(DatumGetPointer(str)))
 6367                          1016                 :            162 :             slice = DatumGetTextPSlice(str, slice_start, slice_size);
                               1017                 :                :         else
                               1018                 :         313102 :             slice = (text *) DatumGetPointer(str);
                               1019                 :                : 
                               1020                 :                :         /* see if we got back an empty string */
 6049                          1021   [ -  +  -  -  :         313264 :         if (VARSIZE_ANY_EXHDR(slice) == 0)
                                     -  -  -  -  +  
                                           +  -  + ]
                               1022                 :                :         {
 6367 tgl@sss.pgh.pa.us        1023         [ #  # ]:UBC           0 :             if (slice != (text *) DatumGetPointer(str))
                               1024                 :              0 :                 pfree(slice);
 5864                          1025                 :              0 :             return cstring_to_text("");
                               1026                 :                :         }
                               1027                 :                : 
                               1028                 :                :         /* Now we can get the actual length of the slice in MB characters */
 6049 tgl@sss.pgh.pa.us        1029         [ +  + ]:CBC      313264 :         slice_strlen = pg_mbstrlen_with_len(VARDATA_ANY(slice),
                               1030   [ -  +  -  -  :         313264 :                                             VARSIZE_ANY_EXHDR(slice));
                                     -  -  -  -  +  
                                                 + ]
                               1031                 :                : 
                               1032                 :                :         /*
                               1033                 :                :          * Check that the start position wasn't > slice_strlen. If so, SQL99
                               1034                 :                :          * says to return a zero-length string.
                               1035                 :                :          */
 7906 bruce@momjian.us         1036         [ +  + ]:         313264 :         if (S1 > slice_strlen)
                               1037                 :                :         {
 6367 tgl@sss.pgh.pa.us        1038         [ -  + ]:             11 :             if (slice != (text *) DatumGetPointer(str))
 6367 tgl@sss.pgh.pa.us        1039                 :UBC           0 :                 pfree(slice);
 5864 tgl@sss.pgh.pa.us        1040                 :CBC          11 :             return cstring_to_text("");
                               1041                 :                :         }
                               1042                 :                : 
                               1043                 :                :         /*
                               1044                 :                :          * Adjust L1 and E1 now that we know the slice string length. Again
                               1045                 :                :          * remember that S1 is one based, and slice_start is zero based.
                               1046                 :                :          */
 7906 bruce@momjian.us         1047         [ +  + ]:         313253 :         if (L1 > -1)
 7893                          1048                 :         313217 :             E1 = Min(S1 + L1, slice_start + 1 + slice_strlen);
                               1049                 :                :         else
 7906                          1050                 :             36 :             E1 = slice_start + 1 + slice_strlen;
                               1051                 :                : 
                               1052                 :                :         /*
                               1053                 :                :          * Find the start position in the slice; remember S1 is not zero based
                               1054                 :                :          */
 6049 tgl@sss.pgh.pa.us        1055         [ +  + ]:         313253 :         p = VARDATA_ANY(slice);
 7906 bruce@momjian.us         1056         [ +  + ]:        2724127 :         for (i = 0; i < S1 - 1; i++)
                               1057                 :        2410874 :             p += pg_mblen(p);
                               1058                 :                : 
                               1059                 :                :         /* hang onto a pointer to our start position */
                               1060                 :         313253 :         s = p;
                               1061                 :                : 
                               1062                 :                :         /*
                               1063                 :                :          * Count the actual bytes used by the substring of the requested
                               1064                 :                :          * length.
                               1065                 :                :          */
                               1066         [ +  + ]:        4888344 :         for (i = S1; i < E1; i++)
                               1067                 :        4575091 :             p += pg_mblen(p);
                               1068                 :                : 
                               1069                 :         313253 :         ret = (text *) palloc(VARHDRSZ + (p - s));
 6256 tgl@sss.pgh.pa.us        1070                 :         313253 :         SET_VARSIZE(ret, VARHDRSZ + (p - s));
 7906 bruce@momjian.us         1071                 :         313253 :         memcpy(VARDATA(ret), s, (p - s));
                               1072                 :                : 
 6367 tgl@sss.pgh.pa.us        1073         [ +  + ]:         313253 :         if (slice != (text *) DatumGetPointer(str))
                               1074                 :            162 :             pfree(slice);
                               1075                 :                : 
 7906 bruce@momjian.us         1076                 :         313253 :         return ret;
                               1077                 :                :     }
                               1078                 :                :     else
 7567 tgl@sss.pgh.pa.us        1079         [ #  # ]:UBC           0 :         elog(ERROR, "invalid backend encoding: encoding max length < 1");
                               1080                 :                : 
                               1081                 :                :     /* not reached: suppress compiler warning */
                               1082                 :                :     return NULL;
                               1083                 :                : }
                               1084                 :                : 
                               1085                 :                : /*
                               1086                 :                :  * textoverlay
                               1087                 :                :  *  Replace specified substring of first string with second
                               1088                 :                :  *
                               1089                 :                :  * The SQL standard defines OVERLAY() in terms of substring and concatenation.
                               1090                 :                :  * This code is a direct implementation of what the standard says.
                               1091                 :                :  */
                               1092                 :                : Datum
 5193 tgl@sss.pgh.pa.us        1093                 :CBC          14 : textoverlay(PG_FUNCTION_ARGS)
                               1094                 :                : {
                               1095                 :             14 :     text       *t1 = PG_GETARG_TEXT_PP(0);
                               1096                 :             14 :     text       *t2 = PG_GETARG_TEXT_PP(1);
 2489                          1097                 :             14 :     int         sp = PG_GETARG_INT32(2);    /* substring start position */
                               1098                 :             14 :     int         sl = PG_GETARG_INT32(3);    /* substring length */
                               1099                 :                : 
 5193                          1100                 :             14 :     PG_RETURN_TEXT_P(text_overlay(t1, t2, sp, sl));
                               1101                 :                : }
                               1102                 :                : 
                               1103                 :                : Datum
                               1104                 :              6 : textoverlay_no_len(PG_FUNCTION_ARGS)
                               1105                 :                : {
                               1106                 :              6 :     text       *t1 = PG_GETARG_TEXT_PP(0);
                               1107                 :              6 :     text       *t2 = PG_GETARG_TEXT_PP(1);
 2489                          1108                 :              6 :     int         sp = PG_GETARG_INT32(2);    /* substring start position */
                               1109                 :                :     int         sl;
                               1110                 :                : 
                               1111                 :              6 :     sl = text_length(PointerGetDatum(t2));  /* defaults to length(t2) */
 5193                          1112                 :              6 :     PG_RETURN_TEXT_P(text_overlay(t1, t2, sp, sl));
                               1113                 :                : }
                               1114                 :                : 
                               1115                 :                : static text *
                               1116                 :             20 : text_overlay(text *t1, text *t2, int sp, int sl)
                               1117                 :                : {
                               1118                 :                :     text       *result;
                               1119                 :                :     text       *s1;
                               1120                 :                :     text       *s2;
                               1121                 :                :     int         sp_pl_sl;
                               1122                 :                : 
                               1123                 :                :     /*
                               1124                 :                :      * Check for possible integer-overflow cases.  For negative sp, throw a
                               1125                 :                :      * "substring length" error because that's what should be expected
                               1126                 :                :      * according to the spec's definition of OVERLAY().
                               1127                 :                :      */
                               1128         [ -  + ]:             20 :     if (sp <= 0)
 5193 tgl@sss.pgh.pa.us        1129         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1130                 :                :                 (errcode(ERRCODE_SUBSTRING_ERROR),
                               1131                 :                :                  errmsg("negative substring length not allowed")));
 2315 andres@anarazel.de       1132         [ -  + ]:CBC          20 :     if (pg_add_s32_overflow(sp, sl, &sp_pl_sl))
 5193 tgl@sss.pgh.pa.us        1133         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1134                 :                :                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                               1135                 :                :                  errmsg("integer out of range")));
                               1136                 :                : 
 5161 bruce@momjian.us         1137                 :CBC          20 :     s1 = text_substring(PointerGetDatum(t1), 1, sp - 1, false);
 5193 tgl@sss.pgh.pa.us        1138                 :             20 :     s2 = text_substring(PointerGetDatum(t1), sp_pl_sl, -1, true);
                               1139                 :             20 :     result = text_catenate(s1, t2);
                               1140                 :             20 :     result = text_catenate(result, s2);
                               1141                 :                : 
                               1142                 :             20 :     return result;
                               1143                 :                : }
                               1144                 :                : 
                               1145                 :                : /*
                               1146                 :                :  * textpos -
                               1147                 :                :  *    Return the position of the specified substring.
                               1148                 :                :  *    Implements the SQL POSITION() function.
                               1149                 :                :  *    Ref: A Guide To The SQL Standard, Date & Darwen, 1997
                               1150                 :                :  * - thomas 1997-07-27
                               1151                 :                :  */
                               1152                 :                : Datum
 8683                          1153                 :             53 : textpos(PG_FUNCTION_ARGS)
                               1154                 :                : {
 6049                          1155                 :             53 :     text       *str = PG_GETARG_TEXT_PP(0);
                               1156                 :             53 :     text       *search_str = PG_GETARG_TEXT_PP(1);
                               1157                 :                : 
 1850 peter@eisentraut.org     1158                 :             53 :     PG_RETURN_INT32((int32) text_position(str, search_str, PG_GET_COLLATION()));
                               1159                 :                : }
                               1160                 :                : 
                               1161                 :                : /*
                               1162                 :                :  * text_position -
                               1163                 :                :  *  Does the real work for textpos()
                               1164                 :                :  *
                               1165                 :                :  * Inputs:
                               1166                 :                :  *      t1 - string to be searched
                               1167                 :                :  *      t2 - pattern to match within t1
                               1168                 :                :  * Result:
                               1169                 :                :  *      Character index of the first matched char, starting from 1,
                               1170                 :                :  *      or 0 if no match.
                               1171                 :                :  *
                               1172                 :                :  *  This is broken out so it can be called directly by other string processing
                               1173                 :                :  *  functions.
                               1174                 :                :  */
                               1175                 :                : static int
                               1176                 :             53 : text_position(text *t1, text *t2, Oid collid)
                               1177                 :                : {
                               1178                 :                :     TextPositionState state;
                               1179                 :                :     int         result;
                               1180                 :                : 
                               1181                 :                :     /* Empty needle always matches at position 1 */
 1630 tgl@sss.pgh.pa.us        1182   [ -  +  -  -  :             53 :     if (VARSIZE_ANY_EXHDR(t2) < 1)
                                     -  -  -  -  -  
                                           +  +  + ]
                               1183                 :              6 :         return 1;
                               1184                 :                : 
                               1185                 :                :     /* Otherwise, can't match if haystack is shorter than needle */
                               1186   [ -  +  -  -  :             47 :     if (VARSIZE_ANY_EXHDR(t1) < VARSIZE_ANY_EXHDR(t2))
                                     -  -  -  -  +  
                                     +  -  +  -  -  
                                     -  -  -  -  -  
                                           +  +  + ]
 1906 heikki.linnakangas@i     1187                 :             11 :         return 0;
                               1188                 :                : 
 1850 peter@eisentraut.org     1189                 :             36 :     text_position_setup(t1, t2, collid, &state);
 1906 heikki.linnakangas@i     1190         [ +  + ]:             36 :     if (!text_position_next(&state))
                               1191                 :             12 :         result = 0;
                               1192                 :                :     else
                               1193                 :             24 :         result = text_position_get_match_pos(&state);
 6399 tgl@sss.pgh.pa.us        1194                 :             36 :     text_position_cleanup(&state);
                               1195                 :             36 :     return result;
                               1196                 :                : }
                               1197                 :                : 
                               1198                 :                : 
                               1199                 :                : /*
                               1200                 :                :  * text_position_setup, text_position_next, text_position_cleanup -
                               1201                 :                :  *  Component steps of text_position()
                               1202                 :                :  *
                               1203                 :                :  * These are broken out so that a string can be efficiently searched for
                               1204                 :                :  * multiple occurrences of the same pattern.  text_position_next may be
                               1205                 :                :  * called multiple times, and it advances to the next match on each call.
                               1206                 :                :  * text_position_get_match_ptr() and text_position_get_match_pos() return
                               1207                 :                :  * a pointer or 1-based character position of the last match, respectively.
                               1208                 :                :  *
                               1209                 :                :  * The "state" variable is normally just a local variable in the caller.
                               1210                 :                :  *
                               1211                 :                :  * NOTE: text_position_next skips over the matched portion.  For example,
                               1212                 :                :  * searching for "xx" in "xxx" returns only one match, not two.
                               1213                 :                :  */
                               1214                 :                : 
                               1215                 :                : static void
 1850 peter@eisentraut.org     1216                 :            664 : text_position_setup(text *t1, text *t2, Oid collid, TextPositionState *state)
                               1217                 :                : {
 6049 tgl@sss.pgh.pa.us        1218   [ -  +  -  -  :            664 :     int         len1 = VARSIZE_ANY_EXHDR(t1);
                                     -  -  -  -  +  
                                                 + ]
                               1219   [ -  +  -  -  :            664 :     int         len2 = VARSIZE_ANY_EXHDR(t2);
                                     -  -  -  -  -  
                                                 + ]
 1789                          1220                 :            664 :     pg_locale_t mylocale = 0;
                               1221                 :                : 
 1850 peter@eisentraut.org     1222                 :            664 :     check_collation_set(collid);
                               1223                 :                : 
  815                          1224         [ +  + ]:            664 :     if (!lc_collate_is_c(collid))
 1850                          1225                 :            105 :         mylocale = pg_newlocale_from_collation(collid);
                               1226                 :                : 
  416 jdavis@postgresql.or     1227         [ +  + ]:            664 :     if (!pg_locale_deterministic(mylocale))
 1850 peter@eisentraut.org     1228         [ +  - ]:              6 :         ereport(ERROR,
                               1229                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1230                 :                :                  errmsg("nondeterministic collations are not supported for substring searches")));
                               1231                 :                : 
 1906 heikki.linnakangas@i     1232         [ -  + ]:            658 :     Assert(len1 > 0);
                               1233         [ -  + ]:            658 :     Assert(len2 > 0);
                               1234                 :                : 
                               1235                 :                :     /*
                               1236                 :                :      * Even with a multi-byte encoding, we perform the search using the raw
                               1237                 :                :      * byte sequence, ignoring multibyte issues.  For UTF-8, that works fine,
                               1238                 :                :      * because in UTF-8 the byte sequence of one character cannot contain
                               1239                 :                :      * another character.  For other multi-byte encodings, we do the search
                               1240                 :                :      * initially as a simple byte search, ignoring multibyte issues, but
                               1241                 :                :      * verify afterwards that the match we found is at a character boundary,
                               1242                 :                :      * and continue the search if it was a false match.
                               1243                 :                :      */
 7379 tgl@sss.pgh.pa.us        1244         [ +  + ]:            658 :     if (pg_database_encoding_max_length() == 1)
 1906 heikki.linnakangas@i     1245                 :             52 :         state->is_multibyte_char_in_char = false;
                               1246         [ +  - ]:            606 :     else if (GetDatabaseEncoding() == PG_UTF8)
                               1247                 :            606 :         state->is_multibyte_char_in_char = false;
                               1248                 :                :     else
 1906 heikki.linnakangas@i     1249                 :UBC           0 :         state->is_multibyte_char_in_char = true;
                               1250                 :                : 
 1906 heikki.linnakangas@i     1251         [ +  + ]:CBC         658 :     state->str1 = VARDATA_ANY(t1);
                               1252         [ -  + ]:            658 :     state->str2 = VARDATA_ANY(t2);
                               1253                 :            658 :     state->len1 = len1;
                               1254                 :            658 :     state->len2 = len2;
                               1255                 :            658 :     state->last_match = NULL;
                               1256                 :            658 :     state->refpoint = state->str1;
                               1257                 :            658 :     state->refpos = 0;
                               1258                 :                : 
                               1259                 :                :     /*
                               1260                 :                :      * Prepare the skip table for Boyer-Moore-Horspool searching.  In these
                               1261                 :                :      * notes we use the terminology that the "haystack" is the string to be
                               1262                 :                :      * searched (t1) and the "needle" is the pattern being sought (t2).
                               1263                 :                :      *
                               1264                 :                :      * If the needle is empty or bigger than the haystack then there is no
                               1265                 :                :      * point in wasting cycles initializing the table.  We also choose not to
                               1266                 :                :      * use B-M-H for needles of length 1, since the skip table can't possibly
                               1267                 :                :      * save anything in that case.
                               1268                 :                :      */
 5698 tgl@sss.pgh.pa.us        1269   [ +  -  +  + ]:            658 :     if (len1 >= len2 && len2 > 1)
                               1270                 :                :     {
 5421 bruce@momjian.us         1271                 :            554 :         int         searchlength = len1 - len2;
                               1272                 :                :         int         skiptablemask;
                               1273                 :                :         int         last;
                               1274                 :                :         int         i;
 1906 heikki.linnakangas@i     1275                 :            554 :         const char *str2 = state->str2;
                               1276                 :                : 
                               1277                 :                :         /*
                               1278                 :                :          * First we must determine how much of the skip table to use.  The
                               1279                 :                :          * declaration of TextPositionState allows up to 256 elements, but for
                               1280                 :                :          * short search problems we don't really want to have to initialize so
                               1281                 :                :          * many elements --- it would take too long in comparison to the
                               1282                 :                :          * actual search time.  So we choose a useful skip table size based on
                               1283                 :                :          * the haystack length minus the needle length.  The closer the needle
                               1284                 :                :          * length is to the haystack length the less useful skipping becomes.
                               1285                 :                :          *
                               1286                 :                :          * Note: since we use bit-masking to select table elements, the skip
                               1287                 :                :          * table size MUST be a power of 2, and so the mask must be 2^N-1.
                               1288                 :                :          */
 5698 tgl@sss.pgh.pa.us        1289         [ +  + ]:            554 :         if (searchlength < 16)
                               1290                 :             27 :             skiptablemask = 3;
                               1291         [ +  + ]:            527 :         else if (searchlength < 64)
                               1292                 :              8 :             skiptablemask = 7;
                               1293         [ +  + ]:            519 :         else if (searchlength < 128)
                               1294                 :              7 :             skiptablemask = 15;
                               1295         [ +  + ]:            512 :         else if (searchlength < 512)
                               1296                 :            105 :             skiptablemask = 31;
                               1297         [ +  + ]:            407 :         else if (searchlength < 2048)
                               1298                 :            334 :             skiptablemask = 63;
                               1299         [ +  + ]:             73 :         else if (searchlength < 4096)
                               1300                 :             37 :             skiptablemask = 127;
                               1301                 :                :         else
                               1302                 :             36 :             skiptablemask = 255;
                               1303                 :            554 :         state->skiptablemask = skiptablemask;
                               1304                 :                : 
                               1305                 :                :         /*
                               1306                 :                :          * Initialize the skip table.  We set all elements to the needle
                               1307                 :                :          * length, since this is the correct skip distance for any character
                               1308                 :                :          * not found in the needle.
                               1309                 :                :          */
                               1310         [ +  + ]:          39526 :         for (i = 0; i <= skiptablemask; i++)
                               1311                 :          38972 :             state->skiptable[i] = len2;
                               1312                 :                : 
                               1313                 :                :         /*
                               1314                 :                :          * Now examine the needle.  For each character except the last one,
                               1315                 :                :          * set the corresponding table element to the appropriate skip
                               1316                 :                :          * distance.  Note that when two characters share the same skip table
                               1317                 :                :          * entry, the one later in the needle must determine the skip
                               1318                 :                :          * distance.
                               1319                 :                :          */
                               1320                 :            554 :         last = len2 - 1;
                               1321                 :                : 
 1906 heikki.linnakangas@i     1322         [ +  + ]:           7567 :         for (i = 0; i < last; i++)
                               1323                 :           7013 :             state->skiptable[(unsigned char) str2[i] & skiptablemask] = last - i;
                               1324                 :                :     }
 6399 tgl@sss.pgh.pa.us        1325                 :            658 : }
                               1326                 :                : 
                               1327                 :                : /*
                               1328                 :                :  * Advance to the next match, starting from the end of the previous match
                               1329                 :                :  * (or the beginning of the string, on first call).  Returns true if a match
                               1330                 :                :  * is found.
                               1331                 :                :  *
                               1332                 :                :  * Note that this refuses to match an empty-string needle.  Most callers
                               1333                 :                :  * will have handled that case specially and we'll never see it here.
                               1334                 :                :  */
                               1335                 :                : static bool
 1906 heikki.linnakangas@i     1336                 :           3178 : text_position_next(TextPositionState *state)
                               1337                 :                : {
 5698 tgl@sss.pgh.pa.us        1338                 :           3178 :     int         needle_len = state->len2;
                               1339                 :                :     char       *start_ptr;
                               1340                 :                :     char       *matchptr;
                               1341                 :                : 
                               1342         [ -  + ]:           3178 :     if (needle_len <= 0)
 1906 heikki.linnakangas@i     1343                 :UBC           0 :         return false;           /* result for empty pattern */
                               1344                 :                : 
                               1345                 :                :     /* Start from the point right after the previous match. */
 1906 heikki.linnakangas@i     1346         [ +  + ]:CBC        3178 :     if (state->last_match)
                               1347                 :           2514 :         start_ptr = state->last_match + needle_len;
                               1348                 :                :     else
                               1349                 :            664 :         start_ptr = state->str1;
                               1350                 :                : 
                               1351                 :           3178 : retry:
                               1352                 :           3178 :     matchptr = text_position_next_internal(start_ptr, state);
                               1353                 :                : 
                               1354         [ +  + ]:           3178 :     if (!matchptr)
                               1355                 :            628 :         return false;
                               1356                 :                : 
                               1357                 :                :     /*
                               1358                 :                :      * Found a match for the byte sequence.  If this is a multibyte encoding,
                               1359                 :                :      * where one character's byte sequence can appear inside a longer
                               1360                 :                :      * multi-byte character, we need to verify that the match was at a
                               1361                 :                :      * character boundary, not in the middle of a multi-byte character.
                               1362                 :                :      */
                               1363         [ -  + ]:           2550 :     if (state->is_multibyte_char_in_char)
                               1364                 :                :     {
                               1365                 :                :         /* Walk one character at a time, until we reach the match. */
                               1366                 :                : 
                               1367                 :                :         /* the search should never move backwards. */
 1906 heikki.linnakangas@i     1368         [ #  # ]:UBC           0 :         Assert(state->refpoint <= matchptr);
                               1369                 :                : 
                               1370         [ #  # ]:              0 :         while (state->refpoint < matchptr)
                               1371                 :                :         {
                               1372                 :                :             /* step to next character. */
                               1373                 :              0 :             state->refpoint += pg_mblen(state->refpoint);
                               1374                 :              0 :             state->refpos++;
                               1375                 :                : 
                               1376                 :                :             /*
                               1377                 :                :              * If we stepped over the match's start position, then it was a
                               1378                 :                :              * false positive, where the byte sequence appeared in the middle
                               1379                 :                :              * of a multi-byte character.  Skip it, and continue the search at
                               1380                 :                :              * the next character boundary.
                               1381                 :                :              */
                               1382         [ #  # ]:              0 :             if (state->refpoint > matchptr)
                               1383                 :                :             {
                               1384                 :              0 :                 start_ptr = state->refpoint;
                               1385                 :              0 :                 goto retry;
                               1386                 :                :             }
                               1387                 :                :         }
                               1388                 :                :     }
                               1389                 :                : 
 1906 heikki.linnakangas@i     1390                 :CBC        2550 :     state->last_match = matchptr;
                               1391                 :           2550 :     return true;
                               1392                 :                : }
                               1393                 :                : 
                               1394                 :                : /*
                               1395                 :                :  * Subroutine of text_position_next().  This searches for the raw byte
                               1396                 :                :  * sequence, ignoring any multi-byte encoding issues.  Returns the first
                               1397                 :                :  * match starting at 'start_ptr', or NULL if no match is found.
                               1398                 :                :  */
                               1399                 :                : static char *
                               1400                 :           3178 : text_position_next_internal(char *start_ptr, TextPositionState *state)
                               1401                 :                : {
                               1402                 :           3178 :     int         haystack_len = state->len1;
                               1403                 :           3178 :     int         needle_len = state->len2;
                               1404                 :           3178 :     int         skiptablemask = state->skiptablemask;
                               1405                 :           3178 :     const char *haystack = state->str1;
                               1406                 :           3178 :     const char *needle = state->str2;
                               1407                 :           3178 :     const char *haystack_end = &haystack[haystack_len];
                               1408                 :                :     const char *hptr;
                               1409                 :                : 
                               1410   [ +  -  -  + ]:           3178 :     Assert(start_ptr >= haystack && start_ptr <= haystack_end);
                               1411                 :                : 
                               1412         [ +  + ]:           3178 :     if (needle_len == 1)
                               1413                 :                :     {
                               1414                 :                :         /* No point in using B-M-H for a one-character needle */
                               1415                 :            377 :         char        nchar = *needle;
                               1416                 :                : 
                               1417                 :            377 :         hptr = start_ptr;
                               1418         [ +  + ]:           2877 :         while (hptr < haystack_end)
                               1419                 :                :         {
                               1420         [ +  + ]:           2794 :             if (*hptr == nchar)
                               1421                 :            294 :                 return (char *) hptr;
                               1422                 :           2500 :             hptr++;
                               1423                 :                :         }
                               1424                 :                :     }
                               1425                 :                :     else
                               1426                 :                :     {
                               1427                 :           2801 :         const char *needle_last = &needle[needle_len - 1];
                               1428                 :                : 
                               1429                 :                :         /* Start at startpos plus the length of the needle */
                               1430                 :           2801 :         hptr = start_ptr + needle_len - 1;
                               1431         [ +  + ]:          72569 :         while (hptr < haystack_end)
                               1432                 :                :         {
                               1433                 :                :             /* Match the needle scanning *backward* */
                               1434                 :                :             const char *nptr;
                               1435                 :                :             const char *p;
                               1436                 :                : 
                               1437                 :          72024 :             nptr = needle_last;
                               1438                 :          72024 :             p = hptr;
                               1439         [ +  + ]:         105860 :             while (*nptr == *p)
                               1440                 :                :             {
                               1441                 :                :                 /* Matched it all?  If so, return 1-based position */
                               1442         [ +  + ]:          36092 :                 if (nptr == needle)
                               1443                 :           2256 :                     return (char *) p;
                               1444                 :          33836 :                 nptr--, p--;
                               1445                 :                :             }
                               1446                 :                : 
                               1447                 :                :             /*
                               1448                 :                :              * No match, so use the haystack char at hptr to decide how far to
                               1449                 :                :              * advance.  If the needle had any occurrence of that character
                               1450                 :                :              * (or more precisely, one sharing the same skiptable entry)
                               1451                 :                :              * before its last character, then we advance far enough to align
                               1452                 :                :              * the last such needle character with that haystack position.
                               1453                 :                :              * Otherwise we can advance by the whole needle length.
                               1454                 :                :              */
                               1455                 :          69768 :             hptr += state->skiptable[(unsigned char) *hptr & skiptablemask];
                               1456                 :                :         }
                               1457                 :                :     }
                               1458                 :                : 
                               1459                 :            628 :     return 0;                   /* not found */
                               1460                 :                : }
                               1461                 :                : 
                               1462                 :                : /*
                               1463                 :                :  * Return a pointer to the current match.
                               1464                 :                :  *
                               1465                 :                :  * The returned pointer points into the original haystack string.
                               1466                 :                :  */
                               1467                 :                : static char *
                               1468                 :           2511 : text_position_get_match_ptr(TextPositionState *state)
                               1469                 :                : {
                               1470                 :           2511 :     return state->last_match;
                               1471                 :                : }
                               1472                 :                : 
                               1473                 :                : /*
                               1474                 :                :  * Return the offset of the current match.
                               1475                 :                :  *
                               1476                 :                :  * The offset is in characters, 1-based.
                               1477                 :                :  */
                               1478                 :                : static int
                               1479                 :             24 : text_position_get_match_pos(TextPositionState *state)
                               1480                 :                : {
                               1481                 :                :     /* Convert the byte position to char position. */
  849 john.naylor@postgres     1482                 :             48 :     state->refpos += pg_mbstrlen_with_len(state->refpoint,
                               1483                 :             24 :                                           state->last_match - state->refpoint);
                               1484                 :             24 :     state->refpoint = state->last_match;
                               1485                 :             24 :     return state->refpos + 1;
                               1486                 :                : }
                               1487                 :                : 
                               1488                 :                : /*
                               1489                 :                :  * Reset search state to the initial state installed by text_position_setup.
                               1490                 :                :  *
                               1491                 :                :  * The next call to text_position_next will search from the beginning
                               1492                 :                :  * of the string.
                               1493                 :                :  */
                               1494                 :                : static void
 1248 tgl@sss.pgh.pa.us        1495                 :              6 : text_position_reset(TextPositionState *state)
                               1496                 :                : {
                               1497                 :              6 :     state->last_match = NULL;
                               1498                 :              6 :     state->refpoint = state->str1;
                               1499                 :              6 :     state->refpos = 0;
                               1500                 :              6 : }
                               1501                 :                : 
                               1502                 :                : static void
 5995 bruce@momjian.us         1503                 :            658 : text_position_cleanup(TextPositionState *state)
                               1504                 :                : {
                               1505                 :                :     /* no cleanup needed */
 6399 tgl@sss.pgh.pa.us        1506                 :            658 : }
                               1507                 :                : 
                               1508                 :                : 
                               1509                 :                : static void
 1850 peter@eisentraut.org     1510                 :        6643733 : check_collation_set(Oid collid)
                               1511                 :                : {
                               1512         [ +  + ]:        6643733 :     if (!OidIsValid(collid))
                               1513                 :                :     {
                               1514                 :                :         /*
                               1515                 :                :          * This typically means that the parser could not resolve a conflict
                               1516                 :                :          * of implicit collations, so report it that way.
                               1517                 :                :          */
                               1518         [ +  - ]:             15 :         ereport(ERROR,
                               1519                 :                :                 (errcode(ERRCODE_INDETERMINATE_COLLATION),
                               1520                 :                :                  errmsg("could not determine which collation to use for string comparison"),
                               1521                 :                :                  errhint("Use the COLLATE clause to set the collation explicitly.")));
                               1522                 :                :     }
                               1523                 :        6643718 : }
                               1524                 :                : 
                               1525                 :                : /* varstr_cmp()
                               1526                 :                :  * Comparison function for text strings with given lengths.
                               1527                 :                :  * Includes locale support, but must copy strings to temporary memory
                               1528                 :                :  *  to allow null-termination for inputs to strcoll().
                               1529                 :                :  * Returns an integer less than, equal to, or greater than zero, indicating
                               1530                 :                :  * whether arg1 is less than, equal to, or greater than arg2.
                               1531                 :                :  *
                               1532                 :                :  * Note: many functions that depend on this are marked leakproof; therefore,
                               1533                 :                :  * avoid reporting the actual contents of the input when throwing errors.
                               1534                 :                :  * All errors herein should be things that can't happen except on corrupt
                               1535                 :                :  * data, anyway; otherwise we will have trouble with indexing strings that
                               1536                 :                :  * would cause them.
                               1537                 :                :  */
                               1538                 :                : int
 2357 peter_e@gmx.net          1539                 :        3290302 : varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid)
                               1540                 :                : {
                               1541                 :                :     int         result;
                               1542                 :                : 
 1850 peter@eisentraut.org     1543                 :        3290302 :     check_collation_set(collid);
                               1544                 :                : 
                               1545                 :                :     /*
                               1546                 :                :      * Unfortunately, there is no strncoll(), so in the non-C locale case we
                               1547                 :                :      * have to do some memory copying.  This turns out to be significantly
                               1548                 :                :      * slower, so we optimize the case where LC_COLLATE is C.  We also try to
                               1549                 :                :      * optimize relatively-short strings by avoiding palloc/pfree overhead.
                               1550                 :                :      */
 4814 peter_e@gmx.net          1551         [ +  + ]:        3290293 :     if (lc_collate_is_c(collid))
                               1552                 :                :     {
 4863 rhaas@postgresql.org     1553                 :        1532441 :         result = memcmp(arg1, arg2, Min(len1, len2));
 6806 tgl@sss.pgh.pa.us        1554   [ +  +  +  + ]:        1532441 :         if ((result == 0) && (len1 != len2))
                               1555         [ +  + ]:          67114 :             result = (len1 < len2) ? -1 : 1;
                               1556                 :                :     }
                               1557                 :                :     else
                               1558                 :                :     {
                               1559                 :                :         pg_locale_t mylocale;
                               1560                 :                : 
  815 peter@eisentraut.org     1561                 :        1757852 :         mylocale = pg_newlocale_from_collation(collid);
                               1562                 :                : 
                               1563                 :                :         /*
                               1564                 :                :          * memcmp() can't tell us which of two unequal strings sorts first,
                               1565                 :                :          * but it's a cheap way to tell if they're equal.  Testing shows that
                               1566                 :                :          * memcmp() followed by strcoll() is only trivially slower than
                               1567                 :                :          * strcoll() by itself, so we don't lose much if this doesn't work out
                               1568                 :                :          * very often, and if it does - for example, because there are many
                               1569                 :                :          * equal strings in the input - then we win big by avoiding expensive
                               1570                 :                :          * collation-aware comparisons.
                               1571                 :                :          */
 3495 rhaas@postgresql.org     1572   [ +  +  +  + ]:        1757852 :         if (len1 == len2 && memcmp(arg1, arg2, len1) == 0)
                               1573                 :         697531 :             return 0;
                               1574                 :                : 
  416 jdavis@postgresql.or     1575                 :        1060321 :         result = pg_strncoll(arg1, len1, arg2, len2, mylocale);
                               1576                 :                : 
                               1577                 :                :         /* Break tie if necessary. */
                               1578   [ +  +  -  + ]:        1060321 :         if (result == 0 && pg_locale_deterministic(mylocale))
                               1579                 :                :         {
  416 jdavis@postgresql.or     1580                 :UBC           0 :             result = memcmp(arg1, arg2, Min(len1, len2));
                               1581   [ #  #  #  # ]:              0 :             if ((result == 0) && (len1 != len2))
                               1582         [ #  # ]:              0 :                 result = (len1 < len2) ? -1 : 1;
                               1583                 :                :         }
                               1584                 :                :     }
                               1585                 :                : 
 9357 bruce@momjian.us         1586                 :CBC     2592762 :     return result;
                               1587                 :                : }
                               1588                 :                : 
                               1589                 :                : /* text_cmp()
                               1590                 :                :  * Internal comparison function for text strings.
                               1591                 :                :  * Returns -1, 0 or 1
                               1592                 :                :  */
                               1593                 :                : static int
 4814 peter_e@gmx.net          1594                 :        2471733 : text_cmp(text *arg1, text *arg2, Oid collid)
                               1595                 :                : {
                               1596                 :                :     char       *a1p,
                               1597                 :                :                *a2p;
                               1598                 :                :     int         len1,
                               1599                 :                :                 len2;
                               1600                 :                : 
 6218 tgl@sss.pgh.pa.us        1601         [ +  + ]:        2471733 :     a1p = VARDATA_ANY(arg1);
                               1602         [ +  + ]:        2471733 :     a2p = VARDATA_ANY(arg2);
                               1603                 :                : 
                               1604   [ -  +  -  -  :        2471733 :     len1 = VARSIZE_ANY_EXHDR(arg1);
                                     -  -  -  -  +  
                                                 + ]
                               1605   [ -  +  -  -  :        2471733 :     len2 = VARSIZE_ANY_EXHDR(arg2);
                                     -  -  -  -  +  
                                                 + ]
                               1606                 :                : 
 4814 peter_e@gmx.net          1607                 :        2471733 :     return varstr_cmp(a1p, len1, a2p, len2, collid);
                               1608                 :                : }
                               1609                 :                : 
                               1610                 :                : /*
                               1611                 :                :  * Comparison functions for text strings.
                               1612                 :                :  *
                               1613                 :                :  * Note: btree indexes need these routines not to leak memory; therefore,
                               1614                 :                :  * be careful to free working copies of toasted datums.  Most places don't
                               1615                 :                :  * need to be so careful.
                               1616                 :                :  */
                               1617                 :                : 
                               1618                 :                : Datum
 8382 tgl@sss.pgh.pa.us        1619                 :        3146551 : texteq(PG_FUNCTION_ARGS)
                               1620                 :                : {
 1850 peter@eisentraut.org     1621                 :        3146551 :     Oid         collid = PG_GET_COLLATION();
  815                          1622                 :        3146551 :     bool        locale_is_c = false;
  703 tgl@sss.pgh.pa.us        1623                 :        3146551 :     pg_locale_t mylocale = 0;
                               1624                 :                :     bool        result;
                               1625                 :                : 
 1850 peter@eisentraut.org     1626                 :        3146551 :     check_collation_set(collid);
                               1627                 :                : 
  815                          1628         [ +  + ]:        3146551 :     if (lc_collate_is_c(collid))
                               1629                 :         663443 :         locale_is_c = true;
                               1630                 :                :     else
                               1631                 :        2483108 :         mylocale = pg_newlocale_from_collation(collid);
                               1632                 :                : 
  416 jdavis@postgresql.or     1633   [ +  +  +  + ]:        3146551 :     if (locale_is_c || pg_locale_deterministic(mylocale))
 1850 peter@eisentraut.org     1634                 :        3146276 :     {
                               1635                 :        3146276 :         Datum       arg1 = PG_GETARG_DATUM(0);
                               1636                 :        3146276 :         Datum       arg2 = PG_GETARG_DATUM(1);
                               1637                 :                :         Size        len1,
                               1638                 :                :                     len2;
                               1639                 :                : 
                               1640                 :                :         /*
                               1641                 :                :          * Since we only care about equality or not-equality, we can avoid all
                               1642                 :                :          * the expense of strcoll() here, and just do bitwise comparison.  In
                               1643                 :                :          * fact, we don't even have to do a bitwise comparison if we can show
                               1644                 :                :          * the lengths of the strings are unequal; which might save us from
                               1645                 :                :          * having to detoast one or both values.
                               1646                 :                :          */
                               1647                 :        3146276 :         len1 = toast_raw_datum_size(arg1);
                               1648                 :        3146276 :         len2 = toast_raw_datum_size(arg2);
                               1649         [ +  + ]:        3146276 :         if (len1 != len2)
                               1650                 :        1509634 :             result = false;
                               1651                 :                :         else
                               1652                 :                :         {
                               1653                 :        1636642 :             text       *targ1 = DatumGetTextPP(arg1);
                               1654                 :        1636642 :             text       *targ2 = DatumGetTextPP(arg2);
                               1655                 :                : 
                               1656   [ +  +  +  + ]:        1636642 :             result = (memcmp(VARDATA_ANY(targ1), VARDATA_ANY(targ2),
                               1657                 :                :                              len1 - VARHDRSZ) == 0);
                               1658                 :                : 
                               1659         [ +  + ]:        1636642 :             PG_FREE_IF_COPY(targ1, 0);
                               1660         [ -  + ]:        1636642 :             PG_FREE_IF_COPY(targ2, 1);
                               1661                 :                :         }
                               1662                 :                :     }
                               1663                 :                :     else
                               1664                 :                :     {
                               1665                 :            275 :         text       *arg1 = PG_GETARG_TEXT_PP(0);
                               1666                 :            275 :         text       *arg2 = PG_GETARG_TEXT_PP(1);
                               1667                 :                : 
                               1668                 :            275 :         result = (text_cmp(arg1, arg2, collid) == 0);
                               1669                 :                : 
                               1670         [ -  + ]:            275 :         PG_FREE_IF_COPY(arg1, 0);
                               1671         [ -  + ]:            275 :         PG_FREE_IF_COPY(arg2, 1);
                               1672                 :                :     }
                               1673                 :                : 
 8382 tgl@sss.pgh.pa.us        1674                 :        3146551 :     PG_RETURN_BOOL(result);
                               1675                 :                : }
                               1676                 :                : 
                               1677                 :                : Datum
                               1678                 :          10177 : textne(PG_FUNCTION_ARGS)
                               1679                 :                : {
 1850 peter@eisentraut.org     1680                 :          10177 :     Oid         collid = PG_GET_COLLATION();
  815                          1681                 :          10177 :     bool        locale_is_c = false;
  703 tgl@sss.pgh.pa.us        1682                 :          10177 :     pg_locale_t mylocale = 0;
                               1683                 :                :     bool        result;
                               1684                 :                : 
 1850 peter@eisentraut.org     1685                 :          10177 :     check_collation_set(collid);
                               1686                 :                : 
  815                          1687         [ +  + ]:          10177 :     if (lc_collate_is_c(collid))
                               1688                 :           2846 :         locale_is_c = true;
                               1689                 :                :     else
                               1690                 :           7331 :         mylocale = pg_newlocale_from_collation(collid);
                               1691                 :                : 
  416 jdavis@postgresql.or     1692   [ +  +  +  + ]:          10177 :     if (locale_is_c || pg_locale_deterministic(mylocale))
 1850 peter@eisentraut.org     1693                 :          10165 :     {
                               1694                 :          10165 :         Datum       arg1 = PG_GETARG_DATUM(0);
                               1695                 :          10165 :         Datum       arg2 = PG_GETARG_DATUM(1);
                               1696                 :                :         Size        len1,
                               1697                 :                :                     len2;
                               1698                 :                : 
                               1699                 :                :         /* See comment in texteq() */
                               1700                 :          10165 :         len1 = toast_raw_datum_size(arg1);
                               1701                 :          10165 :         len2 = toast_raw_datum_size(arg2);
                               1702         [ +  + ]:          10165 :         if (len1 != len2)
                               1703                 :           1343 :             result = true;
                               1704                 :                :         else
                               1705                 :                :         {
                               1706                 :           8822 :             text       *targ1 = DatumGetTextPP(arg1);
                               1707                 :           8822 :             text       *targ2 = DatumGetTextPP(arg2);
                               1708                 :                : 
                               1709   [ +  +  +  + ]:           8822 :             result = (memcmp(VARDATA_ANY(targ1), VARDATA_ANY(targ2),
                               1710                 :                :                              len1 - VARHDRSZ) != 0);
                               1711                 :                : 
                               1712         [ -  + ]:           8822 :             PG_FREE_IF_COPY(targ1, 0);
                               1713         [ -  + ]:           8822 :             PG_FREE_IF_COPY(targ2, 1);
                               1714                 :                :         }
                               1715                 :                :     }
                               1716                 :                :     else
                               1717                 :                :     {
                               1718                 :             12 :         text       *arg1 = PG_GETARG_TEXT_PP(0);
                               1719                 :             12 :         text       *arg2 = PG_GETARG_TEXT_PP(1);
                               1720                 :                : 
                               1721                 :             12 :         result = (text_cmp(arg1, arg2, collid) != 0);
                               1722                 :                : 
                               1723         [ -  + ]:             12 :         PG_FREE_IF_COPY(arg1, 0);
                               1724         [ -  + ]:             12 :         PG_FREE_IF_COPY(arg2, 1);
                               1725                 :                :     }
                               1726                 :                : 
 8382 tgl@sss.pgh.pa.us        1727                 :          10177 :     PG_RETURN_BOOL(result);
                               1728                 :                : }
                               1729                 :                : 
                               1730                 :                : Datum
 8683                          1731                 :         104125 : text_lt(PG_FUNCTION_ARGS)
                               1732                 :                : {
 6218                          1733                 :         104125 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               1734                 :         104125 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               1735                 :                :     bool        result;
                               1736                 :                : 
 4814 peter_e@gmx.net          1737                 :         104125 :     result = (text_cmp(arg1, arg2, PG_GET_COLLATION()) < 0);
                               1738                 :                : 
 8677 tgl@sss.pgh.pa.us        1739         [ +  + ]:         104116 :     PG_FREE_IF_COPY(arg1, 0);
                               1740         [ -  + ]:         104116 :     PG_FREE_IF_COPY(arg2, 1);
                               1741                 :                : 
                               1742                 :         104116 :     PG_RETURN_BOOL(result);
                               1743                 :                : }
                               1744                 :                : 
                               1745                 :                : Datum
 8683                          1746                 :         162616 : text_le(PG_FUNCTION_ARGS)
                               1747                 :                : {
 6218                          1748                 :         162616 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               1749                 :         162616 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               1750                 :                :     bool        result;
                               1751                 :                : 
 4814 peter_e@gmx.net          1752                 :         162616 :     result = (text_cmp(arg1, arg2, PG_GET_COLLATION()) <= 0);
                               1753                 :                : 
 8677 tgl@sss.pgh.pa.us        1754         [ +  + ]:         162616 :     PG_FREE_IF_COPY(arg1, 0);
                               1755         [ +  + ]:         162616 :     PG_FREE_IF_COPY(arg2, 1);
                               1756                 :                : 
                               1757                 :         162616 :     PG_RETURN_BOOL(result);
                               1758                 :                : }
                               1759                 :                : 
                               1760                 :                : Datum
 8683                          1761                 :          98722 : text_gt(PG_FUNCTION_ARGS)
                               1762                 :                : {
 6218                          1763                 :          98722 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               1764                 :          98722 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               1765                 :                :     bool        result;
                               1766                 :                : 
 4814 peter_e@gmx.net          1767                 :          98722 :     result = (text_cmp(arg1, arg2, PG_GET_COLLATION()) > 0);
                               1768                 :                : 
 8677 tgl@sss.pgh.pa.us        1769         [ +  + ]:          98722 :     PG_FREE_IF_COPY(arg1, 0);
                               1770         [ -  + ]:          98722 :     PG_FREE_IF_COPY(arg2, 1);
                               1771                 :                : 
                               1772                 :          98722 :     PG_RETURN_BOOL(result);
                               1773                 :                : }
                               1774                 :                : 
                               1775                 :                : Datum
 8683                          1776                 :          93559 : text_ge(PG_FUNCTION_ARGS)
                               1777                 :                : {
 6218                          1778                 :          93559 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               1779                 :          93559 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               1780                 :                :     bool        result;
                               1781                 :                : 
 4814 peter_e@gmx.net          1782                 :          93559 :     result = (text_cmp(arg1, arg2, PG_GET_COLLATION()) >= 0);
                               1783                 :                : 
 8677 tgl@sss.pgh.pa.us        1784         [ +  + ]:          93559 :     PG_FREE_IF_COPY(arg1, 0);
                               1785         [ -  + ]:          93559 :     PG_FREE_IF_COPY(arg2, 1);
                               1786                 :                : 
                               1787                 :          93559 :     PG_RETURN_BOOL(result);
                               1788                 :                : }
                               1789                 :                : 
                               1790                 :                : Datum
 2203 teodor@sigaev.ru         1791                 :          18957 : text_starts_with(PG_FUNCTION_ARGS)
                               1792                 :                : {
                               1793                 :          18957 :     Datum       arg1 = PG_GETARG_DATUM(0);
                               1794                 :          18957 :     Datum       arg2 = PG_GETARG_DATUM(1);
 1850 peter@eisentraut.org     1795                 :          18957 :     Oid         collid = PG_GET_COLLATION();
 1789 tgl@sss.pgh.pa.us        1796                 :          18957 :     pg_locale_t mylocale = 0;
                               1797                 :                :     bool        result;
                               1798                 :                :     Size        len1,
                               1799                 :                :                 len2;
                               1800                 :                : 
 1850 peter@eisentraut.org     1801                 :          18957 :     check_collation_set(collid);
                               1802                 :                : 
  815                          1803         [ +  + ]:          18957 :     if (!lc_collate_is_c(collid))
 1850                          1804                 :          12638 :         mylocale = pg_newlocale_from_collation(collid);
                               1805                 :                : 
  416 jdavis@postgresql.or     1806         [ -  + ]:          18957 :     if (!pg_locale_deterministic(mylocale))
 1850 peter@eisentraut.org     1807         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1808                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1809                 :                :                  errmsg("nondeterministic collations are not supported for substring searches")));
                               1810                 :                : 
 2203 teodor@sigaev.ru         1811                 :CBC       18957 :     len1 = toast_raw_datum_size(arg1);
                               1812                 :          18957 :     len2 = toast_raw_datum_size(arg2);
                               1813         [ -  + ]:          18957 :     if (len2 > len1)
 2203 teodor@sigaev.ru         1814                 :UBC           0 :         result = false;
                               1815                 :                :     else
                               1816                 :                :     {
 1839 sfrost@snowman.net       1817                 :CBC       18957 :         text       *targ1 = text_substring(arg1, 1, len2, false);
 2203 teodor@sigaev.ru         1818                 :          18957 :         text       *targ2 = DatumGetTextPP(arg2);
                               1819                 :                : 
                               1820   [ -  +  -  + ]:          18957 :         result = (memcmp(VARDATA_ANY(targ1), VARDATA_ANY(targ2),
                               1821   [ -  +  -  -  :          18957 :                          VARSIZE_ANY_EXHDR(targ2)) == 0);
                                     -  -  -  -  -  
                                                 + ]
                               1822                 :                : 
                               1823         [ +  - ]:          18957 :         PG_FREE_IF_COPY(targ1, 0);
                               1824         [ -  + ]:          18957 :         PG_FREE_IF_COPY(targ2, 1);
                               1825                 :                :     }
                               1826                 :                : 
                               1827                 :          18957 :     PG_RETURN_BOOL(result);
                               1828                 :                : }
                               1829                 :                : 
                               1830                 :                : Datum
 8382 tgl@sss.pgh.pa.us        1831                 :        1854606 : bttextcmp(PG_FUNCTION_ARGS)
                               1832                 :                : {
 6218                          1833                 :        1854606 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               1834                 :        1854606 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               1835                 :                :     int32       result;
                               1836                 :                : 
 4814 peter_e@gmx.net          1837                 :        1854606 :     result = text_cmp(arg1, arg2, PG_GET_COLLATION());
                               1838                 :                : 
 8382 tgl@sss.pgh.pa.us        1839         [ +  + ]:        1854606 :     PG_FREE_IF_COPY(arg1, 0);
                               1840         [ +  + ]:        1854606 :     PG_FREE_IF_COPY(arg2, 1);
                               1841                 :                : 
                               1842                 :        1854606 :     PG_RETURN_INT32(result);
                               1843                 :                : }
                               1844                 :                : 
                               1845                 :                : Datum
 3531 rhaas@postgresql.org     1846                 :          35762 : bttextsortsupport(PG_FUNCTION_ARGS)
                               1847                 :                : {
 3249 bruce@momjian.us         1848                 :          35762 :     SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
                               1849                 :          35762 :     Oid         collid = ssup->ssup_collation;
                               1850                 :                :     MemoryContext oldcontext;
                               1851                 :                : 
 3531 rhaas@postgresql.org     1852                 :          35762 :     oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
                               1853                 :                : 
                               1854                 :                :     /* Use generic string SortSupport */
 1943 tgl@sss.pgh.pa.us        1855                 :          35762 :     varstr_sortsupport(ssup, TEXTOID, collid);
                               1856                 :                : 
 3531 rhaas@postgresql.org     1857                 :          35756 :     MemoryContextSwitchTo(oldcontext);
                               1858                 :                : 
                               1859                 :          35756 :     PG_RETURN_VOID();
                               1860                 :                : }
                               1861                 :                : 
                               1862                 :                : /*
                               1863                 :                :  * Generic sortsupport interface for character type's operator classes.
                               1864                 :                :  * Includes locale support, and support for BpChar semantics (i.e. removing
                               1865                 :                :  * trailing spaces before comparison).
                               1866                 :                :  *
                               1867                 :                :  * Relies on the assumption that text, VarChar, BpChar, and bytea all have the
                               1868                 :                :  * same representation.  Callers that always use the C collation (e.g.
                               1869                 :                :  * non-collatable type callers like bytea) may have NUL bytes in their strings;
                               1870                 :                :  * this will not work with any other collation, though.
                               1871                 :                :  */
                               1872                 :                : void
 1921 tgl@sss.pgh.pa.us        1873                 :          53705 : varstr_sortsupport(SortSupport ssup, Oid typid, Oid collid)
                               1874                 :                : {
 3249 bruce@momjian.us         1875                 :          53705 :     bool        abbreviate = ssup->abbreviate;
                               1876                 :          53705 :     bool        collate_c = false;
                               1877                 :                :     VarStringSortSupport *sss;
                               1878                 :          53705 :     pg_locale_t locale = 0;
                               1879                 :                : 
 1850 peter@eisentraut.org     1880                 :          53705 :     check_collation_set(collid);
                               1881                 :                : 
                               1882                 :                :     /*
                               1883                 :                :      * If possible, set ssup->comparator to a function which can be used to
                               1884                 :                :      * directly compare two datums.  If we can do this, we'll avoid the
                               1885                 :                :      * overhead of a trip through the fmgr layer for every comparison, which
                               1886                 :                :      * can be substantial.
                               1887                 :                :      *
                               1888                 :                :      * Most typically, we'll set the comparator to varlenafastcmp_locale,
                               1889                 :                :      * which uses strcoll() to perform comparisons.  We use that for the
                               1890                 :                :      * BpChar case too, but type NAME uses namefastcmp_locale. However, if
                               1891                 :                :      * LC_COLLATE = C, we can make things quite a bit faster with
                               1892                 :                :      * varstrfastcmp_c, bpcharfastcmp_c, or namefastcmp_c, all of which use
                               1893                 :                :      * memcmp() rather than strcoll().
                               1894                 :                :      */
 3370 rhaas@postgresql.org     1895         [ +  + ]:          53699 :     if (lc_collate_is_c(collid))
                               1896                 :                :     {
 1921 tgl@sss.pgh.pa.us        1897         [ +  + ]:          35814 :         if (typid == BPCHAROID)
 2993 rhaas@postgresql.org     1898                 :            140 :             ssup->comparator = bpcharfastcmp_c;
 1921 tgl@sss.pgh.pa.us        1899         [ +  + ]:          35674 :         else if (typid == NAMEOID)
                               1900                 :                :         {
 1943                          1901                 :          17443 :             ssup->comparator = namefastcmp_c;
                               1902                 :                :             /* Not supporting abbreviation with type NAME, for now */
                               1903                 :          17443 :             abbreviate = false;
                               1904                 :                :         }
                               1905                 :                :         else
                               1906                 :          18231 :             ssup->comparator = varstrfastcmp_c;
                               1907                 :                : 
 3370 rhaas@postgresql.org     1908                 :          35814 :         collate_c = true;
                               1909                 :                :     }
                               1910                 :                :     else
                               1911                 :                :     {
                               1912                 :                :         /*
                               1913                 :                :          * We need a collation-sensitive comparison.  To make things faster,
                               1914                 :                :          * we'll figure out the collation based on the locale id and cache the
                               1915                 :                :          * result.
                               1916                 :                :          */
  815 peter@eisentraut.org     1917                 :          17885 :         locale = pg_newlocale_from_collation(collid);
                               1918                 :                : 
                               1919                 :                :         /*
                               1920                 :                :          * We use varlenafastcmp_locale except for type NAME.
                               1921                 :                :          */
 1921 tgl@sss.pgh.pa.us        1922         [ -  + ]:          17885 :         if (typid == NAMEOID)
                               1923                 :                :         {
 1943 tgl@sss.pgh.pa.us        1924                 :UBC           0 :             ssup->comparator = namefastcmp_locale;
                               1925                 :                :             /* Not supporting abbreviation with type NAME, for now */
                               1926                 :              0 :             abbreviate = false;
                               1927                 :                :         }
                               1928                 :                :         else
 1943 tgl@sss.pgh.pa.us        1929                 :CBC       17885 :             ssup->comparator = varlenafastcmp_locale;
                               1930                 :                :     }
                               1931                 :                : 
                               1932                 :                :     /*
                               1933                 :                :      * Unfortunately, it seems that abbreviation for non-C collations is
                               1934                 :                :      * broken on many common platforms; see pg_strxfrm_enabled().
                               1935                 :                :      *
                               1936                 :                :      * Even apart from the risk of broken locales, it's possible that there
                               1937                 :                :      * are platforms where the use of abbreviated keys should be disabled at
                               1938                 :                :      * compile time.  Having only 4 byte datums could make worst-case
                               1939                 :                :      * performance drastically more likely, for example.  Moreover, macOS's
                               1940                 :                :      * strxfrm() implementation is known to not effectively concentrate a
                               1941                 :                :      * significant amount of entropy from the original string in earlier
                               1942                 :                :      * transformed blobs.  It's possible that other supported platforms are
                               1943                 :                :      * similarly encumbered.  So, if we ever get past disabling this
                               1944                 :                :      * categorically, we may still want or need to disable it for particular
                               1945                 :                :      * platforms.
                               1946                 :                :      */
  416 jdavis@postgresql.or     1947   [ +  +  +  + ]:          53699 :     if (!collate_c && !pg_strxfrm_enabled(locale))
 2944 rhaas@postgresql.org     1948                 :          17604 :         abbreviate = false;
                               1949                 :                : 
                               1950                 :                :     /*
                               1951                 :                :      * If we're using abbreviated keys, or if we're using a locale-aware
                               1952                 :                :      * comparison, we need to initialize a VarStringSortSupport object. Both
                               1953                 :                :      * cases will make use of the temporary buffers we initialize here for
                               1954                 :                :      * scratch space (and to detect requirement for BpChar semantics from
                               1955                 :                :      * caller), and the abbreviation case requires additional state.
                               1956                 :                :      */
 3370                          1957   [ +  +  +  + ]:          53699 :     if (abbreviate || !collate_c)
                               1958                 :                :     {
 2988 tgl@sss.pgh.pa.us        1959                 :          28771 :         sss = palloc(sizeof(VarStringSortSupport));
 2993 rhaas@postgresql.org     1960                 :          28771 :         sss->buf1 = palloc(TEXTBUFLEN);
                               1961                 :          28771 :         sss->buflen1 = TEXTBUFLEN;
                               1962                 :          28771 :         sss->buf2 = palloc(TEXTBUFLEN);
                               1963                 :          28771 :         sss->buflen2 = TEXTBUFLEN;
                               1964                 :                :         /* Start with invalid values */
                               1965                 :          28771 :         sss->last_len1 = -1;
                               1966                 :          28771 :         sss->last_len2 = -1;
                               1967                 :                :         /* Initialize */
                               1968                 :          28771 :         sss->last_returned = 0;
                               1969                 :          28771 :         sss->locale = locale;
                               1970                 :                : 
                               1971                 :                :         /*
                               1972                 :                :          * To avoid somehow confusing a strxfrm() blob and an original string,
                               1973                 :                :          * constantly keep track of the variety of data that buf1 and buf2
                               1974                 :                :          * currently contain.
                               1975                 :                :          *
                               1976                 :                :          * Comparisons may be interleaved with conversion calls.  Frequently,
                               1977                 :                :          * conversions and comparisons are batched into two distinct phases,
                               1978                 :                :          * but the correctness of caching cannot hinge upon this.  For
                               1979                 :                :          * comparison caching, buffer state is only trusted if cache_blob is
                               1980                 :                :          * found set to false, whereas strxfrm() caching only trusts the state
                               1981                 :                :          * when cache_blob is found set to true.
                               1982                 :                :          *
                               1983                 :                :          * Arbitrarily initialize cache_blob to true.
                               1984                 :                :          */
                               1985                 :          28771 :         sss->cache_blob = true;
                               1986                 :          28771 :         sss->collate_c = collate_c;
 1921 tgl@sss.pgh.pa.us        1987                 :          28771 :         sss->typid = typid;
 2993 rhaas@postgresql.org     1988                 :          28771 :         ssup->ssup_extra = sss;
                               1989                 :                : 
                               1990                 :                :         /*
                               1991                 :                :          * If possible, plan to use the abbreviated keys optimization.  The
                               1992                 :                :          * core code may switch back to authoritative comparator should
                               1993                 :                :          * abbreviation be aborted.
                               1994                 :                :          */
 3370                          1995         [ +  + ]:          28771 :         if (abbreviate)
                               1996                 :                :         {
 2993                          1997                 :          11143 :             sss->prop_card = 0.20;
                               1998                 :          11143 :             initHyperLogLog(&sss->abbr_card, 10);
                               1999                 :          11143 :             initHyperLogLog(&sss->full_card, 10);
 3370                          2000                 :          11143 :             ssup->abbrev_full_comparator = ssup->comparator;
  743 john.naylor@postgres     2001                 :          11143 :             ssup->comparator = ssup_datum_unsigned_cmp;
 2993 rhaas@postgresql.org     2002                 :          11143 :             ssup->abbrev_converter = varstr_abbrev_convert;
                               2003                 :          11143 :             ssup->abbrev_abort = varstr_abbrev_abort;
                               2004                 :                :         }
                               2005                 :                :     }
 3531                          2006                 :          53699 : }
                               2007                 :                : 
                               2008                 :                : /*
                               2009                 :                :  * sortsupport comparison func (for C locale case)
                               2010                 :                :  */
                               2011                 :                : static int
 2993                          2012                 :       19010508 : varstrfastcmp_c(Datum x, Datum y, SortSupport ssup)
                               2013                 :                : {
 2988 tgl@sss.pgh.pa.us        2014                 :       19010508 :     VarString  *arg1 = DatumGetVarStringPP(x);
                               2015                 :       19010508 :     VarString  *arg2 = DatumGetVarStringPP(y);
                               2016                 :                :     char       *a1p,
                               2017                 :                :                *a2p;
                               2018                 :                :     int         len1,
                               2019                 :                :                 len2,
                               2020                 :                :                 result;
                               2021                 :                : 
 3531 rhaas@postgresql.org     2022         [ +  + ]:       19010508 :     a1p = VARDATA_ANY(arg1);
                               2023         [ +  + ]:       19010508 :     a2p = VARDATA_ANY(arg2);
                               2024                 :                : 
                               2025   [ -  +  -  -  :       19010508 :     len1 = VARSIZE_ANY_EXHDR(arg1);
                                     -  -  -  -  +  
                                                 + ]
                               2026   [ -  +  -  -  :       19010508 :     len2 = VARSIZE_ANY_EXHDR(arg2);
                                     -  -  -  -  +  
                                                 + ]
                               2027                 :                : 
                               2028                 :       19010508 :     result = memcmp(a1p, a2p, Min(len1, len2));
                               2029   [ +  +  +  + ]:       19010508 :     if ((result == 0) && (len1 != len2))
                               2030         [ +  + ]:         533392 :         result = (len1 < len2) ? -1 : 1;
                               2031                 :                : 
                               2032                 :                :     /* We can't afford to leak memory here. */
                               2033         [ +  + ]:       19010508 :     if (PointerGetDatum(arg1) != x)
 3531 rhaas@postgresql.org     2034                 :GBC           1 :         pfree(arg1);
 3531 rhaas@postgresql.org     2035         [ +  + ]:CBC    19010508 :     if (PointerGetDatum(arg2) != y)
 3531 rhaas@postgresql.org     2036                 :GBC           1 :         pfree(arg2);
                               2037                 :                : 
 3531 rhaas@postgresql.org     2038                 :CBC    19010508 :     return result;
                               2039                 :                : }
                               2040                 :                : 
                               2041                 :                : /*
                               2042                 :                :  * sortsupport comparison func (for BpChar C locale case)
                               2043                 :                :  *
                               2044                 :                :  * BpChar outsources its sortsupport to this module.  Specialization for the
                               2045                 :                :  * varstr_sortsupport BpChar case, modeled on
                               2046                 :                :  * internal_bpchar_pattern_compare().
                               2047                 :                :  */
                               2048                 :                : static int
 2993                          2049                 :          31685 : bpcharfastcmp_c(Datum x, Datum y, SortSupport ssup)
                               2050                 :                : {
                               2051                 :          31685 :     BpChar     *arg1 = DatumGetBpCharPP(x);
                               2052                 :          31685 :     BpChar     *arg2 = DatumGetBpCharPP(y);
                               2053                 :                :     char       *a1p,
                               2054                 :                :                *a2p;
                               2055                 :                :     int         len1,
                               2056                 :                :                 len2,
                               2057                 :                :                 result;
                               2058                 :                : 
                               2059         [ +  + ]:          31685 :     a1p = VARDATA_ANY(arg1);
                               2060         [ +  + ]:          31685 :     a2p = VARDATA_ANY(arg2);
                               2061                 :                : 
                               2062   [ -  +  -  -  :          31685 :     len1 = bpchartruelen(a1p, VARSIZE_ANY_EXHDR(arg1));
                                     -  -  -  -  +  
                                                 + ]
                               2063   [ -  +  -  -  :          31685 :     len2 = bpchartruelen(a2p, VARSIZE_ANY_EXHDR(arg2));
                                     -  -  -  -  +  
                                                 + ]
                               2064                 :                : 
                               2065                 :          31685 :     result = memcmp(a1p, a2p, Min(len1, len2));
                               2066   [ +  +  +  + ]:          31685 :     if ((result == 0) && (len1 != len2))
 2993 rhaas@postgresql.org     2067         [ -  + ]:GBC           2 :         result = (len1 < len2) ? -1 : 1;
                               2068                 :                : 
                               2069                 :                :     /* We can't afford to leak memory here. */
 2993 rhaas@postgresql.org     2070         [ -  + ]:CBC       31685 :     if (PointerGetDatum(arg1) != x)
 2993 rhaas@postgresql.org     2071                 :UBC           0 :         pfree(arg1);
 2993 rhaas@postgresql.org     2072         [ -  + ]:CBC       31685 :     if (PointerGetDatum(arg2) != y)
 2993 rhaas@postgresql.org     2073                 :UBC           0 :         pfree(arg2);
                               2074                 :                : 
 2993 rhaas@postgresql.org     2075                 :CBC       31685 :     return result;
                               2076                 :                : }
                               2077                 :                : 
                               2078                 :                : /*
                               2079                 :                :  * sortsupport comparison func (for NAME C locale case)
                               2080                 :                :  */
                               2081                 :                : static int
 1943 tgl@sss.pgh.pa.us        2082                 :       19463014 : namefastcmp_c(Datum x, Datum y, SortSupport ssup)
                               2083                 :                : {
                               2084                 :       19463014 :     Name        arg1 = DatumGetName(x);
                               2085                 :       19463014 :     Name        arg2 = DatumGetName(y);
                               2086                 :                : 
                               2087                 :       19463014 :     return strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN);
                               2088                 :                : }
                               2089                 :                : 
                               2090                 :                : /*
                               2091                 :                :  * sortsupport comparison func (for locale case with all varlena types)
                               2092                 :                :  */
                               2093                 :                : static int
                               2094                 :       14175997 : varlenafastcmp_locale(Datum x, Datum y, SortSupport ssup)
                               2095                 :                : {
 2988                          2096                 :       14175997 :     VarString  *arg1 = DatumGetVarStringPP(x);
                               2097                 :       14175997 :     VarString  *arg2 = DatumGetVarStringPP(y);
                               2098                 :                :     char       *a1p,
                               2099                 :                :                *a2p;
                               2100                 :                :     int         len1,
                               2101                 :                :                 len2,
                               2102                 :                :                 result;
                               2103                 :                : 
 3531 rhaas@postgresql.org     2104         [ +  + ]:       14175997 :     a1p = VARDATA_ANY(arg1);
                               2105         [ +  + ]:       14175997 :     a2p = VARDATA_ANY(arg2);
                               2106                 :                : 
                               2107   [ -  +  -  -  :       14175997 :     len1 = VARSIZE_ANY_EXHDR(arg1);
                                     -  -  -  -  +  
                                                 + ]
                               2108   [ -  +  -  -  :       14175997 :     len2 = VARSIZE_ANY_EXHDR(arg2);
                                     -  -  -  -  +  
                                                 + ]
                               2109                 :                : 
 1943 tgl@sss.pgh.pa.us        2110                 :       14175997 :     result = varstrfastcmp_locale(a1p, len1, a2p, len2, ssup);
                               2111                 :                : 
                               2112                 :                :     /* We can't afford to leak memory here. */
                               2113         [ +  + ]:       14175997 :     if (PointerGetDatum(arg1) != x)
                               2114                 :              2 :         pfree(arg1);
                               2115         [ +  + ]:       14175997 :     if (PointerGetDatum(arg2) != y)
                               2116                 :              2 :         pfree(arg2);
                               2117                 :                : 
                               2118                 :       14175997 :     return result;
                               2119                 :                : }
                               2120                 :                : 
                               2121                 :                : /*
                               2122                 :                :  * sortsupport comparison func (for locale case with NAME type)
                               2123                 :                :  */
                               2124                 :                : static int
 1943 tgl@sss.pgh.pa.us        2125                 :UBC           0 : namefastcmp_locale(Datum x, Datum y, SortSupport ssup)
                               2126                 :                : {
                               2127                 :              0 :     Name        arg1 = DatumGetName(x);
                               2128                 :              0 :     Name        arg2 = DatumGetName(y);
                               2129                 :                : 
                               2130                 :              0 :     return varstrfastcmp_locale(NameStr(*arg1), strlen(NameStr(*arg1)),
                               2131                 :              0 :                                 NameStr(*arg2), strlen(NameStr(*arg2)),
                               2132                 :                :                                 ssup);
                               2133                 :                : }
                               2134                 :                : 
                               2135                 :                : /*
                               2136                 :                :  * sortsupport comparison func for locale cases
                               2137                 :                :  */
                               2138                 :                : static int
 1943 tgl@sss.pgh.pa.us        2139                 :CBC    14175997 : varstrfastcmp_locale(char *a1p, int len1, char *a2p, int len2, SortSupport ssup)
                               2140                 :                : {
                               2141                 :       14175997 :     VarStringSortSupport *sss = (VarStringSortSupport *) ssup->ssup_extra;
                               2142                 :                :     int         result;
                               2143                 :                :     bool        arg1_match;
                               2144                 :                : 
                               2145                 :                :     /* Fast pre-check for equality, as discussed in varstr_cmp() */
 3495 rhaas@postgresql.org     2146   [ +  +  +  + ]:       14175997 :     if (len1 == len2 && memcmp(a1p, a2p, len1) == 0)
                               2147                 :                :     {
                               2148                 :                :         /*
                               2149                 :                :          * No change in buf1 or buf2 contents, so avoid changing last_len1 or
                               2150                 :                :          * last_len2.  Existing contents of buffers might still be used by
                               2151                 :                :          * next call.
                               2152                 :                :          *
                               2153                 :                :          * It's fine to allow the comparison of BpChar padding bytes here,
                               2154                 :                :          * even though that implies that the memcmp() will usually be
                               2155                 :                :          * performed for BpChar callers (though multibyte characters could
                               2156                 :                :          * still prevent that from occurring).  The memcmp() is still very
                               2157                 :                :          * cheap, and BpChar's funny semantics have us remove trailing spaces
                               2158                 :                :          * (not limited to padding), so we need make no distinction between
                               2159                 :                :          * padding space characters and "real" space characters.
                               2160                 :                :          */
 1943 tgl@sss.pgh.pa.us        2161                 :        4749084 :         return 0;
                               2162                 :                :     }
                               2163                 :                : 
 1921                          2164         [ +  + ]:        9426913 :     if (sss->typid == BPCHAROID)
                               2165                 :                :     {
                               2166                 :                :         /* Get true number of bytes, ignoring trailing spaces */
 2993 rhaas@postgresql.org     2167                 :          17533 :         len1 = bpchartruelen(a1p, len1);
                               2168                 :          17533 :         len2 = bpchartruelen(a2p, len2);
                               2169                 :                :     }
                               2170                 :                : 
                               2171         [ +  + ]:        9426913 :     if (len1 >= sss->buflen1)
                               2172                 :                :     {
                               2173         [ +  - ]:              3 :         sss->buflen1 = Max(len1 + 1, Min(sss->buflen1 * 2, MaxAllocSize));
  609 tgl@sss.pgh.pa.us        2174                 :              3 :         sss->buf1 = repalloc(sss->buf1, sss->buflen1);
                               2175                 :                :     }
 2993 rhaas@postgresql.org     2176         [ +  + ]:        9426913 :     if (len2 >= sss->buflen2)
                               2177                 :                :     {
                               2178         [ +  - ]:              3 :         sss->buflen2 = Max(len2 + 1, Min(sss->buflen2 * 2, MaxAllocSize));
  609 tgl@sss.pgh.pa.us        2179                 :              3 :         sss->buf2 = repalloc(sss->buf2, sss->buflen2);
                               2180                 :                :     }
                               2181                 :                : 
                               2182                 :                :     /*
                               2183                 :                :      * We're likely to be asked to compare the same strings repeatedly, and
                               2184                 :                :      * memcmp() is so much cheaper than strcoll() that it pays to try to cache
                               2185                 :                :      * comparisons, even though in general there is no reason to think that
                               2186                 :                :      * that will work out (every string datum may be unique).  Caching does
                               2187                 :                :      * not slow things down measurably when it doesn't work out, and can speed
                               2188                 :                :      * things up by rather a lot when it does.  In part, this is because the
                               2189                 :                :      * memcmp() compares data from cachelines that are needed in L1 cache even
                               2190                 :                :      * when the last comparison's result cannot be reused.
                               2191                 :                :      */
 3110 rhaas@postgresql.org     2192                 :        9426913 :     arg1_match = true;
 2993                          2193   [ +  +  +  + ]:        9426913 :     if (len1 != sss->last_len1 || memcmp(sss->buf1, a1p, len1) != 0)
                               2194                 :                :     {
 3110                          2195                 :        8487187 :         arg1_match = false;
 2993                          2196                 :        8487187 :         memcpy(sss->buf1, a1p, len1);
                               2197                 :        8487187 :         sss->buf1[len1] = '\0';
                               2198                 :        8487187 :         sss->last_len1 = len1;
                               2199                 :                :     }
                               2200                 :                : 
                               2201                 :                :     /*
                               2202                 :                :      * If we're comparing the same two strings as last time, we can return the
                               2203                 :                :      * same answer without calling strcoll() again.  This is more likely than
                               2204                 :                :      * it seems (at least with moderate to low cardinality sets), because
                               2205                 :                :      * quicksort compares the same pivot against many values.
                               2206                 :                :      */
                               2207   [ +  +  +  + ]:        9426913 :     if (len2 != sss->last_len2 || memcmp(sss->buf2, a2p, len2) != 0)
                               2208                 :                :     {
                               2209                 :        1428050 :         memcpy(sss->buf2, a2p, len2);
                               2210                 :        1428050 :         sss->buf2[len2] = '\0';
                               2211                 :        1428050 :         sss->last_len2 = len2;
                               2212                 :                :     }
                               2213   [ +  +  +  - ]:        7998863 :     else if (arg1_match && !sss->cache_blob)
                               2214                 :                :     {
                               2215                 :                :         /* Use result cached following last actual strcoll() call */
 1943 tgl@sss.pgh.pa.us        2216                 :         783961 :         return sss->last_returned;
                               2217                 :                :     }
                               2218                 :                : 
  416 jdavis@postgresql.or     2219                 :        8642952 :     result = pg_strcoll(sss->buf1, sss->buf2, sss->locale);
                               2220                 :                : 
                               2221                 :                :     /* Break tie if necessary. */
                               2222   [ +  +  -  + ]:        8642952 :     if (result == 0 && pg_locale_deterministic(sss->locale))
 2993 rhaas@postgresql.org     2223                 :UBC           0 :         result = strcmp(sss->buf1, sss->buf2);
                               2224                 :                : 
                               2225                 :                :     /* Cache result, perhaps saving an expensive strcoll() call next time */
 2993 rhaas@postgresql.org     2226                 :CBC     8642952 :     sss->cache_blob = false;
                               2227                 :        8642952 :     sss->last_returned = result;
 3531                          2228                 :        8642952 :     return result;
                               2229                 :                : }
                               2230                 :                : 
                               2231                 :                : /*
                               2232                 :                :  * Conversion routine for sortsupport.  Converts original to abbreviated key
                               2233                 :                :  * representation.  Our encoding strategy is simple -- pack the first 8 bytes
                               2234                 :                :  * of a strxfrm() blob into a Datum (on little-endian machines, the 8 bytes are
                               2235                 :                :  * stored in reverse order), and treat it as an unsigned integer.  When the "C"
                               2236                 :                :  * locale is used, or in case of bytea, just memcpy() from original instead.
                               2237                 :                :  */
                               2238                 :                : static Datum
 2993                          2239                 :         409286 : varstr_abbrev_convert(Datum original, SortSupport ssup)
                               2240                 :                : {
  416 jdavis@postgresql.or     2241                 :         409286 :     const size_t max_prefix_bytes = sizeof(Datum);
 2988 tgl@sss.pgh.pa.us        2242                 :         409286 :     VarStringSortSupport *sss = (VarStringSortSupport *) ssup->ssup_extra;
                               2243                 :         409286 :     VarString  *authoritative = DatumGetVarStringPP(original);
                               2244         [ +  + ]:         409286 :     char       *authoritative_data = VARDATA_ANY(authoritative);
                               2245                 :                : 
                               2246                 :                :     /* working state */
                               2247                 :                :     Datum       res;
                               2248                 :                :     char       *pres;
                               2249                 :                :     int         len;
                               2250                 :                :     uint32      hash;
                               2251                 :                : 
 3373 rhaas@postgresql.org     2252                 :         409286 :     pres = (char *) &res;
                               2253                 :                :     /* memset(), so any non-overwritten bytes are NUL */
  416 jdavis@postgresql.or     2254                 :         409286 :     memset(pres, 0, max_prefix_bytes);
 3373 rhaas@postgresql.org     2255   [ -  +  -  -  :         409286 :     len = VARSIZE_ANY_EXHDR(authoritative);
                                     -  -  -  -  +  
                                                 + ]
                               2256                 :                : 
                               2257                 :                :     /* Get number of bytes, ignoring trailing spaces */
 1921 tgl@sss.pgh.pa.us        2258         [ +  + ]:         409286 :     if (sss->typid == BPCHAROID)
 2993 rhaas@postgresql.org     2259                 :            505 :         len = bpchartruelen(authoritative_data, len);
                               2260                 :                : 
                               2261                 :                :     /*
                               2262                 :                :      * If we're using the C collation, use memcpy(), rather than strxfrm(), to
                               2263                 :                :      * abbreviate keys.  The full comparator for the C locale is always
                               2264                 :                :      * memcmp().  It would be incorrect to allow bytea callers (callers that
                               2265                 :                :      * always force the C collation -- bytea isn't a collatable type, but this
                               2266                 :                :      * approach is convenient) to use strxfrm().  This is because bytea
                               2267                 :                :      * strings may contain NUL bytes.  Besides, this should be faster, too.
                               2268                 :                :      *
                               2269                 :                :      * More generally, it's okay that bytea callers can have NUL bytes in
                               2270                 :                :      * strings because abbreviated cmp need not make a distinction between
                               2271                 :                :      * terminating NUL bytes, and NUL bytes representing actual NULs in the
                               2272                 :                :      * authoritative representation.  Hopefully a comparison at or past one
                               2273                 :                :      * abbreviated key's terminating NUL byte will resolve the comparison
                               2274                 :                :      * without consulting the authoritative representation; specifically, some
                               2275                 :                :      * later non-NUL byte in the longer string can resolve the comparison
                               2276                 :                :      * against a subsequent terminating NUL in the shorter string.  There will
                               2277                 :                :      * usually be what is effectively a "length-wise" resolution there and
                               2278                 :                :      * then.
                               2279                 :                :      *
                               2280                 :                :      * If that doesn't work out -- if all bytes in the longer string
                               2281                 :                :      * positioned at or past the offset of the smaller string's (first)
                               2282                 :                :      * terminating NUL are actually representative of NUL bytes in the
                               2283                 :                :      * authoritative binary string (perhaps with some *terminating* NUL bytes
                               2284                 :                :      * towards the end of the longer string iff it happens to still be small)
                               2285                 :                :      * -- then an authoritative tie-breaker will happen, and do the right
                               2286                 :                :      * thing: explicitly consider string length.
                               2287                 :                :      */
                               2288         [ +  + ]:         409286 :     if (sss->collate_c)
  416 jdavis@postgresql.or     2289                 :         408389 :         memcpy(pres, authoritative_data, Min(len, max_prefix_bytes));
                               2290                 :                :     else
                               2291                 :                :     {
                               2292                 :                :         Size        bsize;
                               2293                 :                : 
                               2294                 :                :         /*
                               2295                 :                :          * We're not using the C collation, so fall back on strxfrm or ICU
                               2296                 :                :          * analogs.
                               2297                 :                :          */
                               2298                 :                : 
                               2299                 :                :         /* By convention, we use buffer 1 to store and NUL-terminate */
 2993 rhaas@postgresql.org     2300         [ -  + ]:            897 :         if (len >= sss->buflen1)
                               2301                 :                :         {
 2993 rhaas@postgresql.org     2302         [ #  # ]:LBC         (4) :             sss->buflen1 = Max(len + 1, Min(sss->buflen1 * 2, MaxAllocSize));
  609 tgl@sss.pgh.pa.us        2303                 :            (4) :             sss->buf1 = repalloc(sss->buf1, sss->buflen1);
                               2304                 :                :         }
                               2305                 :                : 
                               2306                 :                :         /* Might be able to reuse strxfrm() blob from last call */
 2993 rhaas@postgresql.org     2307   [ +  +  +  - ]:CBC         897 :         if (sss->last_len1 == len && sss->cache_blob &&
                               2308         [ +  + ]:            462 :             memcmp(sss->buf1, authoritative_data, len) == 0)
                               2309                 :                :         {
  416 jdavis@postgresql.or     2310                 :             84 :             memcpy(pres, sss->buf2, Min(max_prefix_bytes, sss->last_len2));
                               2311                 :                :             /* No change affecting cardinality, so no hashing required */
 3110 rhaas@postgresql.org     2312                 :             84 :             goto done;
                               2313                 :                :         }
                               2314                 :                : 
 2993                          2315                 :            813 :         memcpy(sss->buf1, authoritative_data, len);
                               2316                 :                : 
                               2317                 :                :         /*
                               2318                 :                :          * pg_strxfrm() and pg_strxfrm_prefix expect NUL-terminated strings.
                               2319                 :                :          */
                               2320                 :            813 :         sss->buf1[len] = '\0';
                               2321                 :            813 :         sss->last_len1 = len;
                               2322                 :                : 
  416 jdavis@postgresql.or     2323         [ +  - ]:            813 :         if (pg_strxfrm_prefix_enabled(sss->locale))
                               2324                 :                :         {
                               2325         [ -  + ]:            813 :             if (sss->buflen2 < max_prefix_bytes)
                               2326                 :                :             {
  416 jdavis@postgresql.or     2327         [ #  # ]:UBC           0 :                 sss->buflen2 = Max(max_prefix_bytes,
                               2328                 :                :                                    Min(sss->buflen2 * 2, MaxAllocSize));
                               2329                 :              0 :                 sss->buf2 = repalloc(sss->buf2, sss->buflen2);
                               2330                 :                :             }
                               2331                 :                : 
  416 jdavis@postgresql.or     2332                 :CBC         813 :             bsize = pg_strxfrm_prefix(sss->buf2, sss->buf1,
                               2333                 :                :                                       max_prefix_bytes, sss->locale);
  386                          2334                 :            813 :             sss->last_len2 = bsize;
                               2335                 :                :         }
                               2336                 :                :         else
                               2337                 :                :         {
                               2338                 :                :             /*
                               2339                 :                :              * Loop: Call pg_strxfrm(), possibly enlarge buffer, and try
                               2340                 :                :              * again.  The pg_strxfrm() function leaves the result buffer
                               2341                 :                :              * content undefined if the result did not fit, so we need to
                               2342                 :                :              * retry until everything fits, even though we only need the first
                               2343                 :                :              * few bytes in the end.
                               2344                 :                :              */
                               2345                 :                :             for (;;)
                               2346                 :                :             {
  416 jdavis@postgresql.or     2347                 :UBC           0 :                 bsize = pg_strxfrm(sss->buf2, sss->buf1, sss->buflen2,
                               2348                 :                :                                    sss->locale);
                               2349                 :                : 
                               2350                 :              0 :                 sss->last_len2 = bsize;
                               2351         [ #  # ]:              0 :                 if (bsize < sss->buflen2)
                               2352                 :              0 :                     break;
                               2353                 :                : 
                               2354                 :                :                 /*
                               2355                 :                :                  * Grow buffer and retry.
                               2356                 :                :                  */
                               2357         [ #  # ]:              0 :                 sss->buflen2 = Max(bsize + 1,
                               2358                 :                :                                    Min(sss->buflen2 * 2, MaxAllocSize));
                               2359                 :              0 :                 sss->buf2 = repalloc(sss->buf2, sss->buflen2);
                               2360                 :                :             }
                               2361                 :                :         }
                               2362                 :                : 
                               2363                 :                :         /*
                               2364                 :                :          * Every Datum byte is always compared.  This is safe because the
                               2365                 :                :          * strxfrm() blob is itself NUL terminated, leaving no danger of
                               2366                 :                :          * misinterpreting any NUL bytes not intended to be interpreted as
                               2367                 :                :          * logically representing termination.
                               2368                 :                :          *
                               2369                 :                :          * (Actually, even if there were NUL bytes in the blob it would be
                               2370                 :                :          * okay.  See remarks on bytea case above.)
                               2371                 :                :          */
  416 jdavis@postgresql.or     2372                 :CBC         813 :         memcpy(pres, sss->buf2, Min(max_prefix_bytes, bsize));
                               2373                 :                :     }
                               2374                 :                : 
                               2375                 :                :     /*
                               2376                 :                :      * Maintain approximate cardinality of both abbreviated keys and original,
                               2377                 :                :      * authoritative keys using HyperLogLog.  Used as cheap insurance against
                               2378                 :                :      * the worst case, where we do many string transformations for no saving
                               2379                 :                :      * in full strcoll()-based comparisons.  These statistics are used by
                               2380                 :                :      * varstr_abbrev_abort().
                               2381                 :                :      *
                               2382                 :                :      * First, Hash key proper, or a significant fraction of it.  Mix in length
                               2383                 :                :      * in order to compensate for cases where differences are past
                               2384                 :                :      * PG_CACHE_LINE_SIZE bytes, so as to limit the overhead of hashing.
                               2385                 :                :      */
 3300 rhaas@postgresql.org     2386                 :         409202 :     hash = DatumGetUInt32(hash_any((unsigned char *) authoritative_data,
                               2387                 :                :                                    Min(len, PG_CACHE_LINE_SIZE)));
                               2388                 :                : 
 3373                          2389         [ +  + ]:         409202 :     if (len > PG_CACHE_LINE_SIZE)
                               2390                 :             76 :         hash ^= DatumGetUInt32(hash_uint32((uint32) len));
                               2391                 :                : 
 2993                          2392                 :         409202 :     addHyperLogLog(&sss->full_card, hash);
                               2393                 :                : 
                               2394                 :                :     /* Hash abbreviated key */
                               2395                 :                : #if SIZEOF_DATUM == 8
                               2396                 :                :     {
                               2397                 :                :         uint32      lohalf,
                               2398                 :                :                     hihalf;
                               2399                 :                : 
 3373                          2400                 :         409202 :         lohalf = (uint32) res;
                               2401                 :         409202 :         hihalf = (uint32) (res >> 32);
 3300                          2402                 :         409202 :         hash = DatumGetUInt32(hash_uint32(lohalf ^ hihalf));
                               2403                 :                :     }
                               2404                 :                : #else                           /* SIZEOF_DATUM != 8 */
                               2405                 :                :     hash = DatumGetUInt32(hash_uint32((uint32) res));
                               2406                 :                : #endif
                               2407                 :                : 
 2993                          2408                 :         409202 :     addHyperLogLog(&sss->abbr_card, hash);
                               2409                 :                : 
                               2410                 :                :     /* Cache result, perhaps saving an expensive strxfrm() call next time */
                               2411                 :         409202 :     sss->cache_blob = true;
 3110                          2412                 :         409286 : done:
                               2413                 :                : 
                               2414                 :                :     /*
                               2415                 :                :      * Byteswap on little-endian machines.
                               2416                 :                :      *
                               2417                 :                :      * This is needed so that ssup_datum_unsigned_cmp() (an unsigned integer
                               2418                 :                :      * 3-way comparator) works correctly on all platforms.  If we didn't do
                               2419                 :                :      * this, the comparator would have to call memcmp() with a pair of
                               2420                 :                :      * pointers to the first byte of each abbreviated key, which is slower.
                               2421                 :                :      */
                               2422                 :         409286 :     res = DatumBigEndianToNative(res);
                               2423                 :                : 
                               2424                 :                :     /* Don't leak memory here */
 3212                          2425         [ +  + ]:         409286 :     if (PointerGetDatum(authoritative) != original)
                               2426                 :              2 :         pfree(authoritative);
                               2427                 :                : 
 3373                          2428                 :         409286 :     return res;
                               2429                 :                : }
                               2430                 :                : 
                               2431                 :                : /*
                               2432                 :                :  * Callback for estimating effectiveness of abbreviated key optimization, using
                               2433                 :                :  * heuristic rules.  Returns value indicating if the abbreviation optimization
                               2434                 :                :  * should be aborted, based on its projected effectiveness.
                               2435                 :                :  */
                               2436                 :                : static bool
 2993                          2437                 :           1073 : varstr_abbrev_abort(int memtupcount, SortSupport ssup)
                               2438                 :                : {
 2988 tgl@sss.pgh.pa.us        2439                 :           1073 :     VarStringSortSupport *sss = (VarStringSortSupport *) ssup->ssup_extra;
                               2440                 :                :     double      abbrev_distinct,
                               2441                 :                :                 key_distinct;
                               2442                 :                : 
 3373 rhaas@postgresql.org     2443         [ -  + ]:           1073 :     Assert(ssup->abbreviate);
                               2444                 :                : 
                               2445                 :                :     /* Have a little patience */
 3299                          2446         [ +  + ]:           1073 :     if (memtupcount < 100)
 3373                          2447                 :            586 :         return false;
                               2448                 :                : 
 2993                          2449                 :            487 :     abbrev_distinct = estimateHyperLogLog(&sss->abbr_card);
                               2450                 :            487 :     key_distinct = estimateHyperLogLog(&sss->full_card);
                               2451                 :                : 
                               2452                 :                :     /*
                               2453                 :                :      * Clamp cardinality estimates to at least one distinct value.  While
                               2454                 :                :      * NULLs are generally disregarded, if only NULL values were seen so far,
                               2455                 :                :      * that might misrepresent costs if we failed to clamp.
                               2456                 :                :      */
 3373                          2457         [ -  + ]:            487 :     if (abbrev_distinct <= 1.0)
 3373 rhaas@postgresql.org     2458                 :UBC           0 :         abbrev_distinct = 1.0;
                               2459                 :                : 
 3373 rhaas@postgresql.org     2460         [ -  + ]:CBC         487 :     if (key_distinct <= 1.0)
 3373 rhaas@postgresql.org     2461                 :UBC           0 :         key_distinct = 1.0;
                               2462                 :                : 
                               2463                 :                :     /*
                               2464                 :                :      * In the worst case all abbreviated keys are identical, while at the same
                               2465                 :                :      * time there are differences within full key strings not captured in
                               2466                 :                :      * abbreviations.
                               2467                 :                :      */
                               2468                 :                : #ifdef TRACE_SORT
 3295 rhaas@postgresql.org     2469         [ -  + ]:CBC         487 :     if (trace_sort)
                               2470                 :                :     {
 3249 bruce@momjian.us         2471                 :UBC           0 :         double      norm_abbrev_card = abbrev_distinct / (double) memtupcount;
                               2472                 :                : 
 2993 rhaas@postgresql.org     2473         [ #  # ]:              0 :         elog(LOG, "varstr_abbrev: abbrev_distinct after %d: %f "
                               2474                 :                :              "(key_distinct: %f, norm_abbrev_card: %f, prop_card: %f)",
                               2475                 :                :              memtupcount, abbrev_distinct, key_distinct, norm_abbrev_card,
                               2476                 :                :              sss->prop_card);
                               2477                 :                :     }
                               2478                 :                : #endif
                               2479                 :                : 
                               2480                 :                :     /*
                               2481                 :                :      * If the number of distinct abbreviated keys approximately matches the
                               2482                 :                :      * number of distinct authoritative original keys, that's reason enough to
                               2483                 :                :      * proceed.  We can win even with a very low cardinality set if most
                               2484                 :                :      * tie-breakers only memcmp().  This is by far the most important
                               2485                 :                :      * consideration.
                               2486                 :                :      *
                               2487                 :                :      * While comparisons that are resolved at the abbreviated key level are
                               2488                 :                :      * considerably cheaper than tie-breakers resolved with memcmp(), both of
                               2489                 :                :      * those two outcomes are so much cheaper than a full strcoll() once
                               2490                 :                :      * sorting is underway that it doesn't seem worth it to weigh abbreviated
                               2491                 :                :      * cardinality against the overall size of the set in order to more
                               2492                 :                :      * accurately model costs.  Assume that an abbreviated comparison, and an
                               2493                 :                :      * abbreviated comparison with a cheap memcmp()-based authoritative
                               2494                 :                :      * resolution are equivalent.
                               2495                 :                :      */
 2993 rhaas@postgresql.org     2496         [ +  - ]:CBC         487 :     if (abbrev_distinct > key_distinct * sss->prop_card)
                               2497                 :                :     {
                               2498                 :                :         /*
                               2499                 :                :          * When we have exceeded 10,000 tuples, decay required cardinality
                               2500                 :                :          * aggressively for next call.
                               2501                 :                :          *
                               2502                 :                :          * This is useful because the number of comparisons required on
                               2503                 :                :          * average increases at a linearithmic rate, and at roughly 10,000
                               2504                 :                :          * tuples that factor will start to dominate over the linear costs of
                               2505                 :                :          * string transformation (this is a conservative estimate).  The decay
                               2506                 :                :          * rate is chosen to be a little less aggressive than halving -- which
                               2507                 :                :          * (since we're called at points at which memtupcount has doubled)
                               2508                 :                :          * would never see the cost model actually abort past the first call
                               2509                 :                :          * following a decay.  This decay rate is mostly a precaution against
                               2510                 :                :          * a sudden, violent swing in how well abbreviated cardinality tracks
                               2511                 :                :          * full key cardinality.  The decay also serves to prevent a marginal
                               2512                 :                :          * case from being aborted too late, when too much has already been
                               2513                 :                :          * invested in string transformation.
                               2514                 :                :          *
                               2515                 :                :          * It's possible for sets of several million distinct strings with
                               2516                 :                :          * mere tens of thousands of distinct abbreviated keys to still
                               2517                 :                :          * benefit very significantly.  This will generally occur provided
                               2518                 :                :          * each abbreviated key is a proxy for a roughly uniform number of the
                               2519                 :                :          * set's full keys. If it isn't so, we hope to catch that early and
                               2520                 :                :          * abort.  If it isn't caught early, by the time the problem is
                               2521                 :                :          * apparent it's probably not worth aborting.
                               2522                 :                :          */
 3299                          2523         [ +  + ]:            487 :         if (memtupcount > 10000)
 2993                          2524                 :              2 :             sss->prop_card *= 0.65;
                               2525                 :                : 
 3373                          2526                 :            487 :         return false;
                               2527                 :                :     }
                               2528                 :                : 
                               2529                 :                :     /*
                               2530                 :                :      * Abort abbreviation strategy.
                               2531                 :                :      *
                               2532                 :                :      * The worst case, where all abbreviated keys are identical while all
                               2533                 :                :      * original strings differ will typically only see a regression of about
                               2534                 :                :      * 10% in execution time for small to medium sized lists of strings.
                               2535                 :                :      * Whereas on modern CPUs where cache stalls are the dominant cost, we can
                               2536                 :                :      * often expect very large improvements, particularly with sets of strings
                               2537                 :                :      * of moderately high to high abbreviated cardinality.  There is little to
                               2538                 :                :      * lose but much to gain, which our strategy reflects.
                               2539                 :                :      */
                               2540                 :                : #ifdef TRACE_SORT
 3295 rhaas@postgresql.org     2541         [ #  # ]:UBC           0 :     if (trace_sort)
 2993                          2542         [ #  # ]:              0 :         elog(LOG, "varstr_abbrev: aborted abbreviation at %d "
                               2543                 :                :              "(abbrev_distinct: %f, key_distinct: %f, prop_card: %f)",
                               2544                 :                :              memtupcount, abbrev_distinct, key_distinct, sss->prop_card);
                               2545                 :                : #endif
                               2546                 :                : 
 3373                          2547                 :              0 :     return true;
                               2548                 :                : }
                               2549                 :                : 
                               2550                 :                : /*
                               2551                 :                :  * Generic equalimage support function for character type's operator classes.
                               2552                 :                :  * Disables the use of deduplication with nondeterministic collations.
                               2553                 :                :  */
                               2554                 :                : Datum
 1509 pg@bowt.ie               2555                 :CBC        3935 : btvarstrequalimage(PG_FUNCTION_ARGS)
                               2556                 :                : {
                               2557                 :                :     /* Oid      opcintype = PG_GETARG_OID(0); */
                               2558                 :           3935 :     Oid         collid = PG_GET_COLLATION();
                               2559                 :                : 
                               2560                 :           3935 :     check_collation_set(collid);
                               2561                 :                : 
                               2562   [ +  +  +  + ]:           3935 :     if (lc_collate_is_c(collid) ||
                               2563         [ +  + ]:             22 :         collid == DEFAULT_COLLATION_OID ||
                               2564                 :             22 :         get_collation_isdeterministic(collid))
                               2565                 :           3925 :         PG_RETURN_BOOL(true);
                               2566                 :                :     else
                               2567                 :             10 :         PG_RETURN_BOOL(false);
                               2568                 :                : }
                               2569                 :                : 
                               2570                 :                : Datum
 8683 tgl@sss.pgh.pa.us        2571                 :         114780 : text_larger(PG_FUNCTION_ARGS)
                               2572                 :                : {
 6218                          2573                 :         114780 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               2574                 :         114780 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               2575                 :                :     text       *result;
                               2576                 :                : 
 4814 peter_e@gmx.net          2577         [ +  + ]:         114780 :     result = ((text_cmp(arg1, arg2, PG_GET_COLLATION()) > 0) ? arg1 : arg2);
                               2578                 :                : 
 8683 tgl@sss.pgh.pa.us        2579                 :         114780 :     PG_RETURN_TEXT_P(result);
                               2580                 :                : }
                               2581                 :                : 
                               2582                 :                : Datum
                               2583                 :          43038 : text_smaller(PG_FUNCTION_ARGS)
                               2584                 :                : {
 6218                          2585                 :          43038 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               2586                 :          43038 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               2587                 :                :     text       *result;
                               2588                 :                : 
 4814 peter_e@gmx.net          2589         [ +  + ]:          43038 :     result = ((text_cmp(arg1, arg2, PG_GET_COLLATION()) < 0) ? arg1 : arg2);
                               2590                 :                : 
 8683 tgl@sss.pgh.pa.us        2591                 :          43038 :     PG_RETURN_TEXT_P(result);
                               2592                 :                : }
                               2593                 :                : 
                               2594                 :                : 
                               2595                 :                : /*
                               2596                 :                :  * Cross-type comparison functions for types text and name.
                               2597                 :                :  */
                               2598                 :                : 
                               2599                 :                : Datum
 1943                          2600                 :         115743 : nameeqtext(PG_FUNCTION_ARGS)
                               2601                 :                : {
                               2602                 :         115743 :     Name        arg1 = PG_GETARG_NAME(0);
                               2603                 :         115743 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               2604                 :         115743 :     size_t      len1 = strlen(NameStr(*arg1));
                               2605   [ -  +  -  -  :         115743 :     size_t      len2 = VARSIZE_ANY_EXHDR(arg2);
                                     -  -  -  -  -  
                                                 + ]
 1850 peter@eisentraut.org     2606                 :         115743 :     Oid         collid = PG_GET_COLLATION();
                               2607                 :                :     bool        result;
                               2608                 :                : 
                               2609                 :         115743 :     check_collation_set(collid);
                               2610                 :                : 
                               2611         [ +  + ]:         115743 :     if (collid == C_COLLATION_OID)
                               2612         [ +  + ]:         161317 :         result = (len1 == len2 &&
                               2613   [ -  +  +  + ]:          67277 :                   memcmp(NameStr(*arg1), VARDATA_ANY(arg2), len1) == 0);
                               2614                 :                :     else
 1850 peter@eisentraut.org     2615                 :UBC           0 :         result = (varstr_cmp(NameStr(*arg1), len1,
 1850 peter@eisentraut.org     2616         [ -  + ]:CBC       21703 :                              VARDATA_ANY(arg2), len2,
                               2617                 :                :                              collid) == 0);
                               2618                 :                : 
 1943 tgl@sss.pgh.pa.us        2619         [ -  + ]:         115743 :     PG_FREE_IF_COPY(arg2, 1);
                               2620                 :                : 
                               2621                 :         115743 :     PG_RETURN_BOOL(result);
                               2622                 :                : }
                               2623                 :                : 
                               2624                 :                : Datum
                               2625                 :           3672 : texteqname(PG_FUNCTION_ARGS)
                               2626                 :                : {
                               2627                 :           3672 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               2628                 :           3672 :     Name        arg2 = PG_GETARG_NAME(1);
                               2629   [ -  +  -  -  :           3672 :     size_t      len1 = VARSIZE_ANY_EXHDR(arg1);
                                     -  -  -  -  +  
                                                 + ]
                               2630                 :           3672 :     size_t      len2 = strlen(NameStr(*arg2));
 1850 peter@eisentraut.org     2631                 :           3672 :     Oid         collid = PG_GET_COLLATION();
                               2632                 :                :     bool        result;
                               2633                 :                : 
                               2634                 :           3672 :     check_collation_set(collid);
                               2635                 :                : 
                               2636         [ +  + ]:           3672 :     if (collid == C_COLLATION_OID)
                               2637         [ +  + ]:            282 :         result = (len1 == len2 &&
                               2638   [ +  +  +  - ]:             90 :                   memcmp(VARDATA_ANY(arg1), NameStr(*arg2), len1) == 0);
                               2639                 :                :     else
 1850 peter@eisentraut.org     2640                 :UBC           0 :         result = (varstr_cmp(VARDATA_ANY(arg1), len1,
 1850 peter@eisentraut.org     2641         [ -  + ]:CBC        3480 :                              NameStr(*arg2), len2,
                               2642                 :                :                              collid) == 0);
                               2643                 :                : 
 1943 tgl@sss.pgh.pa.us        2644         [ -  + ]:           3672 :     PG_FREE_IF_COPY(arg1, 0);
                               2645                 :                : 
                               2646                 :           3672 :     PG_RETURN_BOOL(result);
                               2647                 :                : }
                               2648                 :                : 
                               2649                 :                : Datum
                               2650                 :             18 : namenetext(PG_FUNCTION_ARGS)
                               2651                 :                : {
                               2652                 :             18 :     Name        arg1 = PG_GETARG_NAME(0);
                               2653                 :             18 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               2654                 :             18 :     size_t      len1 = strlen(NameStr(*arg1));
                               2655   [ -  +  -  -  :             18 :     size_t      len2 = VARSIZE_ANY_EXHDR(arg2);
                                     -  -  -  -  -  
                                                 + ]
 1850 peter@eisentraut.org     2656                 :             18 :     Oid         collid = PG_GET_COLLATION();
                               2657                 :                :     bool        result;
                               2658                 :                : 
                               2659                 :             18 :     check_collation_set(collid);
                               2660                 :                : 
                               2661         [ +  + ]:             18 :     if (collid == C_COLLATION_OID)
                               2662         [ -  + ]:              9 :         result = !(len1 == len2 &&
 1850 peter@eisentraut.org     2663   [ #  #  #  # ]:UBC           0 :                    memcmp(NameStr(*arg1), VARDATA_ANY(arg2), len1) == 0);
                               2664                 :                :     else
                               2665                 :              0 :         result = !(varstr_cmp(NameStr(*arg1), len1,
 1850 peter@eisentraut.org     2666         [ -  + ]:CBC           9 :                               VARDATA_ANY(arg2), len2,
                               2667                 :                :                               collid) == 0);
                               2668                 :                : 
 1943 tgl@sss.pgh.pa.us        2669         [ -  + ]:             18 :     PG_FREE_IF_COPY(arg2, 1);
                               2670                 :                : 
                               2671                 :             18 :     PG_RETURN_BOOL(result);
                               2672                 :                : }
                               2673                 :                : 
                               2674                 :                : Datum
                               2675                 :              9 : textnename(PG_FUNCTION_ARGS)
                               2676                 :                : {
                               2677                 :              9 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               2678                 :              9 :     Name        arg2 = PG_GETARG_NAME(1);
                               2679   [ -  +  -  -  :              9 :     size_t      len1 = VARSIZE_ANY_EXHDR(arg1);
                                     -  -  -  -  -  
                                                 + ]
                               2680                 :              9 :     size_t      len2 = strlen(NameStr(*arg2));
 1850 peter@eisentraut.org     2681                 :              9 :     Oid         collid = PG_GET_COLLATION();
                               2682                 :                :     bool        result;
                               2683                 :                : 
                               2684                 :              9 :     check_collation_set(collid);
                               2685                 :                : 
                               2686         [ -  + ]:              9 :     if (collid == C_COLLATION_OID)
 1850 peter@eisentraut.org     2687         [ #  # ]:UBC           0 :         result = !(len1 == len2 &&
                               2688   [ #  #  #  # ]:              0 :                    memcmp(VARDATA_ANY(arg1), NameStr(*arg2), len1) == 0);
                               2689                 :                :     else
                               2690                 :              0 :         result = !(varstr_cmp(VARDATA_ANY(arg1), len1,
 1850 peter@eisentraut.org     2691         [ -  + ]:CBC           9 :                               NameStr(*arg2), len2,
                               2692                 :                :                               collid) == 0);
                               2693                 :                : 
 1943 tgl@sss.pgh.pa.us        2694         [ -  + ]:              9 :     PG_FREE_IF_COPY(arg1, 0);
                               2695                 :                : 
                               2696                 :              9 :     PG_RETURN_BOOL(result);
                               2697                 :                : }
                               2698                 :                : 
                               2699                 :                : Datum
                               2700                 :         100093 : btnametextcmp(PG_FUNCTION_ARGS)
                               2701                 :                : {
                               2702                 :         100093 :     Name        arg1 = PG_GETARG_NAME(0);
                               2703                 :         100093 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               2704                 :                :     int32       result;
                               2705                 :                : 
 1943 tgl@sss.pgh.pa.us        2706                 :UBC           0 :     result = varstr_cmp(NameStr(*arg1), strlen(NameStr(*arg1)),
 1943 tgl@sss.pgh.pa.us        2707   [ -  +  -  -  :CBC      200186 :                         VARDATA_ANY(arg2), VARSIZE_ANY_EXHDR(arg2),
                                     -  -  -  -  -  
                                           +  -  + ]
                               2708                 :                :                         PG_GET_COLLATION());
                               2709                 :                : 
                               2710         [ -  + ]:         100093 :     PG_FREE_IF_COPY(arg2, 1);
                               2711                 :                : 
                               2712                 :         100093 :     PG_RETURN_INT32(result);
                               2713                 :                : }
                               2714                 :                : 
                               2715                 :                : Datum
 1943 tgl@sss.pgh.pa.us        2716                 :UBC           0 : bttextnamecmp(PG_FUNCTION_ARGS)
                               2717                 :                : {
                               2718                 :              0 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               2719                 :              0 :     Name        arg2 = PG_GETARG_NAME(1);
                               2720                 :                :     int32       result;
                               2721                 :                : 
                               2722   [ #  #  #  #  :              0 :     result = varstr_cmp(VARDATA_ANY(arg1), VARSIZE_ANY_EXHDR(arg1),
                                     #  #  #  #  #  
                                                 # ]
                               2723         [ #  # ]:              0 :                         NameStr(*arg2), strlen(NameStr(*arg2)),
                               2724                 :                :                         PG_GET_COLLATION());
                               2725                 :                : 
                               2726         [ #  # ]:              0 :     PG_FREE_IF_COPY(arg1, 0);
                               2727                 :                : 
                               2728                 :              0 :     PG_RETURN_INT32(result);
                               2729                 :                : }
                               2730                 :                : 
                               2731                 :                : #define CmpCall(cmpfunc) \
                               2732                 :                :     DatumGetInt32(DirectFunctionCall2Coll(cmpfunc, \
                               2733                 :                :                                           PG_GET_COLLATION(), \
                               2734                 :                :                                           PG_GETARG_DATUM(0), \
                               2735                 :                :                                           PG_GETARG_DATUM(1)))
                               2736                 :                : 
                               2737                 :                : Datum
 1943 tgl@sss.pgh.pa.us        2738                 :CBC       39656 : namelttext(PG_FUNCTION_ARGS)
                               2739                 :                : {
                               2740                 :          39656 :     PG_RETURN_BOOL(CmpCall(btnametextcmp) < 0);
                               2741                 :                : }
                               2742                 :                : 
                               2743                 :                : Datum
 1943 tgl@sss.pgh.pa.us        2744                 :UBC           0 : nameletext(PG_FUNCTION_ARGS)
                               2745                 :                : {
                               2746                 :              0 :     PG_RETURN_BOOL(CmpCall(btnametextcmp) <= 0);
                               2747                 :                : }
                               2748                 :                : 
                               2749                 :                : Datum
                               2750                 :              0 : namegttext(PG_FUNCTION_ARGS)
                               2751                 :                : {
                               2752                 :              0 :     PG_RETURN_BOOL(CmpCall(btnametextcmp) > 0);
                               2753                 :                : }
                               2754                 :                : 
                               2755                 :                : Datum
 1943 tgl@sss.pgh.pa.us        2756                 :CBC       29139 : namegetext(PG_FUNCTION_ARGS)
                               2757                 :                : {
                               2758                 :          29139 :     PG_RETURN_BOOL(CmpCall(btnametextcmp) >= 0);
                               2759                 :                : }
                               2760                 :                : 
                               2761                 :                : Datum
 1943 tgl@sss.pgh.pa.us        2762                 :UBC           0 : textltname(PG_FUNCTION_ARGS)
                               2763                 :                : {
                               2764                 :              0 :     PG_RETURN_BOOL(CmpCall(bttextnamecmp) < 0);
                               2765                 :                : }
                               2766                 :                : 
                               2767                 :                : Datum
                               2768                 :              0 : textlename(PG_FUNCTION_ARGS)
                               2769                 :                : {
                               2770                 :              0 :     PG_RETURN_BOOL(CmpCall(bttextnamecmp) <= 0);
                               2771                 :                : }
                               2772                 :                : 
                               2773                 :                : Datum
                               2774                 :              0 : textgtname(PG_FUNCTION_ARGS)
                               2775                 :                : {
                               2776                 :              0 :     PG_RETURN_BOOL(CmpCall(bttextnamecmp) > 0);
                               2777                 :                : }
                               2778                 :                : 
                               2779                 :                : Datum
                               2780                 :              0 : textgename(PG_FUNCTION_ARGS)
                               2781                 :                : {
                               2782                 :              0 :     PG_RETURN_BOOL(CmpCall(bttextnamecmp) >= 0);
                               2783                 :                : }
                               2784                 :                : 
                               2785                 :                : #undef CmpCall
                               2786                 :                : 
                               2787                 :                : 
                               2788                 :                : /*
                               2789                 :                :  * The following operators support character-by-character comparison
                               2790                 :                :  * of text datums, to allow building indexes suitable for LIKE clauses.
                               2791                 :                :  * Note that the regular texteq/textne comparison operators, and regular
                               2792                 :                :  * support functions 1 and 2 with "C" collation are assumed to be
                               2793                 :                :  * compatible with these!
                               2794                 :                :  */
                               2795                 :                : 
                               2796                 :                : static int
 1667 tgl@sss.pgh.pa.us        2797                 :CBC       76484 : internal_text_pattern_compare(text *arg1, text *arg2)
                               2798                 :                : {
                               2799                 :                :     int         result;
                               2800                 :                :     int         len1,
                               2801                 :                :                 len2;
                               2802                 :                : 
 5801                          2803   [ -  +  -  -  :          76484 :     len1 = VARSIZE_ANY_EXHDR(arg1);
                                     -  -  -  -  +  
                                                 + ]
                               2804   [ -  +  -  -  :          76484 :     len2 = VARSIZE_ANY_EXHDR(arg2);
                                     -  -  -  -  -  
                                                 + ]
                               2805                 :                : 
 4863 rhaas@postgresql.org     2806   [ -  +  +  + ]:          76484 :     result = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
 7640 peter_e@gmx.net          2807         [ +  + ]:          76484 :     if (result != 0)
                               2808                 :          76442 :         return result;
 5801 tgl@sss.pgh.pa.us        2809         [ -  + ]:             42 :     else if (len1 < len2)
 7640 peter_e@gmx.net          2810                 :UBC           0 :         return -1;
 5801 tgl@sss.pgh.pa.us        2811         [ +  + ]:CBC          42 :     else if (len1 > len2)
 7640 peter_e@gmx.net          2812                 :             18 :         return 1;
                               2813                 :                :     else
                               2814                 :             24 :         return 0;
                               2815                 :                : }
                               2816                 :                : 
                               2817                 :                : 
                               2818                 :                : Datum
                               2819                 :          20195 : text_pattern_lt(PG_FUNCTION_ARGS)
                               2820                 :                : {
 6218 tgl@sss.pgh.pa.us        2821                 :          20195 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               2822                 :          20195 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               2823                 :                :     int         result;
                               2824                 :                : 
 1667                          2825                 :          20195 :     result = internal_text_pattern_compare(arg1, arg2);
                               2826                 :                : 
 7640 peter_e@gmx.net          2827         [ -  + ]:          20195 :     PG_FREE_IF_COPY(arg1, 0);
                               2828         [ -  + ]:          20195 :     PG_FREE_IF_COPY(arg2, 1);
                               2829                 :                : 
                               2830                 :          20195 :     PG_RETURN_BOOL(result < 0);
                               2831                 :                : }
                               2832                 :                : 
                               2833                 :                : 
                               2834                 :                : Datum
                               2835                 :          18755 : text_pattern_le(PG_FUNCTION_ARGS)
                               2836                 :                : {
 6218 tgl@sss.pgh.pa.us        2837                 :          18755 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               2838                 :          18755 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               2839                 :                :     int         result;
                               2840                 :                : 
 1667                          2841                 :          18755 :     result = internal_text_pattern_compare(arg1, arg2);
                               2842                 :                : 
 7640 peter_e@gmx.net          2843         [ -  + ]:          18755 :     PG_FREE_IF_COPY(arg1, 0);
                               2844         [ -  + ]:          18755 :     PG_FREE_IF_COPY(arg2, 1);
                               2845                 :                : 
                               2846                 :          18755 :     PG_RETURN_BOOL(result <= 0);
                               2847                 :                : }
                               2848                 :                : 
                               2849                 :                : 
                               2850                 :                : Datum
                               2851                 :          18767 : text_pattern_ge(PG_FUNCTION_ARGS)
                               2852                 :                : {
 6218 tgl@sss.pgh.pa.us        2853                 :          18767 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               2854                 :          18767 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               2855                 :                :     int         result;
                               2856                 :                : 
 1667                          2857                 :          18767 :     result = internal_text_pattern_compare(arg1, arg2);
                               2858                 :                : 
 7640 peter_e@gmx.net          2859         [ -  + ]:          18767 :     PG_FREE_IF_COPY(arg1, 0);
                               2860         [ -  + ]:          18767 :     PG_FREE_IF_COPY(arg2, 1);
                               2861                 :                : 
                               2862                 :          18767 :     PG_RETURN_BOOL(result >= 0);
                               2863                 :                : }
                               2864                 :                : 
                               2865                 :                : 
                               2866                 :                : Datum
                               2867                 :          18755 : text_pattern_gt(PG_FUNCTION_ARGS)
                               2868                 :                : {
 6218 tgl@sss.pgh.pa.us        2869                 :          18755 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               2870                 :          18755 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               2871                 :                :     int         result;
                               2872                 :                : 
 1667                          2873                 :          18755 :     result = internal_text_pattern_compare(arg1, arg2);
                               2874                 :                : 
 7640 peter_e@gmx.net          2875         [ -  + ]:          18755 :     PG_FREE_IF_COPY(arg1, 0);
                               2876         [ -  + ]:          18755 :     PG_FREE_IF_COPY(arg2, 1);
                               2877                 :                : 
                               2878                 :          18755 :     PG_RETURN_BOOL(result > 0);
                               2879                 :                : }
                               2880                 :                : 
                               2881                 :                : 
                               2882                 :                : Datum
                               2883                 :             12 : bttext_pattern_cmp(PG_FUNCTION_ARGS)
                               2884                 :                : {
 6218 tgl@sss.pgh.pa.us        2885                 :             12 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
                               2886                 :             12 :     text       *arg2 = PG_GETARG_TEXT_PP(1);
                               2887                 :                :     int         result;
                               2888                 :                : 
 1667                          2889                 :             12 :     result = internal_text_pattern_compare(arg1, arg2);
                               2890                 :                : 
 7640 peter_e@gmx.net          2891         [ -  + ]:             12 :     PG_FREE_IF_COPY(arg1, 0);
                               2892         [ -  + ]:             12 :     PG_FREE_IF_COPY(arg2, 1);
                               2893                 :                : 
                               2894                 :             12 :     PG_RETURN_INT32(result);
                               2895                 :                : }
                               2896                 :                : 
                               2897                 :                : 
                               2898                 :                : Datum
 2993 rhaas@postgresql.org     2899                 :             58 : bttext_pattern_sortsupport(PG_FUNCTION_ARGS)
                               2900                 :                : {
                               2901                 :             58 :     SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
                               2902                 :                :     MemoryContext oldcontext;
                               2903                 :                : 
                               2904                 :             58 :     oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
                               2905                 :                : 
                               2906                 :                :     /* Use generic string SortSupport, forcing "C" collation */
 1943 tgl@sss.pgh.pa.us        2907                 :             58 :     varstr_sortsupport(ssup, TEXTOID, C_COLLATION_OID);
                               2908                 :                : 
 2993 rhaas@postgresql.org     2909                 :             58 :     MemoryContextSwitchTo(oldcontext);
                               2910                 :                : 
                               2911                 :             58 :     PG_RETURN_VOID();
                               2912                 :                : }
                               2913                 :                : 
                               2914                 :                : 
                               2915                 :                : /*-------------------------------------------------------------
                               2916                 :                :  * byteaoctetlen
                               2917                 :                :  *
                               2918                 :                :  * get the number of bytes contained in an instance of type 'bytea'
                               2919                 :                :  *-------------------------------------------------------------
                               2920                 :                :  */
                               2921                 :                : Datum
 8660 tgl@sss.pgh.pa.us        2922                 :            229 : byteaoctetlen(PG_FUNCTION_ARGS)
                               2923                 :                : {
 7379                          2924                 :            229 :     Datum       str = PG_GETARG_DATUM(0);
                               2925                 :                : 
                               2926                 :                :     /* We need not detoast the input at all */
                               2927                 :            229 :     PG_RETURN_INT32(toast_raw_datum_size(str) - VARHDRSZ);
                               2928                 :                : }
                               2929                 :                : 
                               2930                 :                : /*
                               2931                 :                :  * byteacat -
                               2932                 :                :  *    takes two bytea* and returns a bytea* that is the concatenation of
                               2933                 :                :  *    the two.
                               2934                 :                :  *
                               2935                 :                :  * Cloned from textcat and modified as required.
                               2936                 :                :  */
                               2937                 :                : Datum
 8248 bruce@momjian.us         2938                 :            760 : byteacat(PG_FUNCTION_ARGS)
                               2939                 :                : {
 6218 tgl@sss.pgh.pa.us        2940                 :            760 :     bytea      *t1 = PG_GETARG_BYTEA_PP(0);
                               2941                 :            760 :     bytea      *t2 = PG_GETARG_BYTEA_PP(1);
                               2942                 :                : 
 5193                          2943                 :            760 :     PG_RETURN_BYTEA_P(bytea_catenate(t1, t2));
                               2944                 :                : }
                               2945                 :                : 
                               2946                 :                : /*
                               2947                 :                :  * bytea_catenate
                               2948                 :                :  *  Guts of byteacat(), broken out so it can be used by other functions
                               2949                 :                :  *
                               2950                 :                :  * Arguments can be in short-header form, but not compressed or out-of-line
                               2951                 :                :  */
                               2952                 :                : static bytea *
                               2953                 :            778 : bytea_catenate(bytea *t1, bytea *t2)
                               2954                 :                : {
                               2955                 :                :     bytea      *result;
                               2956                 :                :     int         len1,
                               2957                 :                :                 len2,
                               2958                 :                :                 len;
                               2959                 :                :     char       *ptr;
                               2960                 :                : 
 6218                          2961   [ -  +  -  -  :            778 :     len1 = VARSIZE_ANY_EXHDR(t1);
                                     -  -  -  -  +  
                                                 + ]
 5193                          2962   [ -  +  -  -  :            778 :     len2 = VARSIZE_ANY_EXHDR(t2);
                                     -  -  -  -  +  
                                                 + ]
                               2963                 :                : 
                               2964                 :                :     /* paranoia ... probably should throw error instead? */
 8248 bruce@momjian.us         2965         [ -  + ]:            778 :     if (len1 < 0)
 8248 bruce@momjian.us         2966                 :UBC           0 :         len1 = 0;
 8248 bruce@momjian.us         2967         [ -  + ]:CBC         778 :     if (len2 < 0)
 8248 bruce@momjian.us         2968                 :UBC           0 :         len2 = 0;
                               2969                 :                : 
 8248 bruce@momjian.us         2970                 :CBC         778 :     len = len1 + len2 + VARHDRSZ;
                               2971                 :            778 :     result = (bytea *) palloc(len);
                               2972                 :                : 
                               2973                 :                :     /* Set size of result string... */
 6256 tgl@sss.pgh.pa.us        2974                 :            778 :     SET_VARSIZE(result, len);
                               2975                 :                : 
                               2976                 :                :     /* Fill data field of result string... */
 8248 bruce@momjian.us         2977                 :            778 :     ptr = VARDATA(result);
                               2978         [ +  - ]:            778 :     if (len1 > 0)
 6218 tgl@sss.pgh.pa.us        2979         [ +  + ]:            778 :         memcpy(ptr, VARDATA_ANY(t1), len1);
 8248 bruce@momjian.us         2980         [ +  + ]:            778 :     if (len2 > 0)
 6218 tgl@sss.pgh.pa.us        2981         [ +  + ]:            769 :         memcpy(ptr + len1, VARDATA_ANY(t2), len2);
                               2982                 :                : 
 5193                          2983                 :            778 :     return result;
                               2984                 :                : }
                               2985                 :                : 
                               2986                 :                : #define PG_STR_GET_BYTEA(str_) \
                               2987                 :                :     DatumGetByteaPP(DirectFunctionCall1(byteain, CStringGetDatum(str_)))
                               2988                 :                : 
                               2989                 :                : /*
                               2990                 :                :  * bytea_substr()
                               2991                 :                :  * Return a substring starting at the specified position.
                               2992                 :                :  * Cloned from text_substr and modified as required.
                               2993                 :                :  *
                               2994                 :                :  * Input:
                               2995                 :                :  *  - string
                               2996                 :                :  *  - starting position (is one-based)
                               2997                 :                :  *  - string length (optional)
                               2998                 :                :  *
                               2999                 :                :  * If the starting position is zero or less, then return from the start of the string
                               3000                 :                :  * adjusting the length to be consistent with the "negative start" per SQL.
                               3001                 :                :  * If the length is less than zero, an ERROR is thrown. If no third argument
                               3002                 :                :  * (length) is provided, the length to the end of the string is assumed.
                               3003                 :                :  */
                               3004                 :                : Datum
 8248 bruce@momjian.us         3005                 :             43 : bytea_substr(PG_FUNCTION_ARGS)
                               3006                 :                : {
 5193 tgl@sss.pgh.pa.us        3007                 :             43 :     PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
                               3008                 :                :                                       PG_GETARG_INT32(1),
                               3009                 :                :                                       PG_GETARG_INT32(2),
                               3010                 :                :                                       false));
                               3011                 :                : }
                               3012                 :                : 
                               3013                 :                : /*
                               3014                 :                :  * bytea_substr_no_len -
                               3015                 :                :  *    Wrapper to avoid opr_sanity failure due to
                               3016                 :                :  *    one function accepting a different number of args.
                               3017                 :                :  */
                               3018                 :                : Datum
                               3019                 :           1950 : bytea_substr_no_len(PG_FUNCTION_ARGS)
                               3020                 :                : {
                               3021                 :           1950 :     PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
                               3022                 :                :                                       PG_GETARG_INT32(1),
                               3023                 :                :                                       -1,
                               3024                 :                :                                       true));
                               3025                 :                : }
                               3026                 :                : 
                               3027                 :                : static bytea *
                               3028                 :           2011 : bytea_substring(Datum str,
                               3029                 :                :                 int S,
                               3030                 :                :                 int L,
                               3031                 :                :                 bool length_not_specified)
                               3032                 :                : {
                               3033                 :                :     int32       S1;             /* adjusted start position */
                               3034                 :                :     int32       L1;             /* adjusted substring length */
                               3035                 :                :     int32       E;              /* end position */
                               3036                 :                : 
                               3037                 :                :     /*
                               3038                 :                :      * The logic here should generally match text_substring().
                               3039                 :                :      */
 7906 bruce@momjian.us         3040                 :           2011 :     S1 = Max(S, 1);
                               3041                 :                : 
 5193 tgl@sss.pgh.pa.us        3042         [ +  + ]:           2011 :     if (length_not_specified)
                               3043                 :                :     {
                               3044                 :                :         /*
                               3045                 :                :          * Not passed a length - DatumGetByteaPSlice() grabs everything to the
                               3046                 :                :          * end of the string if we pass it a negative value for length.
                               3047                 :                :          */
 7906 bruce@momjian.us         3048                 :           1959 :         L1 = -1;
                               3049                 :                :     }
 1196 tgl@sss.pgh.pa.us        3050         [ +  + ]:             52 :     else if (L < 0)
                               3051                 :                :     {
                               3052                 :                :         /* SQL99 says to throw an error for E < S, i.e., negative length */
                               3053         [ +  - ]:              6 :         ereport(ERROR,
                               3054                 :                :                 (errcode(ERRCODE_SUBSTRING_ERROR),
                               3055                 :                :                  errmsg("negative substring length not allowed")));
                               3056                 :                :         L1 = -1;                /* silence stupider compilers */
                               3057                 :                :     }
                               3058         [ +  + ]:             46 :     else if (pg_add_s32_overflow(S, L, &E))
                               3059                 :                :     {
                               3060                 :                :         /*
                               3061                 :                :          * L could be large enough for S + L to overflow, in which case the
                               3062                 :                :          * substring must run to end of string.
                               3063                 :                :          */
                               3064                 :              3 :         L1 = -1;
                               3065                 :                :     }
                               3066                 :                :     else
                               3067                 :                :     {
                               3068                 :                :         /*
                               3069                 :                :          * A zero or negative value for the end position can happen if the
                               3070                 :                :          * start was negative or one. SQL99 says to return a zero-length
                               3071                 :                :          * string.
                               3072                 :                :          */
 7906 bruce@momjian.us         3073         [ -  + ]:             43 :         if (E < 1)
 5193 tgl@sss.pgh.pa.us        3074                 :UBC           0 :             return PG_STR_GET_BYTEA("");
                               3075                 :                : 
 7906 bruce@momjian.us         3076                 :CBC          43 :         L1 = E - S1;
                               3077                 :                :     }
                               3078                 :                : 
                               3079                 :                :     /*
                               3080                 :                :      * If the start position is past the end of the string, SQL99 says to
                               3081                 :                :      * return a zero-length string -- DatumGetByteaPSlice() will do that for
                               3082                 :                :      * us.  We need only convert S1 to zero-based starting position.
                               3083                 :                :      */
 5193 tgl@sss.pgh.pa.us        3084                 :           2005 :     return DatumGetByteaPSlice(str, S1 - 1, L1);
                               3085                 :                : }
                               3086                 :                : 
                               3087                 :                : /*
                               3088                 :                :  * byteaoverlay
                               3089                 :                :  *  Replace specified substring of first string with second
                               3090                 :                :  *
                               3091                 :                :  * The SQL standard defines OVERLAY() in terms of substring and concatenation.
                               3092                 :                :  * This code is a direct implementation of what the standard says.
                               3093                 :                :  */
                               3094                 :                : Datum
                               3095                 :              3 : byteaoverlay(PG_FUNCTION_ARGS)
                               3096                 :                : {
                               3097                 :              3 :     bytea      *t1 = PG_GETARG_BYTEA_PP(0);
                               3098                 :              3 :     bytea      *t2 = PG_GETARG_BYTEA_PP(1);
 2489                          3099                 :              3 :     int         sp = PG_GETARG_INT32(2);    /* substring start position */
                               3100                 :              3 :     int         sl = PG_GETARG_INT32(3);    /* substring length */
                               3101                 :                : 
 5193                          3102                 :              3 :     PG_RETURN_BYTEA_P(bytea_overlay(t1, t2, sp, sl));
                               3103                 :                : }
                               3104                 :                : 
                               3105                 :                : Datum
                               3106                 :              6 : byteaoverlay_no_len(PG_FUNCTION_ARGS)
                               3107                 :                : {
                               3108                 :              6 :     bytea      *t1 = PG_GETARG_BYTEA_PP(0);
                               3109                 :              6 :     bytea      *t2 = PG_GETARG_BYTEA_PP(1);
 2489                          3110                 :              6 :     int         sp = PG_GETARG_INT32(2);    /* substring start position */
                               3111                 :                :     int         sl;
                               3112                 :                : 
 5161 bruce@momjian.us         3113   [ -  +  -  -  :              6 :     sl = VARSIZE_ANY_EXHDR(t2); /* defaults to length(t2) */
                                     -  -  -  -  -  
                                                 + ]
 5193 tgl@sss.pgh.pa.us        3114                 :              6 :     PG_RETURN_BYTEA_P(bytea_overlay(t1, t2, sp, sl));
                               3115                 :                : }
                               3116                 :                : 
                               3117                 :                : static bytea *
                               3118                 :              9 : bytea_overlay(bytea *t1, bytea *t2, int sp, int sl)
                               3119                 :                : {
                               3120                 :                :     bytea      *result;
                               3121                 :                :     bytea      *s1;
                               3122                 :                :     bytea      *s2;
                               3123                 :                :     int         sp_pl_sl;
                               3124                 :                : 
                               3125                 :                :     /*
                               3126                 :                :      * Check for possible integer-overflow cases.  For negative sp, throw a
                               3127                 :                :      * "substring length" error because that's what should be expected
                               3128                 :                :      * according to the spec's definition of OVERLAY().
                               3129                 :                :      */
                               3130         [ -  + ]:              9 :     if (sp <= 0)
 5193 tgl@sss.pgh.pa.us        3131         [ #  # ]:UBC           0 :         ereport(ERROR,
                               3132                 :                :                 (errcode(ERRCODE_SUBSTRING_ERROR),
                               3133                 :                :                  errmsg("negative substring length not allowed")));
 2315 andres@anarazel.de       3134         [ -  + ]:CBC           9 :     if (pg_add_s32_overflow(sp, sl, &sp_pl_sl))
 5193 tgl@sss.pgh.pa.us        3135         [ #  # ]:UBC           0 :         ereport(ERROR,
                               3136                 :                :                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                               3137                 :                :                  errmsg("integer out of range")));
                               3138                 :                : 
 5161 bruce@momjian.us         3139                 :CBC           9 :     s1 = bytea_substring(PointerGetDatum(t1), 1, sp - 1, false);
 5193 tgl@sss.pgh.pa.us        3140                 :              9 :     s2 = bytea_substring(PointerGetDatum(t1), sp_pl_sl, -1, true);
                               3141                 :              9 :     result = bytea_catenate(s1, t2);
                               3142                 :              9 :     result = bytea_catenate(result, s2);
                               3143                 :                : 
                               3144                 :              9 :     return result;
                               3145                 :                : }
                               3146                 :                : 
                               3147                 :                : /*
                               3148                 :                :  * bit_count
                               3149                 :                :  */
                               3150                 :                : Datum
 1118 peter@eisentraut.org     3151                 :              3 : bytea_bit_count(PG_FUNCTION_ARGS)
                               3152                 :                : {
                               3153                 :              3 :     bytea      *t1 = PG_GETARG_BYTEA_PP(0);
                               3154                 :                : 
                               3155   [ -  +  -  -  :              3 :     PG_RETURN_INT64(pg_popcount(VARDATA_ANY(t1), VARSIZE_ANY_EXHDR(t1)));
                                     -  -  -  -  -  
                                           +  -  + ]
                               3156                 :                : }
                               3157                 :                : 
                               3158                 :                : /*
                               3159                 :                :  * byteapos -
                               3160                 :                :  *    Return the position of the specified substring.
                               3161                 :                :  *    Implements the SQL POSITION() function.
                               3162                 :                :  * Cloned from textpos and modified as required.
                               3163                 :                :  */
                               3164                 :                : Datum
 8248 bruce@momjian.us         3165                 :UBC           0 : byteapos(PG_FUNCTION_ARGS)
                               3166                 :                : {
 6218 tgl@sss.pgh.pa.us        3167                 :              0 :     bytea      *t1 = PG_GETARG_BYTEA_PP(0);
                               3168                 :              0 :     bytea      *t2 = PG_GETARG_BYTEA_PP(1);
                               3169                 :                :     int         pos;
                               3170                 :                :     int         px,
                               3171                 :                :                 p;
                               3172                 :                :     int         len1,
                               3173                 :                :                 len2;
                               3174                 :                :     char       *p1,
                               3175                 :                :                *p2;
                               3176                 :                : 
                               3177   [ #  #  #  #  :              0 :     len1 = VARSIZE_ANY_EXHDR(t1);
                                     #  #  #  #  #  
                                                 # ]
                               3178   [ #  #  #  #  :              0 :     len2 = VARSIZE_ANY_EXHDR(t2);
                                     #  #  #  #  #  
                                                 # ]
                               3179                 :                : 
                               3180         [ #  # ]:              0 :     if (len2 <= 0)
                               3181                 :              0 :         PG_RETURN_INT32(1);     /* result for empty pattern */
                               3182                 :                : 
                               3183         [ #  # ]:              0 :     p1 = VARDATA_ANY(t1);
                               3184         [ #  # ]:              0 :     p2 = VARDATA_ANY(t2);
                               3185                 :                : 
 8248 bruce@momjian.us         3186                 :              0 :     pos = 0;
                               3187                 :              0 :     px = (len1 - len2);
                               3188         [ #  # ]:              0 :     for (p = 0; p <= px; p++)
                               3189                 :                :     {
                               3190   [ #  #  #  # ]:              0 :         if ((*p2 == *p1) && (memcmp(p1, p2, len2) == 0))
                               3191                 :                :         {
                               3192                 :              0 :             pos = p + 1;
                               3193                 :              0 :             break;
                               3194                 :                :         };
                               3195                 :              0 :         p1++;
                               3196                 :                :     };
                               3197                 :                : 
                               3198                 :              0 :     PG_RETURN_INT32(pos);
                               3199                 :                : }
                               3200                 :                : 
                               3201                 :                : /*-------------------------------------------------------------
                               3202                 :                :  * byteaGetByte
                               3203                 :                :  *
                               3204                 :                :  * this routine treats "bytea" as an array of bytes.
                               3205                 :                :  * It returns the Nth byte (a number between 0 and 255).
                               3206                 :                :  *-------------------------------------------------------------
                               3207                 :                :  */
                               3208                 :                : Datum
 8706 tgl@sss.pgh.pa.us        3209                 :CBC          30 : byteaGetByte(PG_FUNCTION_ARGS)
                               3210                 :                : {
 6218                          3211                 :             30 :     bytea      *v = PG_GETARG_BYTEA_PP(0);
 8706                          3212                 :             30 :     int32       n = PG_GETARG_INT32(1);
                               3213                 :                :     int         len;
                               3214                 :                :     int         byte;
                               3215                 :                : 
 6218                          3216   [ -  +  -  -  :             30 :     len = VARSIZE_ANY_EXHDR(v);
                                     -  -  -  -  +  
                                                 + ]
                               3217                 :                : 
 8787                          3218   [ +  -  +  + ]:             30 :     if (n < 0 || n >= len)
 7567                          3219         [ +  - ]:              3 :         ereport(ERROR,
                               3220                 :                :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                               3221                 :                :                  errmsg("index %d out of valid range, 0..%d",
                               3222                 :                :                         n, len - 1)));
                               3223                 :                : 
 6218                          3224         [ +  + ]:             27 :     byte = ((unsigned char *) VARDATA_ANY(v))[n];
                               3225                 :                : 
 8706                          3226                 :             27 :     PG_RETURN_INT32(byte);
                               3227                 :                : }
                               3228                 :                : 
                               3229                 :                : /*-------------------------------------------------------------
                               3230                 :                :  * byteaGetBit
                               3231                 :                :  *
                               3232                 :                :  * This routine treats a "bytea" type like an array of bits.
                               3233                 :                :  * It returns the value of the Nth bit (0 or 1).
                               3234                 :                :  *
                               3235                 :                :  *-------------------------------------------------------------
                               3236                 :                :  */
                               3237                 :                : Datum
                               3238                 :              6 : byteaGetBit(PG_FUNCTION_ARGS)
                               3239                 :                : {
 6218                          3240                 :              6 :     bytea      *v = PG_GETARG_BYTEA_PP(0);
 1468                          3241                 :              6 :     int64       n = PG_GETARG_INT64(1);
                               3242                 :                :     int         byteNo,
                               3243                 :                :                 bitNo;
                               3244                 :                :     int         len;
                               3245                 :                :     int         byte;
                               3246                 :                : 
 6218                          3247   [ -  +  -  -  :              6 :     len = VARSIZE_ANY_EXHDR(v);
                                     -  -  -  -  -  
                                                 + ]
                               3248                 :                : 
 1468                          3249   [ +  -  +  + ]:              6 :     if (n < 0 || n >= (int64) len * 8)
 7567                          3250         [ +  - ]:              3 :         ereport(ERROR,
                               3251                 :                :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                               3252                 :                :                  errmsg("index %lld out of valid range, 0..%lld",
                               3253                 :                :                         (long long) n, (long long) len * 8 - 1)));
                               3254                 :                : 
                               3255                 :                :     /* n/8 is now known < len, so safe to cast to int */
 1468                          3256                 :              3 :     byteNo = (int) (n / 8);
                               3257                 :              3 :     bitNo = (int) (n % 8);
                               3258                 :                : 
 6218                          3259         [ -  + ]:              3 :     byte = ((unsigned char *) VARDATA_ANY(v))[byteNo];
                               3260                 :                : 
 4753 bruce@momjian.us         3261         [ +  - ]:              3 :     if (byte & (1 << bitNo))
 8706 tgl@sss.pgh.pa.us        3262                 :              3 :         PG_RETURN_INT32(1);
                               3263                 :                :     else
 8706 tgl@sss.pgh.pa.us        3264                 :UBC           0 :         PG_RETURN_INT32(0);
                               3265                 :                : }
                               3266                 :                : 
                               3267                 :                : /*-------------------------------------------------------------
                               3268                 :                :  * byteaSetByte
                               3269                 :                :  *
                               3270                 :                :  * Given an instance of type 'bytea' creates a new one with
                               3271                 :                :  * the Nth byte set to the given value.
                               3272                 :                :  *
                               3273                 :                :  *-------------------------------------------------------------
                               3274                 :                :  */
                               3275                 :                : Datum
 8706 tgl@sss.pgh.pa.us        3276                 :CBC           6 : byteaSetByte(PG_FUNCTION_ARGS)
                               3277                 :                : {
 2590 noah@leadboat.com        3278                 :              6 :     bytea      *res = PG_GETARG_BYTEA_P_COPY(0);
 8706 tgl@sss.pgh.pa.us        3279                 :              6 :     int32       n = PG_GETARG_INT32(1);
                               3280                 :              6 :     int32       newByte = PG_GETARG_INT32(2);
                               3281                 :                :     int         len;
                               3282                 :                : 
 2590 noah@leadboat.com        3283                 :              6 :     len = VARSIZE(res) - VARHDRSZ;
                               3284                 :                : 
 8787 tgl@sss.pgh.pa.us        3285   [ +  -  +  + ]:              6 :     if (n < 0 || n >= len)
 7567                          3286         [ +  - ]:              3 :         ereport(ERROR,
                               3287                 :                :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                               3288                 :                :                  errmsg("index %d out of valid range, 0..%d",
                               3289                 :                :                         n, len - 1)));
                               3290                 :                : 
                               3291                 :                :     /*
                               3292                 :                :      * Now set the byte.
                               3293                 :                :      */
 8787                          3294                 :              3 :     ((unsigned char *) VARDATA(res))[n] = newByte;
                               3295                 :                : 
 8706                          3296                 :              3 :     PG_RETURN_BYTEA_P(res);
                               3297                 :                : }
                               3298                 :                : 
                               3299                 :                : /*-------------------------------------------------------------
                               3300                 :                :  * byteaSetBit
                               3301                 :                :  *
                               3302                 :                :  * Given an instance of type 'bytea' creates a new one with
                               3303                 :                :  * the Nth bit set to the given value.
                               3304                 :                :  *
                               3305                 :                :  *-------------------------------------------------------------
                               3306                 :                :  */
                               3307                 :                : Datum
                               3308                 :              6 : byteaSetBit(PG_FUNCTION_ARGS)
                               3309                 :                : {
 2590 noah@leadboat.com        3310                 :              6 :     bytea      *res = PG_GETARG_BYTEA_P_COPY(0);
 1468 tgl@sss.pgh.pa.us        3311                 :              6 :     int64       n = PG_GETARG_INT64(1);
 8706                          3312                 :              6 :     int32       newBit = PG_GETARG_INT32(2);
                               3313                 :                :     int         len;
                               3314                 :                :     int         oldByte,
                               3315                 :                :                 newByte;
                               3316                 :                :     int         byteNo,
                               3317                 :                :                 bitNo;
                               3318                 :                : 
 2590 noah@leadboat.com        3319                 :              6 :     len = VARSIZE(res) - VARHDRSZ;
                               3320                 :                : 
 1468 tgl@sss.pgh.pa.us        3321   [ +  -  +  + ]:              6 :     if (n < 0 || n >= (int64) len * 8)
 7567                          3322         [ +  - ]:              3 :         ereport(ERROR,
                               3323                 :                :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                               3324                 :                :                  errmsg("index %lld out of valid range, 0..%lld",
                               3325                 :                :                         (long long) n, (long long) len * 8 - 1)));
                               3326                 :                : 
                               3327                 :                :     /* n/8 is now known < len, so safe to cast to int */
 1468                          3328                 :              3 :     byteNo = (int) (n / 8);
                               3329                 :              3 :     bitNo = (int) (n % 8);
                               3330                 :                : 
                               3331                 :                :     /*
                               3332                 :                :      * sanity check!
                               3333                 :                :      */
 9716 bruce@momjian.us         3334   [ -  +  -  - ]:              3 :     if (newBit != 0 && newBit != 1)
 7567 tgl@sss.pgh.pa.us        3335         [ #  # ]:UBC           0 :         ereport(ERROR,
                               3336                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               3337                 :                :                  errmsg("new bit must be 0 or 1")));
                               3338                 :                : 
                               3339                 :                :     /*
                               3340                 :                :      * Update the byte.
                               3341                 :                :      */
 8706 tgl@sss.pgh.pa.us        3342                 :CBC           3 :     oldByte = ((unsigned char *) VARDATA(res))[byteNo];
                               3343                 :                : 
 9716 bruce@momjian.us         3344         [ +  - ]:              3 :     if (newBit == 0)
                               3345                 :              3 :         newByte = oldByte & (~(1 << bitNo));
                               3346                 :                :     else
 9716 bruce@momjian.us         3347                 :UBC           0 :         newByte = oldByte | (1 << bitNo);
                               3348                 :                : 
 8706 tgl@sss.pgh.pa.us        3349                 :CBC           3 :     ((unsigned char *) VARDATA(res))[byteNo] = newByte;
                               3350                 :                : 
                               3351                 :              3 :     PG_RETURN_BYTEA_P(res);
                               3352                 :                : }
                               3353                 :                : 
                               3354                 :                : 
                               3355                 :                : /* text_name()
                               3356                 :                :  * Converts a text type to a Name type.
                               3357                 :                :  */
                               3358                 :                : Datum
 8683                          3359                 :          15281 : text_name(PG_FUNCTION_ARGS)
                               3360                 :                : {
 6218                          3361                 :          15281 :     text       *s = PG_GETARG_TEXT_PP(0);
                               3362                 :                :     Name        result;
                               3363                 :                :     int         len;
                               3364                 :                : 
                               3365   [ -  +  -  -  :          15281 :     len = VARSIZE_ANY_EXHDR(s);
                                     -  -  -  -  +  
                                                 + ]
                               3366                 :                : 
                               3367                 :                :     /* Truncate oversize input */
 8683                          3368         [ +  + ]:          15281 :     if (len >= NAMEDATALEN)
 4342                          3369         [ -  + ]:              3 :         len = pg_mbcliplen(VARDATA_ANY(s), len, NAMEDATALEN - 1);
                               3370                 :                : 
                               3371                 :                :     /* We use palloc0 here to ensure result is zero-padded */
                               3372                 :          15281 :     result = (Name) palloc0(NAMEDATALEN);
 6218                          3373         [ +  + ]:          15281 :     memcpy(NameStr(*result), VARDATA_ANY(s), len);
                               3374                 :                : 
 8683                          3375                 :          15281 :     PG_RETURN_NAME(result);
                               3376                 :                : }
                               3377                 :                : 
                               3378                 :                : /* name_text()
                               3379                 :                :  * Converts a Name type to a text type.
                               3380                 :                :  */
                               3381                 :                : Datum
                               3382                 :         316663 : name_text(PG_FUNCTION_ARGS)
                               3383                 :                : {
                               3384                 :         316663 :     Name        s = PG_GETARG_NAME(0);
                               3385                 :                : 
 5864                          3386                 :         316663 :     PG_RETURN_TEXT_P(cstring_to_text(NameStr(*s)));
                               3387                 :                : }
                               3388                 :                : 
                               3389                 :                : 
                               3390                 :                : /*
                               3391                 :                :  * textToQualifiedNameList - convert a text object to list of names
                               3392                 :                :  *
                               3393                 :                :  * This implements the input parsing needed by nextval() and other
                               3394                 :                :  * functions that take a text parameter representing a qualified name.
                               3395                 :                :  * We split the name at dots, downcase if not double-quoted, and
                               3396                 :                :  * truncate names if they're too long.
                               3397                 :                :  */
                               3398                 :                : List *
 6897 neilc@samurai.com        3399                 :            711 : textToQualifiedNameList(text *textval)
                               3400                 :                : {
                               3401                 :                :     char       *rawname;
 8051 tgl@sss.pgh.pa.us        3402                 :            711 :     List       *result = NIL;
                               3403                 :                :     List       *namelist;
                               3404                 :                :     ListCell   *l;
                               3405                 :                : 
                               3406                 :                :     /* Convert to C string (handles possible detoasting). */
                               3407                 :                :     /* Note we rely on being able to modify rawname below. */
 5864                          3408                 :            711 :     rawname = text_to_cstring(textval);
                               3409                 :                : 
 8049                          3410         [ -  + ]:            711 :     if (!SplitIdentifierString(rawname, '.', &namelist))
 7567 tgl@sss.pgh.pa.us        3411         [ #  # ]:UBC           0 :         ereport(ERROR,
                               3412                 :                :                 (errcode(ERRCODE_INVALID_NAME),
                               3413                 :                :                  errmsg("invalid name syntax")));
                               3414                 :                : 
 8049 tgl@sss.pgh.pa.us        3415         [ -  + ]:CBC         711 :     if (namelist == NIL)
 7567 tgl@sss.pgh.pa.us        3416         [ #  # ]:UBC           0 :         ereport(ERROR,
                               3417                 :                :                 (errcode(ERRCODE_INVALID_NAME),
                               3418                 :                :                  errmsg("invalid name syntax")));
                               3419                 :                : 
 8049 tgl@sss.pgh.pa.us        3420   [ +  -  +  +  :CBC        1477 :     foreach(l, namelist)
                                              +  + ]
                               3421                 :                :     {
 7893 bruce@momjian.us         3422                 :            766 :         char       *curname = (char *) lfirst(l);
                               3423                 :                : 
 8049 tgl@sss.pgh.pa.us        3424                 :            766 :         result = lappend(result, makeString(pstrdup(curname)));
                               3425                 :                :     }
                               3426                 :                : 
                               3427                 :            711 :     pfree(rawname);
 7259 neilc@samurai.com        3428                 :            711 :     list_free(namelist);
                               3429                 :                : 
 8049 tgl@sss.pgh.pa.us        3430                 :            711 :     return result;
                               3431                 :                : }
                               3432                 :                : 
                               3433                 :                : /*
                               3434                 :                :  * SplitIdentifierString --- parse a string containing identifiers
                               3435                 :                :  *
                               3436                 :                :  * This is the guts of textToQualifiedNameList, and is exported for use in
                               3437                 :                :  * other situations such as parsing GUC variables.  In the GUC case, it's
                               3438                 :                :  * important to avoid memory leaks, so the API is designed to minimize the
                               3439                 :                :  * amount of stuff that needs to be allocated and freed.
                               3440                 :                :  *
                               3441                 :                :  * Inputs:
                               3442                 :                :  *  rawstring: the input string; must be overwritable!  On return, it's
                               3443                 :                :  *             been modified to contain the separated identifiers.
                               3444                 :                :  *  separator: the separator punctuation expected between identifiers
                               3445                 :                :  *             (typically '.' or ',').  Whitespace may also appear around
                               3446                 :                :  *             identifiers.
                               3447                 :                :  * Outputs:
                               3448                 :                :  *  namelist: filled with a palloc'd list of pointers to identifiers within
                               3449                 :                :  *            rawstring.  Caller should list_free() this even on error return.
                               3450                 :                :  *
                               3451                 :                :  * Returns true if okay, false if there is a syntax error in the string.
                               3452                 :                :  *
                               3453                 :                :  * Note that an empty string is considered okay here, though not in
                               3454                 :                :  * textToQualifiedNameList.
                               3455                 :                :  */
                               3456                 :                : bool
                               3457                 :          69217 : SplitIdentifierString(char *rawstring, char separator,
                               3458                 :                :                       List **namelist)
                               3459                 :                : {
                               3460                 :          69217 :     char       *nextp = rawstring;
                               3461                 :          69217 :     bool        done = false;
                               3462                 :                : 
                               3463                 :          69217 :     *namelist = NIL;
                               3464                 :                : 
 2517                          3465         [ +  + ]:          69220 :     while (scanner_isspace(*nextp))
 8049                          3466                 :              3 :         nextp++;                /* skip leading whitespace */
                               3467                 :                : 
                               3468         [ +  + ]:          69217 :     if (*nextp == '\0')
                               3469                 :          14394 :         return true;            /* allow empty string */
                               3470                 :                : 
                               3471                 :                :     /* At the top of the loop, we are at start of a new identifier. */
                               3472                 :                :     do
                               3473                 :                :     {
                               3474                 :                :         char       *curname;
                               3475                 :                :         char       *endp;
                               3476                 :                : 
 3036 peter_e@gmx.net          3477         [ +  + ]:          93015 :         if (*nextp == '"')
                               3478                 :                :         {
                               3479                 :                :             /* Quoted name --- collapse quote-quote pairs, no downcasing */
 8051 tgl@sss.pgh.pa.us        3480                 :          19339 :             curname = nextp + 1;
                               3481                 :                :             for (;;)
                               3482                 :                :             {
 3036 peter_e@gmx.net          3483                 :          19341 :                 endp = strchr(nextp + 1, '"');
 8051 tgl@sss.pgh.pa.us        3484         [ -  + ]:          19340 :                 if (endp == NULL)
 2489 tgl@sss.pgh.pa.us        3485                 :UBC           0 :                     return false;   /* mismatched quotes */
 3036 peter_e@gmx.net          3486         [ +  + ]:CBC       19340 :                 if (endp[1] != '"')
 8051 tgl@sss.pgh.pa.us        3487                 :          19339 :                     break;      /* found end of quoted name */
                               3488                 :                :                 /* Collapse adjacent quotes into one quote, and look again */
 7893 bruce@momjian.us         3489                 :              1 :                 memmove(endp, endp + 1, strlen(endp));
 8051 tgl@sss.pgh.pa.us        3490                 :              1 :                 nextp = endp;
                               3491                 :                :             }
                               3492                 :                :             /* endp now points at the terminating quote */
                               3493                 :          19339 :             nextp = endp + 1;
                               3494                 :                :         }
                               3495                 :                :         else
                               3496                 :                :         {
                               3497                 :                :             /* Unquoted name --- extends to separator or whitespace */
                               3498                 :                :             char       *downname;
                               3499                 :                :             int         len;
                               3500                 :                : 
                               3501                 :          73676 :             curname = nextp;
 8049                          3502   [ +  +  +  + ]:         601357 :             while (*nextp && *nextp != separator &&
 2517                          3503         [ +  + ]:         527682 :                    !scanner_isspace(*nextp))
 8049                          3504                 :         527681 :                 nextp++;
                               3505                 :          73676 :             endp = nextp;
                               3506         [ -  + ]:          73676 :             if (curname == nextp)
 8049 tgl@sss.pgh.pa.us        3507                 :UBC           0 :                 return false;   /* empty unquoted name not allowed */
                               3508                 :                : 
                               3509                 :                :             /*
                               3510                 :                :              * Downcase the identifier, using same code as main lexer does.
                               3511                 :                :              *
                               3512                 :                :              * XXX because we want to overwrite the input in-place, we cannot
                               3513                 :                :              * support a downcasing transformation that increases the string
                               3514                 :                :              * length.  This is not a problem given the current implementation
                               3515                 :                :              * of downcase_truncate_identifier, but we'll probably have to do
                               3516                 :                :              * something about this someday.
                               3517                 :                :              */
 7358 tgl@sss.pgh.pa.us        3518                 :CBC       73676 :             len = endp - curname;
                               3519                 :          73676 :             downname = downcase_truncate_identifier(curname, len, false);
                               3520         [ -  + ]:          73676 :             Assert(strlen(downname) <= len);
 3368                          3521                 :          73676 :             strncpy(curname, downname, len);    /* strncpy is required here */
 7358                          3522                 :          73676 :             pfree(downname);
                               3523                 :                :         }
                               3524                 :                : 
 2517                          3525         [ +  + ]:          93016 :         while (scanner_isspace(*nextp))
 8049                          3526                 :              1 :             nextp++;            /* skip trailing whitespace */
                               3527                 :                : 
                               3528         [ +  + ]:          93015 :         if (*nextp == separator)
                               3529                 :                :         {
                               3530                 :          38192 :             nextp++;
 2517                          3531         [ +  + ]:          67329 :             while (scanner_isspace(*nextp))
 8049                          3532                 :          29137 :                 nextp++;        /* skip leading whitespace for next */
                               3533                 :                :             /* we expect another name, so done remains false */
                               3534                 :                :         }
                               3535         [ +  + ]:          54823 :         else if (*nextp == '\0')
                               3536                 :          54822 :             done = true;
                               3537                 :                :         else
                               3538                 :              1 :             return false;       /* invalid syntax */
                               3539                 :                : 
                               3540                 :                :         /* Now safe to overwrite separator with a null */
                               3541                 :          93014 :         *endp = '\0';
                               3542                 :                : 
                               3543                 :                :         /* Truncate name if it's overlength */
 7358                          3544                 :          93014 :         truncate_identifier(curname, strlen(curname), false);
                               3545                 :                : 
                               3546                 :                :         /*
                               3547                 :                :          * Finished isolating current name --- add it to list
                               3548                 :                :          */
 8049                          3549                 :          93014 :         *namelist = lappend(*namelist, curname);
                               3550                 :                : 
                               3551                 :                :         /* Loop back if we didn't reach end of string */
                               3552         [ +  + ]:          93014 :     } while (!done);
                               3553                 :                : 
                               3554                 :          54822 :     return true;
                               3555                 :                : }
                               3556                 :                : 
                               3557                 :                : 
                               3558                 :                : /*
                               3559                 :                :  * SplitDirectoriesString --- parse a string containing file/directory names
                               3560                 :                :  *
                               3561                 :                :  * This works fine on file names too; the function name is historical.
                               3562                 :                :  *
                               3563                 :                :  * This is similar to SplitIdentifierString, except that the parsing
                               3564                 :                :  * rules are meant to handle pathnames instead of identifiers: there is
                               3565                 :                :  * no downcasing, embedded spaces are allowed, the max length is MAXPGPATH-1,
                               3566                 :                :  * and we apply canonicalize_path() to each extracted string.  Because of the
                               3567                 :                :  * last, the returned strings are separately palloc'd rather than being
                               3568                 :                :  * pointers into rawstring --- but we still scribble on rawstring.
                               3569                 :                :  *
                               3570                 :                :  * Inputs:
                               3571                 :                :  *  rawstring: the input string; must be modifiable!
                               3572                 :                :  *  separator: the separator punctuation expected between directories
                               3573                 :                :  *             (typically ',' or ';').  Whitespace may also appear around
                               3574                 :                :  *             directories.
                               3575                 :                :  * Outputs:
                               3576                 :                :  *  namelist: filled with a palloc'd list of directory names.
                               3577                 :                :  *            Caller should list_free_deep() this even on error return.
                               3578                 :                :  *
                               3579                 :                :  * Returns true if okay, false if there is a syntax error in the string.
                               3580                 :                :  *
                               3581                 :                :  * Note that an empty string is considered okay here.
                               3582                 :                :  */
                               3583                 :                : bool
 4265                          3584                 :            759 : SplitDirectoriesString(char *rawstring, char separator,
                               3585                 :                :                        List **namelist)
                               3586                 :                : {
                               3587                 :            759 :     char       *nextp = rawstring;
                               3588                 :            759 :     bool        done = false;
                               3589                 :                : 
                               3590                 :            759 :     *namelist = NIL;
                               3591                 :                : 
 2517                          3592         [ -  + ]:            759 :     while (scanner_isspace(*nextp))
 4265 tgl@sss.pgh.pa.us        3593                 :UBC           0 :         nextp++;                /* skip leading whitespace */
                               3594                 :                : 
 4265 tgl@sss.pgh.pa.us        3595         [ +  + ]:CBC         759 :     if (*nextp == '\0')
                               3596                 :              3 :         return true;            /* allow empty string */
                               3597                 :                : 
                               3598                 :                :     /* At the top of the loop, we are at start of a new directory. */
                               3599                 :                :     do
                               3600                 :                :     {
                               3601                 :                :         char       *curname;
                               3602                 :                :         char       *endp;
                               3603                 :                : 
 3036 peter_e@gmx.net          3604         [ -  + ]:            756 :         if (*nextp == '"')
                               3605                 :                :         {
                               3606                 :                :             /* Quoted name --- collapse quote-quote pairs */
 4265 tgl@sss.pgh.pa.us        3607                 :UBC           0 :             curname = nextp + 1;
                               3608                 :                :             for (;;)
                               3609                 :                :             {
 3036 peter_e@gmx.net          3610                 :              0 :                 endp = strchr(nextp + 1, '"');
 4265 tgl@sss.pgh.pa.us        3611         [ #  # ]:              0 :                 if (endp == NULL)
 2489                          3612                 :              0 :                     return false;   /* mismatched quotes */
 3036 peter_e@gmx.net          3613         [ #  # ]:              0 :                 if (endp[1] != '"')
 4265 tgl@sss.pgh.pa.us        3614                 :              0 :                     break;      /* found end of quoted name */
                               3615                 :                :                 /* Collapse adjacent quotes into one quote, and look again */
                               3616                 :              0 :                 memmove(endp, endp + 1, strlen(endp));
                               3617                 :              0 :                 nextp = endp;
                               3618                 :                :             }
                               3619                 :                :             /* endp now points at the terminating quote */
                               3620                 :              0 :             nextp = endp + 1;
                               3621                 :                :         }
                               3622                 :                :         else
                               3623                 :                :         {
                               3624                 :                :             /* Unquoted name --- extends to separator or end of string */
 4238 tgl@sss.pgh.pa.us        3625                 :CBC         756 :             curname = endp = nextp;
                               3626   [ +  +  +  - ]:          12694 :             while (*nextp && *nextp != separator)
                               3627                 :                :             {
                               3628                 :                :                 /* trailing whitespace should not be included in name */
 2517                          3629         [ +  - ]:          11938 :                 if (!scanner_isspace(*nextp))
 4238                          3630                 :          11938 :                     endp = nextp + 1;
 4265                          3631                 :          11938 :                 nextp++;
                               3632                 :                :             }
 4238                          3633         [ -  + ]:            756 :             if (curname == endp)
 4265 tgl@sss.pgh.pa.us        3634                 :UBC           0 :                 return false;   /* empty unquoted name not allowed */
                               3635                 :                :         }
                               3636                 :                : 
 2517 tgl@sss.pgh.pa.us        3637         [ -  + ]:CBC         756 :         while (scanner_isspace(*nextp))
 4265 tgl@sss.pgh.pa.us        3638                 :UBC           0 :             nextp++;            /* skip trailing whitespace */
                               3639                 :                : 
 4265 tgl@sss.pgh.pa.us        3640         [ -  + ]:CBC         756 :         if (*nextp == separator)
                               3641                 :                :         {
 4265 tgl@sss.pgh.pa.us        3642                 :UBC           0 :             nextp++;
 2517                          3643         [ #  # ]:              0 :             while (scanner_isspace(*nextp))
 4265                          3644                 :              0 :                 nextp++;        /* skip leading whitespace for next */
                               3645                 :                :             /* we expect another name, so done remains false */
                               3646                 :                :         }
 4265 tgl@sss.pgh.pa.us        3647         [ +  - ]:CBC         756 :         else if (*nextp == '\0')
                               3648                 :            756 :             done = true;
                               3649                 :                :         else
 4265 tgl@sss.pgh.pa.us        3650                 :UBC           0 :             return false;       /* invalid syntax */
                               3651                 :                : 
                               3652                 :                :         /* Now safe to overwrite separator with a null */
 4265 tgl@sss.pgh.pa.us        3653                 :CBC         756 :         *endp = '\0';
                               3654                 :                : 
                               3655                 :                :         /* Truncate path if it's overlength */
                               3656         [ -  + ]:            756 :         if (strlen(curname) >= MAXPGPATH)
 4265 tgl@sss.pgh.pa.us        3657                 :UBC           0 :             curname[MAXPGPATH - 1] = '\0';
                               3658                 :                : 
                               3659                 :                :         /*
                               3660                 :                :          * Finished isolating current name --- add it to list
                               3661                 :                :          */
 4265 tgl@sss.pgh.pa.us        3662                 :CBC         756 :         curname = pstrdup(curname);
                               3663                 :            756 :         canonicalize_path(curname);
                               3664                 :            756 :         *namelist = lappend(*namelist, curname);
                               3665                 :                : 
                               3666                 :                :         /* Loop back if we didn't reach end of string */
                               3667         [ -  + ]:            756 :     } while (!done);
                               3668                 :                : 
                               3669                 :            756 :     return true;
                               3670                 :                : }
                               3671                 :                : 
                               3672                 :                : 
                               3673                 :                : /*
                               3674                 :                :  * SplitGUCList --- parse a string containing identifiers or file names
                               3675                 :                :  *
                               3676                 :                :  * This is used to split the value of a GUC_LIST_QUOTE GUC variable, without
                               3677                 :                :  * presuming whether the elements will be taken as identifiers or file names.
                               3678                 :                :  * We assume the input has already been through flatten_set_variable_args(),
                               3679                 :                :  * so that we need never downcase (if appropriate, that was done already).
                               3680                 :                :  * Nor do we ever truncate, since we don't know the correct max length.
                               3681                 :                :  * We disallow embedded whitespace for simplicity (it shouldn't matter,
                               3682                 :                :  * because any embedded whitespace should have led to double-quoting).
                               3683                 :                :  * Otherwise the API is identical to SplitIdentifierString.
                               3684                 :                :  *
                               3685                 :                :  * XXX it's annoying to have so many copies of this string-splitting logic.
                               3686                 :                :  * However, it's not clear that having one function with a bunch of option
                               3687                 :                :  * flags would be much better.
                               3688                 :                :  *
                               3689                 :                :  * XXX there is a version of this function in src/bin/pg_dump/dumputils.c.
                               3690                 :                :  * Be sure to update that if you have to change this.
                               3691                 :                :  *
                               3692                 :                :  * Inputs:
                               3693                 :                :  *  rawstring: the input string; must be overwritable!  On return, it's
                               3694                 :                :  *             been modified to contain the separated identifiers.
                               3695                 :                :  *  separator: the separator punctuation expected between identifiers
                               3696                 :                :  *             (typically '.' or ',').  Whitespace may also appear around
                               3697                 :                :  *             identifiers.
                               3698                 :                :  * Outputs:
                               3699                 :                :  *  namelist: filled with a palloc'd list of pointers to identifiers within
                               3700                 :                :  *            rawstring.  Caller should list_free() this even on error return.
                               3701                 :                :  *
                               3702                 :                :  * Returns true if okay, false if there is a syntax error in the string.
                               3703                 :                :  */
                               3704                 :                : bool
 2084                          3705                 :           1664 : SplitGUCList(char *rawstring, char separator,
                               3706                 :                :              List **namelist)
                               3707                 :                : {
                               3708                 :           1664 :     char       *nextp = rawstring;
                               3709                 :           1664 :     bool        done = false;
                               3710                 :                : 
                               3711                 :           1664 :     *namelist = NIL;
                               3712                 :                : 
                               3713         [ -  + ]:           1664 :     while (scanner_isspace(*nextp))
 2084 tgl@sss.pgh.pa.us        3714                 :UBC           0 :         nextp++;                /* skip leading whitespace */
                               3715                 :                : 
 2084 tgl@sss.pgh.pa.us        3716         [ +  + ]:CBC        1664 :     if (*nextp == '\0')
                               3717                 :           1620 :         return true;            /* allow empty string */
                               3718                 :                : 
                               3719                 :                :     /* At the top of the loop, we are at start of a new identifier. */
                               3720                 :                :     do
                               3721                 :                :     {
                               3722                 :                :         char       *curname;
                               3723                 :                :         char       *endp;
                               3724                 :                : 
                               3725         [ +  + ]:             57 :         if (*nextp == '"')
                               3726                 :                :         {
                               3727                 :                :             /* Quoted name --- collapse quote-quote pairs */
                               3728                 :             12 :             curname = nextp + 1;
                               3729                 :                :             for (;;)
                               3730                 :                :             {
                               3731                 :             18 :                 endp = strchr(nextp + 1, '"');
                               3732         [ -  + ]:             15 :                 if (endp == NULL)
 2084 tgl@sss.pgh.pa.us        3733                 :UBC           0 :                     return false;   /* mismatched quotes */
 2084 tgl@sss.pgh.pa.us        3734         [ +  + ]:CBC          15 :                 if (endp[1] != '"')
                               3735                 :             12 :                     break;      /* found end of quoted name */
                               3736                 :                :                 /* Collapse adjacent quotes into one quote, and look again */
                               3737                 :              3 :                 memmove(endp, endp + 1, strlen(endp));
                               3738                 :              3 :                 nextp = endp;
                               3739                 :                :             }
                               3740                 :                :             /* endp now points at the terminating quote */
                               3741                 :             12 :             nextp = endp + 1;
                               3742                 :                :         }
                               3743                 :                :         else
                               3744                 :                :         {
                               3745                 :                :             /* Unquoted name --- extends to separator or whitespace */
                               3746                 :             45 :             curname = nextp;
                               3747   [ +  +  +  + ]:            429 :             while (*nextp && *nextp != separator &&
                               3748         [ +  - ]:            384 :                    !scanner_isspace(*nextp))
                               3749                 :            384 :                 nextp++;
                               3750                 :             45 :             endp = nextp;
                               3751         [ -  + ]:             45 :             if (curname == nextp)
 2084 tgl@sss.pgh.pa.us        3752                 :UBC           0 :                 return false;   /* empty unquoted name not allowed */
                               3753                 :                :         }
                               3754                 :                : 
 2084 tgl@sss.pgh.pa.us        3755         [ -  + ]:CBC          57 :         while (scanner_isspace(*nextp))
 2084 tgl@sss.pgh.pa.us        3756                 :UBC           0 :             nextp++;            /* skip trailing whitespace */
                               3757                 :                : 
 2084 tgl@sss.pgh.pa.us        3758         [ +  + ]:CBC          57 :         if (*nextp == separator)
                               3759                 :                :         {
                               3760                 :             13 :             nextp++;
                               3761         [ +  + ]:             22 :             while (scanner_isspace(*nextp))
                               3762                 :              9 :                 nextp++;        /* skip leading whitespace for next */
                               3763                 :                :             /* we expect another name, so done remains false */
                               3764                 :                :         }
                               3765         [ +  - ]:             44 :         else if (*nextp == '\0')
                               3766                 :             44 :             done = true;
                               3767                 :                :         else
 2084 tgl@sss.pgh.pa.us        3768                 :UBC           0 :             return false;       /* invalid syntax */
                               3769                 :                : 
                               3770                 :                :         /* Now safe to overwrite separator with a null */
 2084 tgl@sss.pgh.pa.us        3771                 :CBC          57 :         *endp = '\0';
                               3772                 :                : 
                               3773                 :                :         /*
                               3774                 :                :          * Finished isolating current name --- add it to list
                               3775                 :                :          */
                               3776                 :             57 :         *namelist = lappend(*namelist, curname);
                               3777                 :                : 
                               3778                 :                :         /* Loop back if we didn't reach end of string */
                               3779         [ +  + ]:             57 :     } while (!done);
                               3780                 :                : 
                               3781                 :             44 :     return true;
                               3782                 :                : }
                               3783                 :                : 
                               3784                 :                : 
                               3785                 :                : /*****************************************************************************
                               3786                 :                :  *  Comparison Functions used for bytea
                               3787                 :                :  *
                               3788                 :                :  * Note: btree indexes need these routines not to leak memory; therefore,
                               3789                 :                :  * be careful to free working copies of toasted datums.  Most places don't
                               3790                 :                :  * need to be so careful.
                               3791                 :                :  *****************************************************************************/
                               3792                 :                : 
                               3793                 :                : Datum
 8280                          3794                 :           5194 : byteaeq(PG_FUNCTION_ARGS)
                               3795                 :                : {
 4835                          3796                 :           5194 :     Datum       arg1 = PG_GETARG_DATUM(0);
                               3797                 :           5194 :     Datum       arg2 = PG_GETARG_DATUM(1);
                               3798                 :                :     bool        result;
                               3799                 :                :     Size        len1,
                               3800                 :                :                 len2;
                               3801                 :                : 
                               3802                 :                :     /*
                               3803                 :                :      * We can use a fast path for unequal lengths, which might save us from
                               3804                 :                :      * having to detoast one or both values.
                               3805                 :                :      */
                               3806                 :           5194 :     len1 = toast_raw_datum_size(arg1);
                               3807                 :           5194 :     len2 = toast_raw_datum_size(arg2);
 8280                          3808         [ +  + ]:           5194 :     if (len1 != len2)
                               3809                 :           2158 :         result = false;
                               3810                 :                :     else
                               3811                 :                :     {
 4835                          3812                 :           3036 :         bytea      *barg1 = DatumGetByteaPP(arg1);
                               3813                 :           3036 :         bytea      *barg2 = DatumGetByteaPP(arg2);
                               3814                 :                : 
                               3815   [ -  +  +  + ]:           3036 :         result = (memcmp(VARDATA_ANY(barg1), VARDATA_ANY(barg2),
                               3816                 :                :                          len1 - VARHDRSZ) == 0);
                               3817                 :                : 
                               3818         [ +  + ]:           3036 :         PG_FREE_IF_COPY(barg1, 0);
                               3819         [ +  + ]:           3036 :         PG_FREE_IF_COPY(barg2, 1);
                               3820                 :                :     }
                               3821                 :                : 
 8280                          3822                 :           5194 :     PG_RETURN_BOOL(result);
                               3823                 :                : }
                               3824                 :                : 
                               3825                 :                : Datum
                               3826                 :            384 : byteane(PG_FUNCTION_ARGS)
                               3827                 :                : {
 4835                          3828                 :            384 :     Datum       arg1 = PG_GETARG_DATUM(0);
                               3829                 :            384 :     Datum       arg2 = PG_GETARG_DATUM(1);
                               3830                 :                :     bool        result;
                               3831                 :                :     Size        len1,
                               3832                 :                :                 len2;
                               3833                 :                : 
                               3834                 :                :     /*
                               3835                 :                :      * We can use a fast path for unequal lengths, which might save us from
                               3836                 :                :      * having to detoast one or both values.
                               3837                 :                :      */
                               3838                 :            384 :     len1 = toast_raw_datum_size(arg1);
                               3839                 :            384 :     len2 = toast_raw_datum_size(arg2);
 8280                          3840         [ -  + ]:            384 :     if (len1 != len2)
 8280 tgl@sss.pgh.pa.us        3841                 :UBC           0 :         result = true;
                               3842                 :                :     else
                               3843                 :                :     {
 4835 tgl@sss.pgh.pa.us        3844                 :CBC         384 :         bytea      *barg1 = DatumGetByteaPP(arg1);
                               3845                 :            384 :         bytea      *barg2 = DatumGetByteaPP(arg2);
                               3846                 :                : 
                               3847   [ -  +  -  + ]:            384 :         result = (memcmp(VARDATA_ANY(barg1), VARDATA_ANY(barg2),
                               3848                 :                :                          len1 - VARHDRSZ) != 0);
                               3849                 :                : 
                               3850         [ -  + ]:            384 :         PG_FREE_IF_COPY(barg1, 0);
                               3851         [ -  + ]:            384 :         PG_FREE_IF_COPY(barg2, 1);
                               3852                 :                :     }
                               3853                 :                : 
 8280                          3854                 :            384 :     PG_RETURN_BOOL(result);
                               3855                 :                : }
                               3856                 :                : 
                               3857                 :                : Datum
                               3858                 :           4159 : bytealt(PG_FUNCTION_ARGS)
                               3859                 :                : {
 6218                          3860                 :           4159 :     bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
                               3861                 :           4159 :     bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
                               3862                 :                :     int         len1,
                               3863                 :                :                 len2;
                               3864                 :                :     int         cmp;
                               3865                 :                : 
                               3866   [ -  +  -  -  :           4159 :     len1 = VARSIZE_ANY_EXHDR(arg1);
                                     -  -  -  -  +  
                                                 + ]
                               3867   [ -  +  -  -  :           4159 :     len2 = VARSIZE_ANY_EXHDR(arg2);
                                     -  -  -  -  +  
                                                 + ]
                               3868                 :                : 
                               3869   [ +  +  +  + ]:           4159 :     cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
                               3870                 :                : 
 8280                          3871         [ +  + ]:           4159 :     PG_FREE_IF_COPY(arg1, 0);
                               3872         [ -  + ]:           4159 :     PG_FREE_IF_COPY(arg2, 1);
                               3873                 :                : 
                               3874   [ +  +  +  +  :           4159 :     PG_RETURN_BOOL((cmp < 0) || ((cmp == 0) && (len1 < len2)));
                                              +  + ]
                               3875                 :                : }
                               3876                 :                : 
                               3877                 :                : Datum
                               3878                 :           3178 : byteale(PG_FUNCTION_ARGS)
                               3879                 :                : {
 6218                          3880                 :           3178 :     bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
                               3881                 :           3178 :     bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
                               3882                 :                :     int         len1,
                               3883                 :                :                 len2;
                               3884                 :                :     int         cmp;
                               3885                 :                : 
                               3886   [ -  +  -  -  :           3178 :     len1 = VARSIZE_ANY_EXHDR(arg1);
                                     -  -  -  -  +  
                                                 + ]
                               3887   [ -  +  -  -  :           3178 :     len2 = VARSIZE_ANY_EXHDR(arg2);
                                     -  -  -  -  -  
                                                 + ]
                               3888                 :                : 
                               3889   [ -  +  +  + ]:           3178 :     cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
                               3890                 :                : 
 8280                          3891         [ +  + ]:           3178 :     PG_FREE_IF_COPY(arg1, 0);
                               3892         [ -  + ]:           3178 :     PG_FREE_IF_COPY(arg2, 1);
                               3893                 :                : 
                               3894   [ +  +  +  +  :           3178 :     PG_RETURN_BOOL((cmp < 0) || ((cmp == 0) && (len1 <= len2)));
                                              +  + ]
                               3895                 :                : }
                               3896                 :                : 
                               3897                 :                : Datum
                               3898                 :           3114 : byteagt(PG_FUNCTION_ARGS)
                               3899                 :                : {
 6218                          3900                 :           3114 :     bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
                               3901                 :           3114 :     bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
                               3902                 :                :     int         len1,
                               3903                 :                :                 len2;
                               3904                 :                :     int         cmp;
                               3905                 :                : 
                               3906   [ -  +  -  -  :           3114 :     len1 = VARSIZE_ANY_EXHDR(arg1);
                                     -  -  -  -  +  
                                                 + ]
                               3907   [ -  +  -  -  :           3114 :     len2 = VARSIZE_ANY_EXHDR(arg2);
                                     -  -  -  -  +  
                                                 + ]
                               3908                 :                : 
                               3909   [ +  +  +  + ]:           3114 :     cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
                               3910                 :                : 
 8280                          3911         [ +  + ]:           3114 :     PG_FREE_IF_COPY(arg1, 0);
                               3912         [ -  + ]:           3114 :     PG_FREE_IF_COPY(arg2, 1);
                               3913                 :                : 
                               3914   [ +  +  +  +  :           3114 :     PG_RETURN_BOOL((cmp > 0) || ((cmp == 0) && (len1 > len2)));
                                              +  + ]
                               3915                 :                : }
                               3916                 :                : 
                               3917                 :                : Datum
                               3918                 :           2505 : byteage(PG_FUNCTION_ARGS)
                               3919                 :                : {
 6218                          3920                 :           2505 :     bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
                               3921                 :           2505 :     bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
                               3922                 :                :     int         len1,
                               3923                 :                :                 len2;
                               3924                 :                :     int         cmp;
                               3925                 :                : 
                               3926   [ -  +  -  -  :           2505 :     len1 = VARSIZE_ANY_EXHDR(arg1);
                                     -  -  -  -  +  
                                                 + ]
                               3927   [ -  +  -  -  :           2505 :     len2 = VARSIZE_ANY_EXHDR(arg2);
                                     -  -  -  -  -  
                                                 + ]
                               3928                 :                : 
                               3929   [ -  +  +  + ]:           2505 :     cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
                               3930                 :                : 
 8280                          3931         [ +  + ]:           2505 :     PG_FREE_IF_COPY(arg1, 0);
                               3932         [ -  + ]:           2505 :     PG_FREE_IF_COPY(arg2, 1);
                               3933                 :                : 
                               3934   [ +  +  +  +  :           2505 :     PG_RETURN_BOOL((cmp > 0) || ((cmp == 0) && (len1 >= len2)));
                                              +  + ]
                               3935                 :                : }
                               3936                 :                : 
                               3937                 :                : Datum
                               3938                 :          43704 : byteacmp(PG_FUNCTION_ARGS)
                               3939                 :                : {
 6218                          3940                 :          43704 :     bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
                               3941                 :          43704 :     bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
                               3942                 :                :     int         len1,
                               3943                 :                :                 len2;
                               3944                 :                :     int         cmp;
                               3945                 :                : 
                               3946   [ -  +  -  -  :          43704 :     len1 = VARSIZE_ANY_EXHDR(arg1);
                                     -  -  -  -  -  
                                                 + ]
                               3947   [ -  +  -  -  :          43704 :     len2 = VARSIZE_ANY_EXHDR(arg2);
                                     -  -  -  -  +  
                                                 + ]
                               3948                 :                : 
                               3949   [ +  +  -  + ]:          43704 :     cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
 8280                          3950   [ +  +  +  + ]:          43704 :     if ((cmp == 0) && (len1 != len2))
                               3951         [ +  + ]:           7332 :         cmp = (len1 < len2) ? -1 : 1;
                               3952                 :                : 
                               3953         [ -  + ]:          43704 :     PG_FREE_IF_COPY(arg1, 0);
                               3954         [ -  + ]:          43704 :     PG_FREE_IF_COPY(arg2, 1);
                               3955                 :                : 
                               3956                 :          43704 :     PG_RETURN_INT32(cmp);
                               3957                 :                : }
                               3958                 :                : 
                               3959                 :                : Datum
 2993 rhaas@postgresql.org     3960                 :             26 : bytea_sortsupport(PG_FUNCTION_ARGS)
                               3961                 :                : {
                               3962                 :             26 :     SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
                               3963                 :                :     MemoryContext oldcontext;
                               3964                 :                : 
                               3965                 :             26 :     oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
                               3966                 :                : 
                               3967                 :                :     /* Use generic string SortSupport, forcing "C" collation */
 1943 tgl@sss.pgh.pa.us        3968                 :             26 :     varstr_sortsupport(ssup, BYTEAOID, C_COLLATION_OID);
                               3969                 :                : 
 2993 rhaas@postgresql.org     3970                 :             26 :     MemoryContextSwitchTo(oldcontext);
                               3971                 :                : 
                               3972                 :             26 :     PG_RETURN_VOID();
                               3973                 :                : }
                               3974                 :                : 
                               3975                 :                : /*
                               3976                 :                :  * appendStringInfoText
                               3977                 :                :  *
                               3978                 :                :  * Append a text to str.
                               3979                 :                :  * Like appendStringInfoString(str, text_to_cstring(t)) but faster.
                               3980                 :                :  */
                               3981                 :                : static void
 6859 bruce@momjian.us         3982                 :         842598 : appendStringInfoText(StringInfo str, const text *t)
                               3983                 :                : {
 6049 tgl@sss.pgh.pa.us        3984   [ -  +  -  -  :         842598 :     appendBinaryStringInfo(str, VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t));
                                     -  -  -  -  +  
                                           +  +  + ]
 6859 bruce@momjian.us         3985                 :         842598 : }
                               3986                 :                : 
                               3987                 :                : /*
                               3988                 :                :  * replace_text
                               3989                 :                :  * replace all occurrences of 'old_sub_str' in 'orig_str'
                               3990                 :                :  * with 'new_sub_str' to form 'new_str'
                               3991                 :                :  *
                               3992                 :                :  * returns 'orig_str' if 'old_sub_str' == '' or 'orig_str' == ''
                               3993                 :                :  * otherwise returns 'new_str'
                               3994                 :                :  */
                               3995                 :                : Datum
 7906                          3996                 :            534 : replace_text(PG_FUNCTION_ARGS)
                               3997                 :                : {
 6049 tgl@sss.pgh.pa.us        3998                 :            534 :     text       *src_text = PG_GETARG_TEXT_PP(0);
                               3999                 :            534 :     text       *from_sub_text = PG_GETARG_TEXT_PP(1);
                               4000                 :            534 :     text       *to_sub_text = PG_GETARG_TEXT_PP(2);
                               4001                 :                :     int         src_text_len;
                               4002                 :                :     int         from_sub_text_len;
                               4003                 :                :     TextPositionState state;
                               4004                 :                :     text       *ret_text;
                               4005                 :                :     int         chunk_len;
                               4006                 :                :     char       *curr_ptr;
                               4007                 :                :     char       *start_ptr;
                               4008                 :                :     StringInfoData str;
                               4009                 :                :     bool        found;
                               4010                 :                : 
 1906 heikki.linnakangas@i     4011   [ -  +  -  -  :            534 :     src_text_len = VARSIZE_ANY_EXHDR(src_text);
                                     -  -  -  -  -  
                                                 + ]
                               4012   [ -  +  -  -  :            534 :     from_sub_text_len = VARSIZE_ANY_EXHDR(from_sub_text);
                                     -  -  -  -  -  
                                                 + ]
                               4013                 :                : 
                               4014                 :                :     /* Return unmodified source string if empty source or pattern */
 6114 tgl@sss.pgh.pa.us        4015   [ +  -  -  + ]:            534 :     if (src_text_len < 1 || from_sub_text_len < 1)
                               4016                 :                :     {
 6114 tgl@sss.pgh.pa.us        4017                 :UBC           0 :         PG_RETURN_TEXT_P(src_text);
                               4018                 :                :     }
                               4019                 :                : 
 1850 peter@eisentraut.org     4020                 :CBC         534 :     text_position_setup(src_text, from_sub_text, PG_GET_COLLATION(), &state);
                               4021                 :                : 
 1906 heikki.linnakangas@i     4022                 :            534 :     found = text_position_next(&state);
                               4023                 :                : 
                               4024                 :                :     /* When the from_sub_text is not found, there is nothing to do. */
                               4025         [ +  + ]:            534 :     if (!found)
                               4026                 :                :     {
 6399 tgl@sss.pgh.pa.us        4027                 :            124 :         text_position_cleanup(&state);
 6859 bruce@momjian.us         4028                 :            124 :         PG_RETURN_TEXT_P(src_text);
                               4029                 :                :     }
 1906 heikki.linnakangas@i     4030                 :            410 :     curr_ptr = text_position_get_match_ptr(&state);
 6049 tgl@sss.pgh.pa.us        4031         [ -  + ]:            410 :     start_ptr = VARDATA_ANY(src_text);
                               4032                 :                : 
 6619 neilc@samurai.com        4033                 :            410 :     initStringInfo(&str);
                               4034                 :                : 
                               4035                 :                :     do
                               4036                 :                :     {
 6114 tgl@sss.pgh.pa.us        4037         [ -  + ]:           2249 :         CHECK_FOR_INTERRUPTS();
                               4038                 :                : 
                               4039                 :                :         /* copy the data skipped over by last text_position_next() */
 1906 heikki.linnakangas@i     4040                 :           2249 :         chunk_len = curr_ptr - start_ptr;
 6367 tgl@sss.pgh.pa.us        4041                 :           2249 :         appendBinaryStringInfo(&str, start_ptr, chunk_len);
                               4042                 :                : 
 6619 neilc@samurai.com        4043                 :           2249 :         appendStringInfoText(&str, to_sub_text);
                               4044                 :                : 
 1906 heikki.linnakangas@i     4045                 :           2249 :         start_ptr = curr_ptr + from_sub_text_len;
                               4046                 :                : 
                               4047                 :           2249 :         found = text_position_next(&state);
                               4048         [ +  + ]:           2249 :         if (found)
                               4049                 :           1839 :             curr_ptr = text_position_get_match_ptr(&state);
                               4050                 :                :     }
                               4051         [ +  + ]:           2249 :     while (found);
                               4052                 :                : 
                               4053                 :                :     /* copy trailing data */
 6049 tgl@sss.pgh.pa.us        4054   [ -  +  -  -  :            410 :     chunk_len = ((char *) src_text + VARSIZE_ANY(src_text)) - start_ptr;
                                     -  -  -  -  -  
                                                 + ]
 6367                          4055                 :            410 :     appendBinaryStringInfo(&str, start_ptr, chunk_len);
                               4056                 :                : 
 6399                          4057                 :            410 :     text_position_cleanup(&state);
                               4058                 :                : 
 5864                          4059                 :            410 :     ret_text = cstring_to_text_with_len(str.data, str.len);
 6619 neilc@samurai.com        4060                 :            410 :     pfree(str.data);
                               4061                 :                : 
 7906 bruce@momjian.us         4062                 :            410 :     PG_RETURN_TEXT_P(ret_text);
                               4063                 :                : }
                               4064                 :                : 
                               4065                 :                : /*
                               4066                 :                :  * check_replace_text_has_escape
                               4067                 :                :  *
                               4068                 :                :  * Returns 0 if text contains no backslashes that need processing.
                               4069                 :                :  * Returns 1 if text contains backslashes, but not regexp submatch specifiers.
                               4070                 :                :  * Returns 2 if text contains regexp submatch specifiers (\1 .. \9).
                               4071                 :                :  */
                               4072                 :                : static int
  979 tgl@sss.pgh.pa.us        4073                 :           5612 : check_replace_text_has_escape(const text *replace_text)
                               4074                 :                : {
                               4075                 :           5612 :     int         result = 0;
 6049                          4076         [ -  + ]:           5612 :     const char *p = VARDATA_ANY(replace_text);
                               4077   [ -  +  -  -  :           5612 :     const char *p_end = p + VARSIZE_ANY_EXHDR(replace_text);
                                     -  -  -  -  -  
                                                 + ]
                               4078                 :                : 
  979                          4079         [ +  + ]:          11246 :     while (p < p_end)
                               4080                 :                :     {
                               4081                 :                :         /* Find next escape char, if any. */
                               4082                 :           5186 :         p = memchr(p, '\\', p_end - p);
                               4083         [ +  + ]:           5186 :         if (p == NULL)
                               4084                 :           4775 :             break;
                               4085                 :            411 :         p++;
                               4086                 :                :         /* Note: a backslash at the end doesn't require extra processing. */
                               4087         [ +  - ]:            411 :         if (p < p_end)
                               4088                 :                :         {
                               4089   [ +  +  +  + ]:            411 :             if (*p >= '1' && *p <= '9')
                               4090                 :            389 :                 return 2;       /* Found a submatch specifier, so done */
                               4091                 :             22 :             result = 1;         /* Found some other sequence, keep looking */
                               4092                 :             22 :             p++;
                               4093                 :                :         }
                               4094                 :                :     }
                               4095                 :           5223 :     return result;
                               4096                 :                : }
                               4097                 :                : 
                               4098                 :                : /*
                               4099                 :                :  * appendStringInfoRegexpSubstr
                               4100                 :                :  *
                               4101                 :                :  * Append replace_text to str, substituting regexp back references for
                               4102                 :                :  * \n escapes.  start_ptr is the start of the match in the source string,
                               4103                 :                :  * at logical character position data_pos.
                               4104                 :                :  */
                               4105                 :                : static void
 6853 bruce@momjian.us         4106                 :            118 : appendStringInfoRegexpSubstr(StringInfo str, text *replace_text,
                               4107                 :                :                              regmatch_t *pmatch,
                               4108                 :                :                              char *start_ptr, int data_pos)
                               4109                 :                : {
 6049 tgl@sss.pgh.pa.us        4110         [ -  + ]:            118 :     const char *p = VARDATA_ANY(replace_text);
                               4111   [ -  +  -  -  :            118 :     const char *p_end = p + VARSIZE_ANY_EXHDR(replace_text);
                                     -  -  -  -  -  
                                                 + ]
                               4112                 :                : 
  979                          4113         [ +  + ]:            287 :     while (p < p_end)
                               4114                 :                :     {
 6753                          4115                 :            259 :         const char *chunk_start = p;
                               4116                 :                :         int         so;
                               4117                 :                :         int         eo;
                               4118                 :                : 
                               4119                 :                :         /* Find next escape char, if any. */
  979                          4120                 :            259 :         p = memchr(p, '\\', p_end - p);
                               4121         [ +  + ]:            259 :         if (p == NULL)
                               4122                 :             87 :             p = p_end;
                               4123                 :                : 
                               4124                 :                :         /* Copy the text we just scanned over, if any. */
 6753                          4125         [ +  + ]:            259 :         if (p > chunk_start)
                               4126                 :            159 :             appendBinaryStringInfo(str, chunk_start, p - chunk_start);
                               4127                 :                : 
                               4128                 :                :         /* Done if at end of string, else advance over escape char. */
                               4129         [ +  + ]:            259 :         if (p >= p_end)
 6853 bruce@momjian.us         4130                 :             87 :             break;
                               4131                 :            172 :         p++;
                               4132                 :                : 
 6753 tgl@sss.pgh.pa.us        4133         [ +  + ]:            172 :         if (p >= p_end)
                               4134                 :                :         {
                               4135                 :                :             /* Escape at very end of input.  Treat same as unexpected char */
                               4136                 :              3 :             appendStringInfoChar(str, '\\');
                               4137                 :              3 :             break;
                               4138                 :                :         }
                               4139                 :                : 
 6853 bruce@momjian.us         4140   [ +  +  +  + ]:            169 :         if (*p >= '1' && *p <= '9')
                               4141                 :            139 :         {
                               4142                 :                :             /* Use the back reference of regexp. */
 6756                          4143                 :            139 :             int         idx = *p - '0';
                               4144                 :                : 
 6853                          4145                 :            139 :             so = pmatch[idx].rm_so;
                               4146                 :            139 :             eo = pmatch[idx].rm_eo;
                               4147                 :            139 :             p++;
                               4148                 :                :         }
                               4149         [ +  + ]:             30 :         else if (*p == '&')
                               4150                 :                :         {
                               4151                 :                :             /* Use the entire matched string. */
                               4152                 :              9 :             so = pmatch[0].rm_so;
                               4153                 :              9 :             eo = pmatch[0].rm_eo;
                               4154                 :              9 :             p++;
                               4155                 :                :         }
 6753 tgl@sss.pgh.pa.us        4156         [ +  + ]:             21 :         else if (*p == '\\')
                               4157                 :                :         {
                               4158                 :                :             /* \\ means transfer one \ to output. */
                               4159                 :             18 :             appendStringInfoChar(str, '\\');
                               4160                 :             18 :             p++;
                               4161                 :             18 :             continue;
                               4162                 :                :         }
                               4163                 :                :         else
                               4164                 :                :         {
                               4165                 :                :             /*
                               4166                 :                :              * If escape char is not followed by any expected char, just treat
                               4167                 :                :              * it as ordinary data to copy.  (XXX would it be better to throw
                               4168                 :                :              * an error?)
                               4169                 :                :              */
                               4170                 :              3 :             appendStringInfoChar(str, '\\');
                               4171                 :              3 :             continue;
                               4172                 :                :         }
                               4173                 :                : 
  979                          4174   [ +  -  +  - ]:            148 :         if (so >= 0 && eo >= 0)
                               4175                 :                :         {
                               4176                 :                :             /*
                               4177                 :                :              * Copy the text that is back reference of regexp.  Note so and eo
                               4178                 :                :              * are counted in characters not bytes.
                               4179                 :                :              */
                               4180                 :                :             char       *chunk_start;
                               4181                 :                :             int         chunk_len;
                               4182                 :                : 
 6367                          4183         [ -  + ]:            148 :             Assert(so >= data_pos);
                               4184                 :            148 :             chunk_start = start_ptr;
                               4185                 :            148 :             chunk_start += charlen_to_bytelen(chunk_start, so - data_pos);
                               4186                 :            148 :             chunk_len = charlen_to_bytelen(chunk_start, eo - so);
                               4187                 :            148 :             appendBinaryStringInfo(str, chunk_start, chunk_len);
                               4188                 :                :         }
                               4189                 :                :     }
 6853 bruce@momjian.us         4190                 :            118 : }
                               4191                 :                : 
                               4192                 :                : /*
                               4193                 :                :  * replace_text_regexp
                               4194                 :                :  *
                               4195                 :                :  * replace substring(s) in src_text that match pattern with replace_text.
                               4196                 :                :  * The replace_text can contain backslash markers to substitute
                               4197                 :                :  * (parts of) the matched text.
                               4198                 :                :  *
                               4199                 :                :  * cflags: regexp compile flags.
                               4200                 :                :  * collation: collation to use.
                               4201                 :                :  * search_start: the character (not byte) offset in src_text at which to
                               4202                 :                :  * begin searching.
                               4203                 :                :  * n: if 0, replace all matches; if > 0, replace only the N'th match.
                               4204                 :                :  */
                               4205                 :                : text *
  979 tgl@sss.pgh.pa.us        4206                 :           5612 : replace_text_regexp(text *src_text, text *pattern_text,
                               4207                 :                :                     text *replace_text,
                               4208                 :                :                     int cflags, Oid collation,
                               4209                 :                :                     int search_start, int n)
                               4210                 :                : {
                               4211                 :                :     text       *ret_text;
                               4212                 :                :     regex_t    *re;
 6049                          4213   [ -  +  -  -  :           5612 :     int         src_text_len = VARSIZE_ANY_EXHDR(src_text);
                                     -  -  -  -  +  
                                                 + ]
  985                          4214                 :           5612 :     int         nmatches = 0;
                               4215                 :                :     StringInfoData buf;
                               4216                 :                :     regmatch_t  pmatch[10];     /* main match, plus \1 to \9 */
  979                          4217                 :           5612 :     int         nmatch = lengthof(pmatch);
                               4218                 :                :     pg_wchar   *data;
                               4219                 :                :     size_t      data_len;
                               4220                 :                :     int         data_pos;
                               4221                 :                :     char       *start_ptr;
                               4222                 :                :     int         escape_status;
                               4223                 :                : 
 6619 neilc@samurai.com        4224                 :           5612 :     initStringInfo(&buf);
                               4225                 :                : 
                               4226                 :                :     /* Convert data string to wide characters. */
 6853 bruce@momjian.us         4227                 :           5612 :     data = (pg_wchar *) palloc((src_text_len + 1) * sizeof(pg_wchar));
 6049 tgl@sss.pgh.pa.us        4228         [ +  + ]:           5612 :     data_len = pg_mb2wchar_with_len(VARDATA_ANY(src_text), data, src_text_len);
                               4229                 :                : 
                               4230                 :                :     /* Check whether replace_text has escapes, especially regexp submatches. */
  979                          4231                 :           5612 :     escape_status = check_replace_text_has_escape(replace_text);
                               4232                 :                : 
                               4233                 :                :     /* If no regexp submatches, we can use REG_NOSUB. */
                               4234         [ +  + ]:           5612 :     if (escape_status < 2)
                               4235                 :                :     {
                               4236                 :           5223 :         cflags |= REG_NOSUB;
                               4237                 :                :         /* Also tell pg_regexec we only want the whole-match location. */
                               4238                 :           5223 :         nmatch = 1;
                               4239                 :                :     }
                               4240                 :                : 
                               4241                 :                :     /* Prepare the regexp. */
                               4242                 :           5612 :     re = RE_compile_and_cache(pattern_text, cflags, collation);
                               4243                 :                : 
                               4244                 :                :     /* start_ptr points to the data_pos'th character of src_text */
 6049                          4245         [ +  + ]:           5612 :     start_ptr = (char *) VARDATA_ANY(src_text);
 6367                          4246                 :           5612 :     data_pos = 0;
                               4247                 :                : 
                               4248         [ +  + ]:           8142 :     while (search_start <= data_len)
                               4249                 :                :     {
                               4250                 :                :         int         regexec_result;
                               4251                 :                : 
                               4252         [ -  + ]:           8139 :         CHECK_FOR_INTERRUPTS();
                               4253                 :                : 
 6853 bruce@momjian.us         4254                 :           8139 :         regexec_result = pg_regexec(re,
                               4255                 :                :                                     data,
                               4256                 :                :                                     data_len,
                               4257                 :                :                                     search_start,
                               4258                 :                :                                     NULL,   /* no details */
                               4259                 :                :                                     nmatch,
                               4260                 :                :                                     pmatch,
                               4261                 :                :                                     0);
                               4262                 :                : 
 6619 neilc@samurai.com        4263         [ +  + ]:           8139 :         if (regexec_result == REG_NOMATCH)
                               4264                 :           4892 :             break;
                               4265                 :                : 
                               4266         [ -  + ]:           3247 :         if (regexec_result != REG_OKAY)
                               4267                 :                :         {
                               4268                 :                :             char        errMsg[100];
                               4269                 :                : 
 6853 bruce@momjian.us         4270                 :UBC           0 :             pg_regerror(regexec_result, re, errMsg, sizeof(errMsg));
                               4271         [ #  # ]:              0 :             ereport(ERROR,
                               4272                 :                :                     (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
                               4273                 :                :                      errmsg("regular expression failed: %s", errMsg)));
                               4274                 :                :         }
                               4275                 :                : 
                               4276                 :                :         /*
                               4277                 :                :          * Count matches, and decide whether to replace this match.
                               4278                 :                :          */
  985 tgl@sss.pgh.pa.us        4279                 :CBC        3247 :         nmatches++;
                               4280   [ +  +  +  + ]:           3247 :         if (n > 0 && nmatches != n)
                               4281                 :                :         {
                               4282                 :                :             /*
                               4283                 :                :              * No, so advance search_start, but not start_ptr/data_pos. (Thus,
                               4284                 :                :              * we treat the matched text as if it weren't matched, and copy it
                               4285                 :                :              * to the output later.)
                               4286                 :                :              */
                               4287                 :             30 :             search_start = pmatch[0].rm_eo;
                               4288         [ -  + ]:             30 :             if (pmatch[0].rm_so == pmatch[0].rm_eo)
  985 tgl@sss.pgh.pa.us        4289                 :UBC           0 :                 search_start++;
  985 tgl@sss.pgh.pa.us        4290                 :CBC          30 :             continue;
                               4291                 :                :         }
                               4292                 :                : 
                               4293                 :                :         /*
                               4294                 :                :          * Copy the text to the left of the match position.  Note we are given
                               4295                 :                :          * character not byte indexes.
                               4296                 :                :          */
 6853 bruce@momjian.us         4297         [ +  + ]:           3217 :         if (pmatch[0].rm_so - data_pos > 0)
                               4298                 :                :         {
                               4299                 :                :             int         chunk_len;
                               4300                 :                : 
 6367 tgl@sss.pgh.pa.us        4301                 :           3130 :             chunk_len = charlen_to_bytelen(start_ptr,
                               4302                 :           3130 :                                            pmatch[0].rm_so - data_pos);
                               4303                 :           3130 :             appendBinaryStringInfo(&buf, start_ptr, chunk_len);
                               4304                 :                : 
                               4305                 :                :             /*
                               4306                 :                :              * Advance start_ptr over that text, to avoid multiple rescans of
                               4307                 :                :              * it if the replace_text contains multiple back-references.
                               4308                 :                :              */
                               4309                 :           3130 :             start_ptr += chunk_len;
                               4310                 :           3130 :             data_pos = pmatch[0].rm_so;
                               4311                 :                :         }
                               4312                 :                : 
                               4313                 :                :         /*
                               4314                 :                :          * Copy the replace_text, processing escapes if any are present.
                               4315                 :                :          */
  979                          4316         [ +  + ]:           3217 :         if (escape_status > 0)
 6367                          4317                 :            118 :             appendStringInfoRegexpSubstr(&buf, replace_text, pmatch,
                               4318                 :                :                                          start_ptr, data_pos);
                               4319                 :                :         else
 6619 neilc@samurai.com        4320                 :           3099 :             appendStringInfoText(&buf, replace_text);
                               4321                 :                : 
                               4322                 :                :         /* Advance start_ptr and data_pos over the matched text. */
 6367 tgl@sss.pgh.pa.us        4323                 :           6434 :         start_ptr += charlen_to_bytelen(start_ptr,
                               4324                 :           3217 :                                         pmatch[0].rm_eo - data_pos);
                               4325                 :           3217 :         data_pos = pmatch[0].rm_eo;
                               4326                 :                : 
                               4327                 :                :         /*
                               4328                 :                :          * If we only want to replace one occurrence, we're done.
                               4329                 :                :          */
  985                          4330         [ +  + ]:           3217 :         if (n > 0)
 6853 bruce@momjian.us         4331                 :            717 :             break;
                               4332                 :                : 
                               4333                 :                :         /*
                               4334                 :                :          * Advance search position.  Normally we start the next search at the
                               4335                 :                :          * end of the previous match; but if the match was of zero length, we
                               4336                 :                :          * have to advance by one character, or we'd just find the same match
                               4337                 :                :          * again.
                               4338                 :                :          */
 6367 tgl@sss.pgh.pa.us        4339                 :           2500 :         search_start = data_pos;
 6853 bruce@momjian.us         4340         [ +  + ]:           2500 :         if (pmatch[0].rm_so == pmatch[0].rm_eo)
                               4341                 :              6 :             search_start++;
                               4342                 :                :     }
                               4343                 :                : 
                               4344                 :                :     /*
                               4345                 :                :      * Copy the text to the right of the last match.
                               4346                 :                :      */
                               4347         [ +  + ]:           5612 :     if (data_pos < data_len)
                               4348                 :                :     {
                               4349                 :                :         int         chunk_len;
                               4350                 :                : 
 6049 tgl@sss.pgh.pa.us        4351   [ -  +  -  -  :           5359 :         chunk_len = ((char *) src_text + VARSIZE_ANY(src_text)) - start_ptr;
                                     -  -  -  -  +  
                                                 + ]
 6367                          4352                 :           5359 :         appendBinaryStringInfo(&buf, start_ptr, chunk_len);
                               4353                 :                :     }
                               4354                 :                : 
 5864                          4355                 :           5612 :     ret_text = cstring_to_text_with_len(buf.data, buf.len);
 6619 neilc@samurai.com        4356                 :           5612 :     pfree(buf.data);
 6853 bruce@momjian.us         4357                 :           5612 :     pfree(data);
                               4358                 :                : 
 6753 tgl@sss.pgh.pa.us        4359                 :           5612 :     return ret_text;
                               4360                 :                : }
                               4361                 :                : 
                               4362                 :                : /*
                               4363                 :                :  * split_part
                               4364                 :                :  * parse input string based on provided field separator
                               4365                 :                :  * return N'th item (1 based, negative counts from end)
                               4366                 :                :  */
                               4367                 :                : Datum
 1320                          4368                 :             51 : split_part(PG_FUNCTION_ARGS)
                               4369                 :                : {
 6049                          4370                 :             51 :     text       *inputstring = PG_GETARG_TEXT_PP(0);
                               4371                 :             51 :     text       *fldsep = PG_GETARG_TEXT_PP(1);
 7906 bruce@momjian.us         4372                 :             51 :     int         fldnum = PG_GETARG_INT32(2);
                               4373                 :                :     int         inputstring_len;
                               4374                 :                :     int         fldsep_len;
                               4375                 :                :     TextPositionState state;
                               4376                 :                :     char       *start_ptr;
                               4377                 :                :     char       *end_ptr;
                               4378                 :                :     text       *result_text;
                               4379                 :                :     bool        found;
                               4380                 :                : 
                               4381                 :                :     /* field number is 1 based */
 1248 tgl@sss.pgh.pa.us        4382         [ +  + ]:             51 :     if (fldnum == 0)
 7379                          4383         [ +  - ]:              3 :         ereport(ERROR,
                               4384                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               4385                 :                :                  errmsg("field position must not be zero")));
                               4386                 :                : 
 1906 heikki.linnakangas@i     4387   [ -  +  -  -  :             48 :     inputstring_len = VARSIZE_ANY_EXHDR(inputstring);
                                     -  -  -  -  -  
                                                 + ]
                               4388   [ -  +  -  -  :             48 :     fldsep_len = VARSIZE_ANY_EXHDR(fldsep);
                                     -  -  -  -  -  
                                                 + ]
                               4389                 :                : 
                               4390                 :                :     /* return empty string for empty input string */
 7906 bruce@momjian.us         4391         [ +  + ]:             48 :     if (inputstring_len < 1)
 5864 tgl@sss.pgh.pa.us        4392                 :              6 :         PG_RETURN_TEXT_P(cstring_to_text(""));
                               4393                 :                : 
                               4394                 :                :     /* handle empty field separator */
 7906 bruce@momjian.us         4395         [ +  + ]:             42 :     if (fldsep_len < 1)
                               4396                 :                :     {
                               4397                 :                :         /* if first or last field, return input string, else empty string */
 1248 tgl@sss.pgh.pa.us        4398   [ +  +  +  + ]:             12 :         if (fldnum == 1 || fldnum == -1)
 7906 bruce@momjian.us         4399                 :              6 :             PG_RETURN_TEXT_P(inputstring);
                               4400                 :                :         else
 5864 tgl@sss.pgh.pa.us        4401                 :              6 :             PG_RETURN_TEXT_P(cstring_to_text(""));
                               4402                 :                :     }
                               4403                 :                : 
                               4404                 :                :     /* find the first field separator */
 1850 peter@eisentraut.org     4405                 :             30 :     text_position_setup(inputstring, fldsep, PG_GET_COLLATION(), &state);
                               4406                 :                : 
 1906 heikki.linnakangas@i     4407                 :             30 :     found = text_position_next(&state);
                               4408                 :                : 
                               4409                 :                :     /* special case if fldsep not found at all */
                               4410         [ +  + ]:             30 :     if (!found)
                               4411                 :                :     {
 6399 tgl@sss.pgh.pa.us        4412                 :              6 :         text_position_cleanup(&state);
                               4413                 :                :         /* if first or last field, return input string, else empty string */
 1248                          4414   [ +  +  -  + ]:              6 :         if (fldnum == 1 || fldnum == -1)
 7906 bruce@momjian.us         4415                 :              3 :             PG_RETURN_TEXT_P(inputstring);
                               4416                 :                :         else
 5864 tgl@sss.pgh.pa.us        4417                 :              3 :             PG_RETURN_TEXT_P(cstring_to_text(""));
                               4418                 :                :     }
                               4419                 :                : 
                               4420                 :                :     /*
                               4421                 :                :      * take care of a negative field number (i.e. count from the right) by
                               4422                 :                :      * converting to a positive field number; we need total number of fields
                               4423                 :                :      */
 1248                          4424         [ +  + ]:             24 :     if (fldnum < 0)
                               4425                 :                :     {
                               4426                 :                :         /* we found a fldsep, so there are at least two fields */
                               4427                 :             12 :         int         numfields = 2;
                               4428                 :                : 
                               4429         [ +  + ]:             18 :         while (text_position_next(&state))
                               4430                 :              6 :             numfields++;
                               4431                 :                : 
                               4432                 :                :         /* special case of last field does not require an extra pass */
                               4433         [ +  + ]:             12 :         if (fldnum == -1)
                               4434                 :                :         {
                               4435                 :              3 :             start_ptr = text_position_get_match_ptr(&state) + fldsep_len;
                               4436         [ -  + ]:              3 :             end_ptr = VARDATA_ANY(inputstring) + inputstring_len;
                               4437                 :              3 :             text_position_cleanup(&state);
                               4438                 :              3 :             PG_RETURN_TEXT_P(cstring_to_text_with_len(start_ptr,
                               4439                 :                :                                                       end_ptr - start_ptr));
                               4440                 :                :         }
                               4441                 :                : 
                               4442                 :                :         /* else, convert fldnum to positive notation */
                               4443                 :              9 :         fldnum += numfields + 1;
                               4444                 :                : 
                               4445                 :                :         /* if nonexistent field, return empty string */
                               4446         [ +  + ]:              9 :         if (fldnum <= 0)
                               4447                 :                :         {
                               4448                 :              3 :             text_position_cleanup(&state);
                               4449                 :              3 :             PG_RETURN_TEXT_P(cstring_to_text(""));
                               4450                 :                :         }
                               4451                 :                : 
                               4452                 :                :         /* reset to pointing at first match, but now with positive fldnum */
                               4453                 :              6 :         text_position_reset(&state);
                               4454                 :              6 :         found = text_position_next(&state);
                               4455         [ -  + ]:              6 :         Assert(found);
                               4456                 :                :     }
                               4457                 :                : 
                               4458                 :                :     /* identify bounds of first field */
                               4459         [ -  + ]:             18 :     start_ptr = VARDATA_ANY(inputstring);
 1906 heikki.linnakangas@i     4460                 :             18 :     end_ptr = text_position_get_match_ptr(&state);
                               4461                 :                : 
                               4462   [ +  +  +  + ]:             33 :     while (found && --fldnum > 0)
                               4463                 :                :     {
                               4464                 :                :         /* identify bounds of next field */
                               4465                 :             15 :         start_ptr = end_ptr + fldsep_len;
                               4466                 :             15 :         found = text_position_next(&state);
                               4467         [ +  + ]:             15 :         if (found)
                               4468                 :              9 :             end_ptr = text_position_get_match_ptr(&state);
                               4469                 :                :     }
                               4470                 :                : 
 6399 tgl@sss.pgh.pa.us        4471                 :             18 :     text_position_cleanup(&state);
                               4472                 :                : 
                               4473         [ +  + ]:             18 :     if (fldnum > 0)
                               4474                 :                :     {
                               4475                 :                :         /* N'th field separator not found */
                               4476                 :                :         /* if last field requested, return it, else empty string */
                               4477         [ +  + ]:              6 :         if (fldnum == 1)
                               4478                 :                :         {
 1906 heikki.linnakangas@i     4479         [ -  + ]:              3 :             int         last_len = start_ptr - VARDATA_ANY(inputstring);
                               4480                 :                : 
                               4481                 :              3 :             result_text = cstring_to_text_with_len(start_ptr,
                               4482                 :                :                                                    inputstring_len - last_len);
                               4483                 :                :         }
                               4484                 :                :         else
 5864 tgl@sss.pgh.pa.us        4485                 :              3 :             result_text = cstring_to_text("");
                               4486                 :                :     }
                               4487                 :                :     else
                               4488                 :                :     {
                               4489                 :                :         /* non-last field requested */
 1906 heikki.linnakangas@i     4490                 :             12 :         result_text = cstring_to_text_with_len(start_ptr, end_ptr - start_ptr);
                               4491                 :                :     }
                               4492                 :                : 
 6399 tgl@sss.pgh.pa.us        4493                 :             18 :     PG_RETURN_TEXT_P(result_text);
                               4494                 :                : }
                               4495                 :                : 
                               4496                 :                : /*
                               4497                 :                :  * Convenience function to return true when two text params are equal.
                               4498                 :                :  */
                               4499                 :                : static bool
 1850 peter@eisentraut.org     4500                 :            174 : text_isequal(text *txt1, text *txt2, Oid collid)
                               4501                 :                : {
                               4502                 :            174 :     return DatumGetBool(DirectFunctionCall2Coll(texteq,
                               4503                 :                :                                                 collid,
                               4504                 :                :                                                 PointerGetDatum(txt1),
                               4505                 :                :                                                 PointerGetDatum(txt2)));
                               4506                 :                : }
                               4507                 :                : 
                               4508                 :                : /*
                               4509                 :                :  * text_to_array
                               4510                 :                :  * parse input string and return text array of elements,
                               4511                 :                :  * based on provided field separator
                               4512                 :                :  */
                               4513                 :                : Datum
 7597 tgl@sss.pgh.pa.us        4514                 :             73 : text_to_array(PG_FUNCTION_ARGS)
                               4515                 :                : {
                               4516                 :                :     SplitTextOutputData tstate;
                               4517                 :                : 
                               4518                 :                :     /* For array output, tstate should start as all zeroes */
 1320                          4519                 :             73 :     memset(&tstate, 0, sizeof(tstate));
                               4520                 :                : 
                               4521         [ +  + ]:             73 :     if (!split_text(fcinfo, &tstate))
                               4522                 :              3 :         PG_RETURN_NULL();
                               4523                 :                : 
                               4524         [ +  + ]:             64 :     if (tstate.astate == NULL)
                               4525                 :              3 :         PG_RETURN_ARRAYTYPE_P(construct_empty_array(TEXTOID));
                               4526                 :                : 
  595 peter@eisentraut.org     4527                 :             61 :     PG_RETURN_DATUM(makeArrayResult(tstate.astate,
                               4528                 :                :                                     CurrentMemoryContext));
                               4529                 :                : }
                               4530                 :                : 
                               4531                 :                : /*
                               4532                 :                :  * text_to_array_null
                               4533                 :                :  * parse input string and return text array of elements,
                               4534                 :                :  * based on provided field separator and null string
                               4535                 :                :  *
                               4536                 :                :  * This is a separate entry point only to prevent the regression tests from
                               4537                 :                :  * complaining about different argument sets for the same internal function.
                               4538                 :                :  */
                               4539                 :                : Datum
 4996 tgl@sss.pgh.pa.us        4540                 :             30 : text_to_array_null(PG_FUNCTION_ARGS)
                               4541                 :                : {
 1320                          4542                 :             30 :     return text_to_array(fcinfo);
                               4543                 :                : }
                               4544                 :                : 
                               4545                 :                : /*
                               4546                 :                :  * text_to_table
                               4547                 :                :  * parse input string and return table of elements,
                               4548                 :                :  * based on provided field separator
                               4549                 :                :  */
                               4550                 :                : Datum
                               4551                 :             42 : text_to_table(PG_FUNCTION_ARGS)
                               4552                 :                : {
                               4553                 :             42 :     ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
                               4554                 :                :     SplitTextOutputData tstate;
                               4555                 :                : 
                               4556                 :             42 :     tstate.astate = NULL;
  544 michael@paquier.xyz      4557                 :             42 :     InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC);
  769                          4558                 :             42 :     tstate.tupstore = rsi->setResult;
                               4559                 :             42 :     tstate.tupdesc = rsi->setDesc;
                               4560                 :                : 
 1320 tgl@sss.pgh.pa.us        4561                 :             42 :     (void) split_text(fcinfo, &tstate);
                               4562                 :                : 
                               4563                 :             42 :     return (Datum) 0;
                               4564                 :                : }
                               4565                 :                : 
                               4566                 :                : /*
                               4567                 :                :  * text_to_table_null
                               4568                 :                :  * parse input string and return table of elements,
                               4569                 :                :  * based on provided field separator and null string
                               4570                 :                :  *
                               4571                 :                :  * This is a separate entry point only to prevent the regression tests from
                               4572                 :                :  * complaining about different argument sets for the same internal function.
                               4573                 :                :  */
                               4574                 :                : Datum
                               4575                 :             12 : text_to_table_null(PG_FUNCTION_ARGS)
                               4576                 :                : {
                               4577                 :             12 :     return text_to_table(fcinfo);
                               4578                 :                : }
                               4579                 :                : 
                               4580                 :                : /*
                               4581                 :                :  * Common code for text_to_array, text_to_array_null, text_to_table
                               4582                 :                :  * and text_to_table_null functions.
                               4583                 :                :  *
                               4584                 :                :  * These are not strict so we have to test for null inputs explicitly.
                               4585                 :                :  * Returns false if result is to be null, else returns true.
                               4586                 :                :  *
                               4587                 :                :  * Note that if the result is valid but empty (zero elements), we return
                               4588                 :                :  * without changing *tstate --- caller must handle that case, too.
                               4589                 :                :  */
                               4590                 :                : static bool
                               4591                 :            115 : split_text(FunctionCallInfo fcinfo, SplitTextOutputData *tstate)
                               4592                 :                : {
                               4593                 :                :     text       *inputstring;
                               4594                 :                :     text       *fldsep;
                               4595                 :                :     text       *null_string;
                               4596                 :            115 :     Oid         collation = PG_GET_COLLATION();
                               4597                 :                :     int         inputstring_len;
                               4598                 :                :     int         fldsep_len;
                               4599                 :                :     char       *start_ptr;
                               4600                 :                :     text       *result_text;
                               4601                 :                : 
                               4602                 :                :     /* when input string is NULL, then result is NULL too */
 4996                          4603         [ +  + ]:            115 :     if (PG_ARGISNULL(0))
 1320                          4604                 :              6 :         return false;
                               4605                 :                : 
 4996                          4606                 :            109 :     inputstring = PG_GETARG_TEXT_PP(0);
                               4607                 :                : 
                               4608                 :                :     /* fldsep can be NULL */
                               4609         [ +  + ]:            109 :     if (!PG_ARGISNULL(1))
                               4610                 :             94 :         fldsep = PG_GETARG_TEXT_PP(1);
                               4611                 :                :     else
                               4612                 :             15 :         fldsep = NULL;
                               4613                 :                : 
                               4614                 :                :     /* null_string can be NULL or omitted */
                               4615   [ +  +  +  - ]:            109 :     if (PG_NARGS() > 2 && !PG_ARGISNULL(2))
                               4616                 :             42 :         null_string = PG_GETARG_TEXT_PP(2);
                               4617                 :                :     else
                               4618                 :             67 :         null_string = NULL;
                               4619                 :                : 
                               4620         [ +  + ]:            109 :     if (fldsep != NULL)
                               4621                 :                :     {
                               4622                 :                :         /*
                               4623                 :                :          * Normal case with non-null fldsep.  Use the text_position machinery
                               4624                 :                :          * to search for occurrences of fldsep.
                               4625                 :                :          */
                               4626                 :                :         TextPositionState state;
                               4627                 :                : 
 1906 heikki.linnakangas@i     4628   [ -  +  -  -  :             94 :         inputstring_len = VARSIZE_ANY_EXHDR(inputstring);
                                     -  -  -  -  -  
                                                 + ]
                               4629   [ -  +  -  -  :             94 :         fldsep_len = VARSIZE_ANY_EXHDR(fldsep);
                                     -  -  -  -  -  
                                                 + ]
                               4630                 :                : 
                               4631                 :                :         /* return empty set for empty input string */
 4996 tgl@sss.pgh.pa.us        4632         [ +  + ]:             94 :         if (inputstring_len < 1)
 1320                          4633                 :             30 :             return true;
                               4634                 :                : 
                               4635                 :                :         /* empty field separator: return input string as a one-element set */
 4996                          4636         [ +  + ]:             88 :         if (fldsep_len < 1)
                               4637                 :                :         {
 1320                          4638                 :             24 :             split_text_accum_result(tstate, inputstring,
                               4639                 :                :                                     null_string, collation);
                               4640                 :             24 :             return true;
                               4641                 :                :         }
                               4642                 :                : 
                               4643                 :             64 :         text_position_setup(inputstring, fldsep, collation, &state);
                               4644                 :                : 
 4996                          4645         [ -  + ]:             58 :         start_ptr = VARDATA_ANY(inputstring);
                               4646                 :                : 
                               4647                 :                :         for (;;)
                               4648                 :            232 :         {
                               4649                 :                :             bool        found;
                               4650                 :                :             char       *end_ptr;
                               4651                 :                :             int         chunk_len;
                               4652                 :                : 
 1906 heikki.linnakangas@i     4653         [ -  + ]:            290 :             CHECK_FOR_INTERRUPTS();
                               4654                 :                : 
                               4655                 :            290 :             found = text_position_next(&state);
                               4656         [ +  + ]:            290 :             if (!found)
                               4657                 :                :             {
                               4658                 :                :                 /* fetch last field */
 4996 tgl@sss.pgh.pa.us        4659   [ -  +  -  -  :             58 :                 chunk_len = ((char *) inputstring + VARSIZE_ANY(inputstring)) - start_ptr;
                                     -  -  -  -  -  
                                                 + ]
 1906                          4660                 :             58 :                 end_ptr = NULL; /* not used, but some compilers complain */
                               4661                 :                :             }
                               4662                 :                :             else
                               4663                 :                :             {
                               4664                 :                :                 /* fetch non-last field */
      heikki.linnakangas@i     4665                 :            232 :                 end_ptr = text_position_get_match_ptr(&state);
                               4666                 :            232 :                 chunk_len = end_ptr - start_ptr;
                               4667                 :                :             }
                               4668                 :                : 
                               4669                 :                :             /* build a temp text datum to pass to split_text_accum_result */
 4996 tgl@sss.pgh.pa.us        4670                 :            290 :             result_text = cstring_to_text_with_len(start_ptr, chunk_len);
                               4671                 :                : 
                               4672                 :                :             /* stash away this field */
 1320                          4673                 :            290 :             split_text_accum_result(tstate, result_text,
                               4674                 :                :                                     null_string, collation);
                               4675                 :                : 
 4996                          4676                 :            290 :             pfree(result_text);
                               4677                 :                : 
 1906 heikki.linnakangas@i     4678         [ +  + ]:            290 :             if (!found)
 4996 tgl@sss.pgh.pa.us        4679                 :             58 :                 break;
                               4680                 :                : 
 1906 heikki.linnakangas@i     4681                 :            232 :             start_ptr = end_ptr + fldsep_len;
                               4682                 :                :         }
                               4683                 :                : 
 4996 tgl@sss.pgh.pa.us        4684                 :             58 :         text_position_cleanup(&state);
                               4685                 :                :     }
                               4686                 :                :     else
                               4687                 :                :     {
                               4688                 :                :         /*
                               4689                 :                :          * When fldsep is NULL, each character in the input string becomes a
                               4690                 :                :          * separate element in the result set.  The separator is effectively
                               4691                 :                :          * the space between characters.
                               4692                 :                :          */
                               4693   [ -  +  -  -  :             15 :         inputstring_len = VARSIZE_ANY_EXHDR(inputstring);
                                     -  -  -  -  -  
                                                 + ]
                               4694                 :                : 
                               4695         [ -  + ]:             15 :         start_ptr = VARDATA_ANY(inputstring);
                               4696                 :                : 
                               4697         [ +  + ]:            126 :         while (inputstring_len > 0)
                               4698                 :                :         {
 4753 bruce@momjian.us         4699                 :            111 :             int         chunk_len = pg_mblen(start_ptr);
                               4700                 :                : 
 4996 tgl@sss.pgh.pa.us        4701         [ -  + ]:            111 :             CHECK_FOR_INTERRUPTS();
                               4702                 :                : 
                               4703                 :                :             /* build a temp text datum to pass to split_text_accum_result */
                               4704                 :            111 :             result_text = cstring_to_text_with_len(start_ptr, chunk_len);
                               4705                 :                : 
                               4706                 :                :             /* stash away this field */
 1320                          4707                 :            111 :             split_text_accum_result(tstate, result_text,
                               4708                 :                :                                     null_string, collation);
                               4709                 :                : 
 4996                          4710                 :            111 :             pfree(result_text);
                               4711                 :                : 
                               4712                 :            111 :             start_ptr += chunk_len;
                               4713                 :            111 :             inputstring_len -= chunk_len;
                               4714                 :                :         }
                               4715                 :                :     }
                               4716                 :                : 
 1320                          4717                 :             73 :     return true;
                               4718                 :                : }
                               4719                 :                : 
                               4720                 :                : /*
                               4721                 :                :  * Add text item to result set (table or array).
                               4722                 :                :  *
                               4723                 :                :  * This is also responsible for checking to see if the item matches
                               4724                 :                :  * the null_string, in which case we should emit NULL instead.
                               4725                 :                :  */
                               4726                 :                : static void
                               4727                 :            425 : split_text_accum_result(SplitTextOutputData *tstate,
                               4728                 :                :                         text *field_value,
                               4729                 :                :                         text *null_string,
                               4730                 :                :                         Oid collation)
                               4731                 :                : {
                               4732                 :            425 :     bool        is_null = false;
                               4733                 :                : 
                               4734   [ +  +  +  + ]:            425 :     if (null_string && text_isequal(field_value, null_string, collation))
                               4735                 :             30 :         is_null = true;
                               4736                 :                : 
                               4737         [ +  + ]:            425 :     if (tstate->tupstore)
                               4738                 :                :     {
                               4739                 :                :         Datum       values[1];
                               4740                 :                :         bool        nulls[1];
                               4741                 :                : 
                               4742                 :            114 :         values[0] = PointerGetDatum(field_value);
                               4743                 :            114 :         nulls[0] = is_null;
                               4744                 :                : 
                               4745                 :            114 :         tuplestore_putvalues(tstate->tupstore,
                               4746                 :                :                              tstate->tupdesc,
                               4747                 :                :                              values,
                               4748                 :                :                              nulls);
                               4749                 :                :     }
                               4750                 :                :     else
                               4751                 :                :     {
                               4752                 :            311 :         tstate->astate = accumArrayResult(tstate->astate,
                               4753                 :                :                                           PointerGetDatum(field_value),
                               4754                 :                :                                           is_null,
                               4755                 :                :                                           TEXTOID,
                               4756                 :                :                                           CurrentMemoryContext);
                               4757                 :                :     }
 7597                          4758                 :            425 : }
                               4759                 :                : 
                               4760                 :                : /*
                               4761                 :                :  * array_to_text
                               4762                 :                :  * concatenate Cstring representation of input array elements
                               4763                 :                :  * using provided field separator
                               4764                 :                :  */
                               4765                 :                : Datum
                               4766                 :          32896 : array_to_text(PG_FUNCTION_ARGS)
                               4767                 :                : {
                               4768                 :          32896 :     ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
 5864                          4769                 :          32896 :     char       *fldsep = text_to_cstring(PG_GETARG_TEXT_PP(1));
                               4770                 :                : 
 4996                          4771                 :          32896 :     PG_RETURN_TEXT_P(array_to_text_internal(fcinfo, v, fldsep, NULL));
                               4772                 :                : }
                               4773                 :                : 
                               4774                 :                : /*
                               4775                 :                :  * array_to_text_null
                               4776                 :                :  * concatenate Cstring representation of input array elements
                               4777                 :                :  * using provided field separator and null string
                               4778                 :                :  *
                               4779                 :                :  * This version is not strict so we have to test for null inputs explicitly.
                               4780                 :                :  */
                               4781                 :                : Datum
                               4782                 :              6 : array_to_text_null(PG_FUNCTION_ARGS)
                               4783                 :                : {
                               4784                 :                :     ArrayType  *v;
                               4785                 :                :     char       *fldsep;
                               4786                 :                :     char       *null_string;
                               4787                 :                : 
                               4788                 :                :     /* returns NULL when first or second parameter is NULL */
                               4789   [ +  -  -  + ]:              6 :     if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
 4996 tgl@sss.pgh.pa.us        4790                 :UBC           0 :         PG_RETURN_NULL();
                               4791                 :                : 
 4996 tgl@sss.pgh.pa.us        4792                 :CBC           6 :     v = PG_GETARG_ARRAYTYPE_P(0);
                               4793                 :              6 :     fldsep = text_to_cstring(PG_GETARG_TEXT_PP(1));
                               4794                 :                : 
                               4795                 :                :     /* NULL null string is passed through as a null pointer */
                               4796         [ +  + ]:              6 :     if (!PG_ARGISNULL(2))
                               4797                 :              3 :         null_string = text_to_cstring(PG_GETARG_TEXT_PP(2));
                               4798                 :                :     else
                               4799                 :              3 :         null_string = NULL;
                               4800                 :                : 
                               4801                 :              6 :     PG_RETURN_TEXT_P(array_to_text_internal(fcinfo, v, fldsep, null_string));
                               4802                 :                : }
                               4803                 :                : 
                               4804                 :                : /*
                               4805                 :                :  * common code for array_to_text and array_to_text_null functions
                               4806                 :                :  */
                               4807                 :                : static text *
                               4808                 :          32911 : array_to_text_internal(FunctionCallInfo fcinfo, ArrayType *v,
                               4809                 :                :                        const char *fldsep, const char *null_string)
                               4810                 :                : {
                               4811                 :                :     text       *result;
                               4812                 :                :     int         nitems,
                               4813                 :                :                *dims,
                               4814                 :                :                 ndims;
                               4815                 :                :     Oid         element_type;
                               4816                 :                :     int         typlen;
                               4817                 :                :     bool        typbyval;
                               4818                 :                :     char        typalign;
                               4819                 :                :     StringInfoData buf;
 6722                          4820                 :          32911 :     bool        printed = false;
                               4821                 :                :     char       *p;
                               4822                 :                :     bits8      *bitmap;
                               4823                 :                :     int         bitmask;
                               4824                 :                :     int         i;
                               4825                 :                :     ArrayMetaState *my_extra;
                               4826                 :                : 
 7597                          4827                 :          32911 :     ndims = ARR_NDIM(v);
                               4828                 :          32911 :     dims = ARR_DIMS(v);
                               4829                 :          32911 :     nitems = ArrayGetNItems(ndims, dims);
                               4830                 :                : 
                               4831                 :                :     /* if there are no elements, return an empty string */
                               4832         [ +  + ]:          32911 :     if (nitems == 0)
 4996                          4833                 :          20845 :         return cstring_to_text_with_len("", 0);
                               4834                 :                : 
 7597                          4835                 :          12066 :     element_type = ARR_ELEMTYPE(v);
 6619 neilc@samurai.com        4836                 :          12066 :     initStringInfo(&buf);
                               4837                 :                : 
                               4838                 :                :     /*
                               4839                 :                :      * We arrange to look up info about element type, including its output
                               4840                 :                :      * conversion proc, only once per series of calls, assuming the element
                               4841                 :                :      * type doesn't change underneath us.
                               4842                 :                :      */
 7597 tgl@sss.pgh.pa.us        4843                 :          12066 :     my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
                               4844         [ +  + ]:          12066 :     if (my_extra == NULL)
                               4845                 :                :     {
                               4846                 :            697 :         fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
                               4847                 :                :                                                       sizeof(ArrayMetaState));
                               4848                 :            697 :         my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
 6722                          4849                 :            697 :         my_extra->element_type = ~element_type;
                               4850                 :                :     }
                               4851                 :                : 
 7597                          4852         [ +  + ]:          12066 :     if (my_extra->element_type != element_type)
                               4853                 :                :     {
                               4854                 :                :         /*
                               4855                 :                :          * Get info about element type, including its output conversion proc
                               4856                 :                :          */
                               4857                 :            697 :         get_type_io_data(element_type, IOFunc_output,
                               4858                 :                :                          &my_extra->typlen, &my_extra->typbyval,
                               4859                 :                :                          &my_extra->typalign, &my_extra->typdelim,
                               4860                 :                :                          &my_extra->typioparam, &my_extra->typiofunc);
                               4861                 :            697 :         fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
                               4862                 :            697 :                       fcinfo->flinfo->fn_mcxt);
                               4863                 :            697 :         my_extra->element_type = element_type;
                               4864                 :                :     }
                               4865                 :          12066 :     typlen = my_extra->typlen;
                               4866                 :          12066 :     typbyval = my_extra->typbyval;
                               4867                 :          12066 :     typalign = my_extra->typalign;
                               4868                 :                : 
 6722                          4869         [ +  + ]:          12066 :     p = ARR_DATA_PTR(v);
                               4870         [ +  + ]:          12066 :     bitmap = ARR_NULLBITMAP(v);
                               4871                 :          12066 :     bitmask = 1;
                               4872                 :                : 
 7597                          4873         [ +  + ]:          41082 :     for (i = 0; i < nitems; i++)
                               4874                 :                :     {
                               4875                 :                :         Datum       itemvalue;
                               4876                 :                :         char       *value;
                               4877                 :                : 
                               4878                 :                :         /* Get source element, checking for NULL */
 6722                          4879   [ +  +  +  + ]:          29016 :         if (bitmap && (*bitmap & bitmask) == 0)
                               4880                 :                :         {
                               4881                 :                :             /* if null_string is NULL, we just ignore null elements */
 4996                          4882         [ +  + ]:              9 :             if (null_string != NULL)
                               4883                 :                :             {
                               4884         [ +  - ]:              3 :                 if (printed)
                               4885                 :              3 :                     appendStringInfo(&buf, "%s%s", fldsep, null_string);
                               4886                 :                :                 else
 4996 tgl@sss.pgh.pa.us        4887                 :UBC           0 :                     appendStringInfoString(&buf, null_string);
 4996 tgl@sss.pgh.pa.us        4888                 :CBC           3 :                 printed = true;
                               4889                 :                :             }
                               4890                 :                :         }
                               4891                 :                :         else
                               4892                 :                :         {
 6722                          4893                 :          29007 :             itemvalue = fetch_att(p, typbyval, typlen);
                               4894                 :                : 
 6585                          4895                 :          29007 :             value = OutputFunctionCall(&my_extra->proc, itemvalue);
                               4896                 :                : 
 6722                          4897         [ +  + ]:          29007 :             if (printed)
 6619 neilc@samurai.com        4898                 :          16941 :                 appendStringInfo(&buf, "%s%s", fldsep, value);
                               4899                 :                :             else
                               4900                 :          12066 :                 appendStringInfoString(&buf, value);
 6722 tgl@sss.pgh.pa.us        4901                 :          29007 :             printed = true;
                               4902                 :                : 
 6218                          4903   [ +  +  +  -  :          29007 :             p = att_addlength_pointer(p, typlen, p);
                                     -  +  -  -  -  
                                     -  -  -  -  +  
                                              -  - ]
                               4904   [ +  +  +  +  :          29007 :             p = (char *) att_align_nominal(p, typalign);
                                        +  -  -  - ]
                               4905                 :                :         }
                               4906                 :                : 
                               4907                 :                :         /* advance bitmap pointer if any */
 6722                          4908         [ +  + ]:          29016 :         if (bitmap)
                               4909                 :                :         {
                               4910                 :             54 :             bitmask <<= 1;
                               4911         [ -  + ]:             54 :             if (bitmask == 0x100)
                               4912                 :                :             {
 6722 tgl@sss.pgh.pa.us        4913                 :UBC           0 :                 bitmap++;
                               4914                 :              0 :                 bitmask = 1;
                               4915                 :                :             }
                               4916                 :                :         }
                               4917                 :                :     }
                               4918                 :                : 
 4996 tgl@sss.pgh.pa.us        4919                 :CBC       12066 :     result = cstring_to_text_with_len(buf.data, buf.len);
                               4920                 :          12066 :     pfree(buf.data);
                               4921                 :                : 
                               4922                 :          12066 :     return result;
                               4923                 :                : }
                               4924                 :                : 
                               4925                 :                : /*
                               4926                 :                :  * Workhorse for to_bin, to_oct, and to_hex.  Note that base must be > 1 and <=
                               4927                 :                :  * 16.
                               4928                 :                :  */
                               4929                 :                : static inline text *
  235 nathan@postgresql.or     4930                 :GNC       19375 : convert_to_base(uint64 value, int base)
                               4931                 :                : {
 7422 tgl@sss.pgh.pa.us        4932                 :          19375 :     const char *digits = "0123456789abcdef";
                               4933                 :                : 
                               4934                 :                :     /* We size the buffer for to_bin's longest possible return value. */
                               4935                 :                :     char        buf[sizeof(uint64) * BITS_PER_BYTE];
  235 nathan@postgresql.or     4936                 :          19375 :     char       *const end = buf + sizeof(buf);
                               4937                 :          19375 :     char       *ptr = end;
                               4938                 :                : 
                               4939         [ -  + ]:          19375 :     Assert(base > 1);
                               4940         [ -  + ]:          19375 :     Assert(base <= 16);
                               4941                 :                : 
                               4942                 :                :     do
                               4943                 :                :     {
                               4944                 :          37987 :         *--ptr = digits[value % base];
                               4945                 :          37987 :         value /= base;
 7906 bruce@momjian.us         4946   [ +  +  +  + ]:          37987 :     } while (ptr > buf && value);
                               4947                 :                : 
  235 nathan@postgresql.or     4948                 :          19375 :     return cstring_to_text_with_len(ptr, end - ptr);
                               4949                 :                : }
                               4950                 :                : 
                               4951                 :                : /*
                               4952                 :                :  * Convert an integer to a string containing a base-2 (binary) representation
                               4953                 :                :  * of the number.
                               4954                 :                :  */
                               4955                 :                : Datum
                               4956                 :              6 : to_bin32(PG_FUNCTION_ARGS)
                               4957                 :                : {
                               4958                 :              6 :     uint64      value = (uint32) PG_GETARG_INT32(0);
                               4959                 :                : 
                               4960                 :              6 :     PG_RETURN_TEXT_P(convert_to_base(value, 2));
                               4961                 :                : }
                               4962                 :                : Datum
                               4963                 :              6 : to_bin64(PG_FUNCTION_ARGS)
                               4964                 :                : {
                               4965                 :              6 :     uint64      value = (uint64) PG_GETARG_INT64(0);
                               4966                 :                : 
                               4967                 :              6 :     PG_RETURN_TEXT_P(convert_to_base(value, 2));
                               4968                 :                : }
                               4969                 :                : 
                               4970                 :                : /*
                               4971                 :                :  * Convert an integer to a string containing a base-8 (oct) representation of
                               4972                 :                :  * the number.
                               4973                 :                :  */
                               4974                 :                : Datum
                               4975                 :              6 : to_oct32(PG_FUNCTION_ARGS)
                               4976                 :                : {
                               4977                 :              6 :     uint64      value = (uint32) PG_GETARG_INT32(0);
                               4978                 :                : 
                               4979                 :              6 :     PG_RETURN_TEXT_P(convert_to_base(value, 8));
                               4980                 :                : }
                               4981                 :                : Datum
                               4982                 :              6 : to_oct64(PG_FUNCTION_ARGS)
                               4983                 :                : {
 7422 tgl@sss.pgh.pa.us        4984                 :              6 :     uint64      value = (uint64) PG_GETARG_INT64(0);
                               4985                 :                : 
  235 nathan@postgresql.or     4986                 :              6 :     PG_RETURN_TEXT_P(convert_to_base(value, 8));
                               4987                 :                : }
                               4988                 :                : 
                               4989                 :                : /*
                               4990                 :                :  * Convert an integer to a string containing a base-16 (hex) representation of
                               4991                 :                :  * the number.
                               4992                 :                :  */
                               4993                 :                : Datum
  235 nathan@postgresql.or     4994                 :CBC       19345 : to_hex32(PG_FUNCTION_ARGS)
                               4995                 :                : {
  235 nathan@postgresql.or     4996                 :GNC       19345 :     uint64      value = (uint32) PG_GETARG_INT32(0);
                               4997                 :                : 
                               4998                 :          19345 :     PG_RETURN_TEXT_P(convert_to_base(value, 16));
                               4999                 :                : }
                               5000                 :                : Datum
  235 nathan@postgresql.or     5001                 :CBC           6 : to_hex64(PG_FUNCTION_ARGS)
                               5002                 :                : {
                               5003                 :              6 :     uint64      value = (uint64) PG_GETARG_INT64(0);
                               5004                 :                : 
  235 nathan@postgresql.or     5005                 :GNC           6 :     PG_RETURN_TEXT_P(convert_to_base(value, 16));
                               5006                 :                : }
                               5007                 :                : 
                               5008                 :                : /*
                               5009                 :                :  * Return the size of a datum, possibly compressed
                               5010                 :                :  *
                               5011                 :                :  * Works on any data type
                               5012                 :                :  */
                               5013                 :                : Datum
 6857 bruce@momjian.us         5014                 :CBC          61 : pg_column_size(PG_FUNCTION_ARGS)
                               5015                 :                : {
 6830 tgl@sss.pgh.pa.us        5016                 :             61 :     Datum       value = PG_GETARG_DATUM(0);
                               5017                 :                :     int32       result;
                               5018                 :                :     int         typlen;
                               5019                 :                : 
                               5020                 :                :     /* On first call, get the input type's typlen, and save at *fn_extra */
                               5021         [ +  - ]:             61 :     if (fcinfo->flinfo->fn_extra == NULL)
                               5022                 :                :     {
                               5023                 :                :         /* Lookup the datatype of the supplied argument */
 6756 bruce@momjian.us         5024                 :             61 :         Oid         argtypeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
                               5025                 :                : 
 6830 tgl@sss.pgh.pa.us        5026                 :             61 :         typlen = get_typlen(argtypeid);
                               5027         [ -  + ]:             61 :         if (typlen == 0)        /* should not happen */
 6856 bruce@momjian.us         5028         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for type %u", argtypeid);
                               5029                 :                : 
 6857 bruce@momjian.us         5030                 :CBC          61 :         fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
                               5031                 :                :                                                       sizeof(int));
 6830 tgl@sss.pgh.pa.us        5032                 :             61 :         *((int *) fcinfo->flinfo->fn_extra) = typlen;
                               5033                 :                :     }
                               5034                 :                :     else
 6830 tgl@sss.pgh.pa.us        5035                 :UBC           0 :         typlen = *((int *) fcinfo->flinfo->fn_extra);
                               5036                 :                : 
 6830 tgl@sss.pgh.pa.us        5037         [ +  - ]:CBC          61 :     if (typlen == -1)
                               5038                 :                :     {
                               5039                 :                :         /* varlena type, possibly toasted */
                               5040                 :             61 :         result = toast_datum_size(value);
                               5041                 :                :     }
 6830 tgl@sss.pgh.pa.us        5042         [ #  # ]:UBC           0 :     else if (typlen == -2)
                               5043                 :                :     {
                               5044                 :                :         /* cstring */
                               5045                 :              0 :         result = strlen(DatumGetCString(value)) + 1;
                               5046                 :                :     }
                               5047                 :                :     else
                               5048                 :                :     {
                               5049                 :                :         /* ordinary fixed-width type */
                               5050                 :              0 :         result = typlen;
                               5051                 :                :     }
                               5052                 :                : 
 6830 tgl@sss.pgh.pa.us        5053                 :CBC          61 :     PG_RETURN_INT32(result);
                               5054                 :                : }
                               5055                 :                : 
                               5056                 :                : /*
                               5057                 :                :  * Return the compression method stored in the compressed attribute.  Return
                               5058                 :                :  * NULL for non varlena type or uncompressed data.
                               5059                 :                :  */
                               5060                 :                : Datum
 1122 rhaas@postgresql.org     5061                 :             81 : pg_column_compression(PG_FUNCTION_ARGS)
                               5062                 :                : {
                               5063                 :                :     int         typlen;
                               5064                 :                :     char       *result;
                               5065                 :                :     ToastCompressionId cmid;
                               5066                 :                : 
                               5067                 :                :     /* On first call, get the input type's typlen, and save at *fn_extra */
                               5068         [ +  + ]:             81 :     if (fcinfo->flinfo->fn_extra == NULL)
                               5069                 :                :     {
                               5070                 :                :         /* Lookup the datatype of the supplied argument */
                               5071                 :             54 :         Oid         argtypeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
                               5072                 :                : 
                               5073                 :             54 :         typlen = get_typlen(argtypeid);
                               5074         [ -  + ]:             54 :         if (typlen == 0)        /* should not happen */
 1122 rhaas@postgresql.org     5075         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for type %u", argtypeid);
                               5076                 :                : 
 1122 rhaas@postgresql.org     5077                 :CBC          54 :         fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
                               5078                 :                :                                                       sizeof(int));
                               5079                 :             54 :         *((int *) fcinfo->flinfo->fn_extra) = typlen;
                               5080                 :                :     }
                               5081                 :                :     else
                               5082                 :             27 :         typlen = *((int *) fcinfo->flinfo->fn_extra);
                               5083                 :                : 
                               5084         [ -  + ]:             81 :     if (typlen != -1)
 1122 rhaas@postgresql.org     5085                 :UBC           0 :         PG_RETURN_NULL();
                               5086                 :                : 
                               5087                 :                :     /* get the compression method id stored in the compressed varlena */
 1122 rhaas@postgresql.org     5088                 :CBC          81 :     cmid = toast_get_compression_id((struct varlena *)
                               5089                 :             81 :                                     DatumGetPointer(PG_GETARG_DATUM(0)));
                               5090         [ +  + ]:             81 :     if (cmid == TOAST_INVALID_COMPRESSION_ID)
                               5091                 :              3 :         PG_RETURN_NULL();
                               5092                 :                : 
                               5093                 :                :     /* convert compression method id to compression method name */
                               5094      [ +  +  - ]:             78 :     switch (cmid)
                               5095                 :                :     {
                               5096                 :             33 :         case TOAST_PGLZ_COMPRESSION_ID:
                               5097                 :             33 :             result = "pglz";
                               5098                 :             33 :             break;
                               5099                 :             45 :         case TOAST_LZ4_COMPRESSION_ID:
                               5100                 :             45 :             result = "lz4";
                               5101                 :             45 :             break;
 1122 rhaas@postgresql.org     5102                 :UBC           0 :         default:
                               5103         [ #  # ]:              0 :             elog(ERROR, "invalid compression method id %d", cmid);
                               5104                 :                :     }
                               5105                 :                : 
 1122 rhaas@postgresql.org     5106                 :CBC          78 :     PG_RETURN_TEXT_P(cstring_to_text(result));
                               5107                 :                : }
                               5108                 :                : 
                               5109                 :                : /*
                               5110                 :                :  * Return the chunk_id of the on-disk TOASTed value.  Return NULL if the value
                               5111                 :                :  * is un-TOASTed or not on-disk.
                               5112                 :                :  */
                               5113                 :                : Datum
   31 nathan@postgresql.or     5114                 :GNC           6 : pg_column_toast_chunk_id(PG_FUNCTION_ARGS)
                               5115                 :                : {
                               5116                 :                :     int         typlen;
                               5117                 :                :     struct varlena *attr;
                               5118                 :                :     struct varatt_external toast_pointer;
                               5119                 :                : 
                               5120                 :                :     /* On first call, get the input type's typlen, and save at *fn_extra */
                               5121         [ +  - ]:              6 :     if (fcinfo->flinfo->fn_extra == NULL)
                               5122                 :                :     {
                               5123                 :                :         /* Lookup the datatype of the supplied argument */
                               5124                 :              6 :         Oid         argtypeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
                               5125                 :                : 
                               5126                 :              6 :         typlen = get_typlen(argtypeid);
                               5127         [ -  + ]:              6 :         if (typlen == 0)        /* should not happen */
   31 nathan@postgresql.or     5128         [ #  # ]:UNC           0 :             elog(ERROR, "cache lookup failed for type %u", argtypeid);
                               5129                 :                : 
   31 nathan@postgresql.or     5130                 :GNC           6 :         fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
                               5131                 :                :                                                       sizeof(int));
                               5132                 :              6 :         *((int *) fcinfo->flinfo->fn_extra) = typlen;
                               5133                 :                :     }
                               5134                 :                :     else
   31 nathan@postgresql.or     5135                 :UNC           0 :         typlen = *((int *) fcinfo->flinfo->fn_extra);
                               5136                 :                : 
   31 nathan@postgresql.or     5137         [ -  + ]:GNC           6 :     if (typlen != -1)
   31 nathan@postgresql.or     5138                 :UNC           0 :         PG_RETURN_NULL();
                               5139                 :                : 
   31 nathan@postgresql.or     5140                 :GNC           6 :     attr = (struct varlena *) DatumGetPointer(PG_GETARG_DATUM(0));
                               5141                 :                : 
                               5142   [ +  +  -  + ]:              6 :     if (!VARATT_IS_EXTERNAL_ONDISK(attr))
                               5143                 :              3 :         PG_RETURN_NULL();
                               5144                 :                : 
                               5145   [ -  +  +  -  :              3 :     VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
                                     +  -  -  +  -  
                                                 + ]
                               5146                 :                : 
                               5147                 :              3 :     PG_RETURN_OID(toast_pointer.va_valueid);
                               5148                 :                : }
                               5149                 :                : 
                               5150                 :                : /*
                               5151                 :                :  * string_agg - Concatenates values and returns string.
                               5152                 :                :  *
                               5153                 :                :  * Syntax: string_agg(value text, delimiter text) RETURNS text
                               5154                 :                :  *
                               5155                 :                :  * Note: Any NULL values are ignored. The first-call delimiter isn't
                               5156                 :                :  * actually used at all, and on subsequent calls the delimiter precedes
                               5157                 :                :  * the associated value.
                               5158                 :                :  */
                               5159                 :                : 
                               5160                 :                : /* subroutine to initialize state */
                               5161                 :                : static StringInfo
 5179 tgl@sss.pgh.pa.us        5162                 :CBC        1270 : makeStringAggState(FunctionCallInfo fcinfo)
                               5163                 :                : {
                               5164                 :                :     StringInfo  state;
                               5165                 :                :     MemoryContext aggcontext;
                               5166                 :                :     MemoryContext oldcontext;
                               5167                 :                : 
                               5168         [ -  + ]:           1270 :     if (!AggCheckCallContext(fcinfo, &aggcontext))
                               5169                 :                :     {
                               5170                 :                :         /* cannot be called directly because of internal-type argument */
 5186 itagaki.takahiro@gma     5171         [ #  # ]:UBC           0 :         elog(ERROR, "string_agg_transfn called in non-aggregate context");
                               5172                 :                :     }
                               5173                 :                : 
                               5174                 :                :     /*
                               5175                 :                :      * Create state in aggregate context.  It'll stay there across subsequent
                               5176                 :                :      * calls.
                               5177                 :                :      */
 5186 itagaki.takahiro@gma     5178                 :CBC        1270 :     oldcontext = MemoryContextSwitchTo(aggcontext);
                               5179                 :           1270 :     state = makeStringInfo();
                               5180                 :           1270 :     MemoryContextSwitchTo(oldcontext);
                               5181                 :                : 
                               5182                 :           1270 :     return state;
                               5183                 :                : }
                               5184                 :                : 
                               5185                 :                : Datum
                               5186                 :         426149 : string_agg_transfn(PG_FUNCTION_ARGS)
                               5187                 :                : {
                               5188                 :                :     StringInfo  state;
                               5189                 :                : 
                               5190         [ +  + ]:         426149 :     state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);
                               5191                 :                : 
                               5192                 :                :     /* Append the value unless null, preceding it with the delimiter. */
                               5193         [ +  + ]:         426149 :     if (!PG_ARGISNULL(1))
                               5194                 :                :     {
  447 drowley@postgresql.o     5195                 :         418625 :         text       *value = PG_GETARG_TEXT_PP(1);
                               5196                 :         418625 :         bool        isfirst = false;
                               5197                 :                : 
                               5198                 :                :         /*
                               5199                 :                :          * You might think we can just throw away the first delimiter, however
                               5200                 :                :          * we must keep it as we may be a parallel worker doing partial
                               5201                 :                :          * aggregation building a state to send to the main process.  We need
                               5202                 :                :          * to keep the delimiter of every aggregation so that the combine
                               5203                 :                :          * function can properly join up the strings of two separately
                               5204                 :                :          * partially aggregated results.  The first delimiter is only stripped
                               5205                 :                :          * off in the final function.  To know how much to strip off the front
                               5206                 :                :          * of the string, we store the length of the first delimiter in the
                               5207                 :                :          * StringInfo's cursor field, which we don't otherwise need here.
                               5208                 :                :          */
 5186 itagaki.takahiro@gma     5209         [ +  + ]:         418625 :         if (state == NULL)
                               5210                 :                :         {
 5179 tgl@sss.pgh.pa.us        5211                 :            986 :             state = makeStringAggState(fcinfo);
  447 drowley@postgresql.o     5212                 :            986 :             isfirst = true;
                               5213                 :                :         }
                               5214                 :                : 
                               5215         [ +  - ]:         418625 :         if (!PG_ARGISNULL(2))
                               5216                 :                :         {
                               5217                 :         418625 :             text       *delim = PG_GETARG_TEXT_PP(2);
                               5218                 :                : 
                               5219                 :         418625 :             appendStringInfoText(state, delim);
                               5220         [ +  + ]:         418625 :             if (isfirst)
                               5221   [ -  +  -  -  :            986 :                 state->cursor = VARSIZE_ANY_EXHDR(delim);
                                     -  -  -  -  +  
                                                 + ]
                               5222                 :                :         }
                               5223                 :                : 
                               5224                 :         418625 :         appendStringInfoText(state, value);
                               5225                 :                :     }
                               5226                 :                : 
                               5227                 :                :     /*
                               5228                 :                :      * The transition type for string_agg() is declared to be "internal",
                               5229                 :                :      * which is a pass-by-value type the same size as a pointer.
                               5230                 :                :      */
                               5231         [ +  + ]:         426149 :     if (state)
                               5232                 :         426102 :         PG_RETURN_POINTER(state);
                               5233                 :             47 :     PG_RETURN_NULL();
                               5234                 :                : }
                               5235                 :                : 
                               5236                 :                : /*
                               5237                 :                :  * string_agg_combine
                               5238                 :                :  *      Aggregate combine function for string_agg(text) and string_agg(bytea)
                               5239                 :                :  */
                               5240                 :                : Datum
                               5241                 :            120 : string_agg_combine(PG_FUNCTION_ARGS)
                               5242                 :                : {
                               5243                 :                :     StringInfo  state1;
                               5244                 :                :     StringInfo  state2;
                               5245                 :                :     MemoryContext agg_context;
                               5246                 :                : 
                               5247         [ -  + ]:            120 :     if (!AggCheckCallContext(fcinfo, &agg_context))
  447 drowley@postgresql.o     5248         [ #  # ]:UBC           0 :         elog(ERROR, "aggregate function called in non-aggregate context");
                               5249                 :                : 
  447 drowley@postgresql.o     5250         [ +  + ]:CBC         120 :     state1 = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);
                               5251         [ +  - ]:            120 :     state2 = PG_ARGISNULL(1) ? NULL : (StringInfo) PG_GETARG_POINTER(1);
                               5252                 :                : 
                               5253         [ -  + ]:            120 :     if (state2 == NULL)
                               5254                 :                :     {
                               5255                 :                :         /*
                               5256                 :                :          * NULL state2 is easy, just return state1, which we know is already
                               5257                 :                :          * in the agg_context
                               5258                 :                :          */
  447 drowley@postgresql.o     5259         [ #  # ]:UBC           0 :         if (state1 == NULL)
                               5260                 :              0 :             PG_RETURN_NULL();
                               5261                 :              0 :         PG_RETURN_POINTER(state1);
                               5262                 :                :     }
                               5263                 :                : 
  447 drowley@postgresql.o     5264         [ +  + ]:CBC         120 :     if (state1 == NULL)
                               5265                 :                :     {
                               5266                 :                :         /* We must copy state2's data into the agg_context */
                               5267                 :                :         MemoryContext old_context;
                               5268                 :                : 
                               5269                 :             60 :         old_context = MemoryContextSwitchTo(agg_context);
                               5270                 :             60 :         state1 = makeStringAggState(fcinfo);
                               5271                 :             60 :         appendBinaryStringInfo(state1, state2->data, state2->len);
                               5272                 :             60 :         state1->cursor = state2->cursor;
                               5273                 :             60 :         MemoryContextSwitchTo(old_context);
                               5274                 :                :     }
                               5275         [ +  - ]:             60 :     else if (state2->len > 0)
                               5276                 :                :     {
                               5277                 :                :         /* Combine ... state1->cursor does not change in this case */
                               5278                 :             60 :         appendBinaryStringInfo(state1, state2->data, state2->len);
                               5279                 :                :     }
                               5280                 :                : 
                               5281                 :            120 :     PG_RETURN_POINTER(state1);
                               5282                 :                : }
                               5283                 :                : 
                               5284                 :                : /*
                               5285                 :                :  * string_agg_serialize
                               5286                 :                :  *      Aggregate serialize function for string_agg(text) and string_agg(bytea)
                               5287                 :                :  *
                               5288                 :                :  * This is strict, so we need not handle NULL input
                               5289                 :                :  */
                               5290                 :                : Datum
                               5291                 :            120 : string_agg_serialize(PG_FUNCTION_ARGS)
                               5292                 :                : {
                               5293                 :                :     StringInfo  state;
                               5294                 :                :     StringInfoData buf;
                               5295                 :                :     bytea      *result;
                               5296                 :                : 
                               5297                 :                :     /* cannot be called directly because of internal-type argument */
                               5298         [ -  + ]:            120 :     Assert(AggCheckCallContext(fcinfo, NULL));
                               5299                 :                : 
                               5300                 :            120 :     state = (StringInfo) PG_GETARG_POINTER(0);
                               5301                 :                : 
                               5302                 :            120 :     pq_begintypsend(&buf);
                               5303                 :                : 
                               5304                 :                :     /* cursor */
                               5305                 :            120 :     pq_sendint(&buf, state->cursor, 4);
                               5306                 :                : 
                               5307                 :                :     /* data */
                               5308                 :            120 :     pq_sendbytes(&buf, state->data, state->len);
                               5309                 :                : 
                               5310                 :            120 :     result = pq_endtypsend(&buf);
                               5311                 :                : 
                               5312                 :            120 :     PG_RETURN_BYTEA_P(result);
                               5313                 :                : }
                               5314                 :                : 
                               5315                 :                : /*
                               5316                 :                :  * string_agg_deserialize
                               5317                 :                :  *      Aggregate deserial function for string_agg(text) and string_agg(bytea)
                               5318                 :                :  *
                               5319                 :                :  * This is strict, so we need not handle NULL input
                               5320                 :                :  */
                               5321                 :                : Datum
                               5322                 :            120 : string_agg_deserialize(PG_FUNCTION_ARGS)
                               5323                 :                : {
                               5324                 :                :     bytea      *sstate;
                               5325                 :                :     StringInfo  result;
                               5326                 :                :     StringInfoData buf;
                               5327                 :                :     char       *data;
                               5328                 :                :     int         datalen;
                               5329                 :                : 
                               5330                 :                :     /* cannot be called directly because of internal-type argument */
                               5331         [ -  + ]:            120 :     Assert(AggCheckCallContext(fcinfo, NULL));
                               5332                 :                : 
                               5333                 :            120 :     sstate = PG_GETARG_BYTEA_PP(0);
                               5334                 :                : 
                               5335                 :                :     /*
                               5336                 :                :      * Initialize a StringInfo so that we can "receive" it using the standard
                               5337                 :                :      * recv-function infrastructure.
                               5338                 :                :      */
  170 drowley@postgresql.o     5339         [ -  + ]:GNC         120 :     initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
                               5340   [ -  +  -  -  :            120 :                            VARSIZE_ANY_EXHDR(sstate));
                                     -  -  -  -  -  
                                                 + ]
                               5341                 :                : 
  447 drowley@postgresql.o     5342                 :CBC         120 :     result = makeStringAggState(fcinfo);
                               5343                 :                : 
                               5344                 :                :     /* cursor */
                               5345                 :            120 :     result->cursor = pq_getmsgint(&buf, 4);
                               5346                 :                : 
                               5347                 :                :     /* data */
                               5348   [ -  +  -  -  :            120 :     datalen = VARSIZE_ANY_EXHDR(sstate) - 4;
                                     -  -  -  -  -  
                                                 + ]
                               5349                 :            120 :     data = (char *) pq_getmsgbytes(&buf, datalen);
                               5350                 :            120 :     appendBinaryStringInfo(result, data, datalen);
                               5351                 :                : 
                               5352                 :            120 :     pq_getmsgend(&buf);
                               5353                 :                : 
                               5354                 :            120 :     PG_RETURN_POINTER(result);
                               5355                 :                : }
                               5356                 :                : 
                               5357                 :                : Datum
 5186 itagaki.takahiro@gma     5358                 :            992 : string_agg_finalfn(PG_FUNCTION_ARGS)
                               5359                 :                : {
                               5360                 :                :     StringInfo  state;
                               5361                 :                : 
                               5362                 :                :     /* cannot be called directly because of internal-type argument */
 5179 tgl@sss.pgh.pa.us        5363         [ -  + ]:            992 :     Assert(AggCheckCallContext(fcinfo, NULL));
                               5364                 :                : 
                               5365         [ +  + ]:            992 :     state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);
                               5366                 :                : 
 5186 itagaki.takahiro@gma     5367         [ +  + ]:            992 :     if (state != NULL)
                               5368                 :                :     {
                               5369                 :                :         /* As per comment in transfn, strip data before the cursor position */
  447 drowley@postgresql.o     5370                 :            956 :         PG_RETURN_TEXT_P(cstring_to_text_with_len(&state->data[state->cursor],
                               5371                 :                :                                                   state->len - state->cursor));
                               5372                 :                :     }
                               5373                 :                :     else
 5186 itagaki.takahiro@gma     5374                 :             36 :         PG_RETURN_NULL();
                               5375                 :                : }
                               5376                 :                : 
                               5377                 :                : /*
                               5378                 :                :  * Prepare cache with fmgr info for the output functions of the datatypes of
                               5379                 :                :  * the arguments of a concat-like function, beginning with argument "argidx".
                               5380                 :                :  * (Arguments before that will have corresponding slots in the resulting
                               5381                 :                :  * FmgrInfo array, but we don't fill those slots.)
                               5382                 :                :  */
                               5383                 :                : static FmgrInfo *
 2399 tgl@sss.pgh.pa.us        5384                 :             23 : build_concat_foutcache(FunctionCallInfo fcinfo, int argidx)
                               5385                 :                : {
                               5386                 :                :     FmgrInfo   *foutcache;
                               5387                 :                :     int         i;
                               5388                 :                : 
                               5389                 :                :     /* We keep the info in fn_mcxt so it survives across calls */
                               5390                 :             23 :     foutcache = (FmgrInfo *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
                               5391                 :             23 :                                                 PG_NARGS() * sizeof(FmgrInfo));
                               5392                 :                : 
                               5393         [ +  + ]:            110 :     for (i = argidx; i < PG_NARGS(); i++)
                               5394                 :                :     {
                               5395                 :                :         Oid         valtype;
                               5396                 :                :         Oid         typOutput;
                               5397                 :                :         bool        typIsVarlena;
                               5398                 :                : 
                               5399                 :             87 :         valtype = get_fn_expr_argtype(fcinfo->flinfo, i);
                               5400         [ -  + ]:             87 :         if (!OidIsValid(valtype))
 2399 tgl@sss.pgh.pa.us        5401         [ #  # ]:UBC           0 :             elog(ERROR, "could not determine data type of concat() input");
                               5402                 :                : 
 2399 tgl@sss.pgh.pa.us        5403                 :CBC          87 :         getTypeOutputInfo(valtype, &typOutput, &typIsVarlena);
                               5404                 :             87 :         fmgr_info_cxt(typOutput, &foutcache[i], fcinfo->flinfo->fn_mcxt);
                               5405                 :                :     }
                               5406                 :                : 
                               5407                 :             23 :     fcinfo->flinfo->fn_extra = foutcache;
                               5408                 :                : 
                               5409                 :             23 :     return foutcache;
                               5410                 :                : }
                               5411                 :                : 
                               5412                 :                : /*
                               5413                 :                :  * Implementation of both concat() and concat_ws().
                               5414                 :                :  *
                               5415                 :                :  * sepstr is the separator string to place between values.
                               5416                 :                :  * argidx identifies the first argument to concatenate (counting from zero);
                               5417                 :                :  * note that this must be constant across any one series of calls.
                               5418                 :                :  *
                               5419                 :                :  * Returns NULL if result should be NULL, else text value.
                               5420                 :                :  */
                               5421                 :                : static text *
 4097                          5422                 :             57 : concat_internal(const char *sepstr, int argidx,
                               5423                 :                :                 FunctionCallInfo fcinfo)
                               5424                 :                : {
                               5425                 :                :     text       *result;
                               5426                 :                :     StringInfoData str;
                               5427                 :                :     FmgrInfo   *foutcache;
 4612                          5428                 :             57 :     bool        first_arg = true;
                               5429                 :                :     int         i;
                               5430                 :                : 
                               5431                 :                :     /*
                               5432                 :                :      * concat(VARIADIC some-array) is essentially equivalent to
                               5433                 :                :      * array_to_text(), ie concat the array elements with the given separator.
                               5434                 :                :      * So we just pass the case off to that code.
                               5435                 :                :      */
 4097                          5436         [ +  + ]:             57 :     if (get_fn_expr_variadic(fcinfo->flinfo))
                               5437                 :                :     {
                               5438                 :                :         ArrayType  *arr;
                               5439                 :                : 
                               5440                 :                :         /* Should have just the one argument */
                               5441         [ -  + ]:             15 :         Assert(argidx == PG_NARGS() - 1);
                               5442                 :                : 
                               5443                 :                :         /* concat(VARIADIC NULL) is defined as NULL */
                               5444         [ +  + ]:             15 :         if (PG_ARGISNULL(argidx))
                               5445                 :              6 :             return NULL;
                               5446                 :                : 
                               5447                 :                :         /*
                               5448                 :                :          * Non-null argument had better be an array.  We assume that any call
                               5449                 :                :          * context that could let get_fn_expr_variadic return true will have
                               5450                 :                :          * checked that a VARIADIC-labeled parameter actually is an array.  So
                               5451                 :                :          * it should be okay to just Assert that it's an array rather than
                               5452                 :                :          * doing a full-fledged error check.
                               5453                 :                :          */
 3664                          5454         [ -  + ]:              9 :         Assert(OidIsValid(get_base_element_type(get_fn_expr_argtype(fcinfo->flinfo, argidx))));
                               5455                 :                : 
                               5456                 :                :         /* OK, safe to fetch the array value */
 4097                          5457                 :              9 :         arr = PG_GETARG_ARRAYTYPE_P(argidx);
                               5458                 :                : 
                               5459                 :                :         /*
                               5460                 :                :          * And serialize the array.  We tell array_to_text to ignore null
                               5461                 :                :          * elements, which matches the behavior of the loop below.
                               5462                 :                :          */
                               5463                 :              9 :         return array_to_text_internal(fcinfo, arr, sepstr, NULL);
                               5464                 :                :     }
                               5465                 :                : 
                               5466                 :                :     /* Normal case without explicit VARIADIC marker */
 4982 itagaki.takahiro@gma     5467                 :             42 :     initStringInfo(&str);
                               5468                 :                : 
                               5469                 :                :     /* Get output function info, building it if first time through */
 2399 tgl@sss.pgh.pa.us        5470                 :             42 :     foutcache = (FmgrInfo *) fcinfo->flinfo->fn_extra;
                               5471         [ +  + ]:             42 :     if (foutcache == NULL)
                               5472                 :             23 :         foutcache = build_concat_foutcache(fcinfo, argidx);
                               5473                 :                : 
 4982 itagaki.takahiro@gma     5474         [ +  + ]:            186 :     for (i = argidx; i < PG_NARGS(); i++)
                               5475                 :                :     {
                               5476         [ +  + ]:            144 :         if (!PG_ARGISNULL(i))
                               5477                 :                :         {
 4612 tgl@sss.pgh.pa.us        5478                 :            105 :             Datum       value = PG_GETARG_DATUM(i);
                               5479                 :                : 
                               5480                 :                :             /* add separator if appropriate */
                               5481         [ +  + ]:            105 :             if (first_arg)
                               5482                 :             39 :                 first_arg = false;
                               5483                 :                :             else
 4097                          5484                 :             66 :                 appendStringInfoString(&str, sepstr);
                               5485                 :                : 
                               5486                 :                :             /* call the appropriate type output function, append the result */
 4982 itagaki.takahiro@gma     5487                 :            105 :             appendStringInfoString(&str,
 2399 tgl@sss.pgh.pa.us        5488                 :            105 :                                    OutputFunctionCall(&foutcache[i], value));
                               5489                 :                :         }
                               5490                 :                :     }
                               5491                 :                : 
 4982 itagaki.takahiro@gma     5492                 :             42 :     result = cstring_to_text_with_len(str.data, str.len);
                               5493                 :             42 :     pfree(str.data);
                               5494                 :                : 
                               5495                 :             42 :     return result;
                               5496                 :                : }
                               5497                 :                : 
                               5498                 :                : /*
                               5499                 :                :  * Concatenate all arguments. NULL arguments are ignored.
                               5500                 :                :  */
                               5501                 :                : Datum
                               5502                 :             18 : text_concat(PG_FUNCTION_ARGS)
                               5503                 :                : {
                               5504                 :                :     text       *result;
                               5505                 :                : 
 4097 tgl@sss.pgh.pa.us        5506                 :             18 :     result = concat_internal("", 0, fcinfo);
                               5507         [ +  + ]:             18 :     if (result == NULL)
                               5508                 :              3 :         PG_RETURN_NULL();
                               5509                 :             15 :     PG_RETURN_TEXT_P(result);
                               5510                 :                : }
                               5511                 :                : 
                               5512                 :                : /*
                               5513                 :                :  * Concatenate all but first argument value with separators. The first
                               5514                 :                :  * parameter is used as the separator. NULL arguments are ignored.
                               5515                 :                :  */
                               5516                 :                : Datum
 4982 itagaki.takahiro@gma     5517                 :             42 : text_concat_ws(PG_FUNCTION_ARGS)
                               5518                 :                : {
                               5519                 :                :     char       *sep;
                               5520                 :                :     text       *result;
                               5521                 :                : 
                               5522                 :                :     /* return NULL when separator is NULL */
                               5523         [ +  + ]:             42 :     if (PG_ARGISNULL(0))
                               5524                 :              3 :         PG_RETURN_NULL();
 4097 tgl@sss.pgh.pa.us        5525                 :             39 :     sep = text_to_cstring(PG_GETARG_TEXT_PP(0));
                               5526                 :                : 
                               5527                 :             39 :     result = concat_internal(sep, 1, fcinfo);
                               5528         [ +  + ]:             39 :     if (result == NULL)
                               5529                 :              3 :         PG_RETURN_NULL();
                               5530                 :             36 :     PG_RETURN_TEXT_P(result);
                               5531                 :                : }
                               5532                 :                : 
                               5533                 :                : /*
                               5534                 :                :  * Return first n characters in the string. When n is negative,
                               5535                 :                :  * return all but last |n| characters.
                               5536                 :                :  */
                               5537                 :                : Datum
 4982 itagaki.takahiro@gma     5538                 :            942 : text_left(PG_FUNCTION_ARGS)
                               5539                 :                : {
 1789 tgl@sss.pgh.pa.us        5540                 :            942 :     int         n = PG_GETARG_INT32(1);
                               5541                 :                : 
 4982 itagaki.takahiro@gma     5542         [ +  + ]:            942 :     if (n < 0)
                               5543                 :                :     {
 1839 sfrost@snowman.net       5544                 :             15 :         text       *str = PG_GETARG_TEXT_PP(0);
                               5545         [ -  + ]:             15 :         const char *p = VARDATA_ANY(str);
                               5546   [ -  +  -  -  :             15 :         int         len = VARSIZE_ANY_EXHDR(str);
                                     -  -  -  -  -  
                                                 + ]
                               5547                 :                :         int         rlen;
                               5548                 :                : 
                               5549                 :             15 :         n = pg_mbstrlen_with_len(p, len) + n;
                               5550                 :             15 :         rlen = pg_mbcharcliplen(p, len, n);
                               5551                 :             15 :         PG_RETURN_TEXT_P(cstring_to_text_with_len(p, rlen));
                               5552                 :                :     }
                               5553                 :                :     else
                               5554                 :            927 :         PG_RETURN_TEXT_P(text_substring(PG_GETARG_DATUM(0), 1, n, false));
                               5555                 :                : }
                               5556                 :                : 
                               5557                 :                : /*
                               5558                 :                :  * Return last n characters in the string. When n is negative,
                               5559                 :                :  * return all but first |n| characters.
                               5560                 :                :  */
                               5561                 :                : Datum
 4982 itagaki.takahiro@gma     5562                 :             33 : text_right(PG_FUNCTION_ARGS)
                               5563                 :                : {
                               5564                 :             33 :     text       *str = PG_GETARG_TEXT_PP(0);
                               5565         [ -  + ]:             33 :     const char *p = VARDATA_ANY(str);
                               5566   [ -  +  -  -  :             33 :     int         len = VARSIZE_ANY_EXHDR(str);
                                     -  -  -  -  -  
                                                 + ]
                               5567                 :             33 :     int         n = PG_GETARG_INT32(1);
                               5568                 :                :     int         off;
                               5569                 :                : 
                               5570         [ +  + ]:             33 :     if (n < 0)
                               5571                 :             15 :         n = -n;
                               5572                 :                :     else
                               5573                 :             18 :         n = pg_mbstrlen_with_len(p, len) - n;
                               5574                 :             33 :     off = pg_mbcharcliplen(p, len, n);
                               5575                 :                : 
                               5576                 :             33 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(p + off, len - off));
                               5577                 :                : }
                               5578                 :                : 
                               5579                 :                : /*
                               5580                 :                :  * Return reversed string
                               5581                 :                :  */
                               5582                 :                : Datum
                               5583                 :              3 : text_reverse(PG_FUNCTION_ARGS)
                               5584                 :                : {
 4753 bruce@momjian.us         5585                 :              3 :     text       *str = PG_GETARG_TEXT_PP(0);
                               5586         [ -  + ]:              3 :     const char *p = VARDATA_ANY(str);
                               5587   [ -  +  -  -  :              3 :     int         len = VARSIZE_ANY_EXHDR(str);
                                     -  -  -  -  -  
                                                 + ]
                               5588                 :              3 :     const char *endp = p + len;
                               5589                 :                :     text       *result;
                               5590                 :                :     char       *dst;
                               5591                 :                : 
 4982 itagaki.takahiro@gma     5592                 :              3 :     result = palloc(len + VARHDRSZ);
 4753 bruce@momjian.us         5593                 :              3 :     dst = (char *) VARDATA(result) + len;
 4982 itagaki.takahiro@gma     5594                 :              3 :     SET_VARSIZE(result, len + VARHDRSZ);
                               5595                 :                : 
                               5596         [ +  - ]:              3 :     if (pg_database_encoding_max_length() > 1)
                               5597                 :                :     {
                               5598                 :                :         /* multibyte version */
                               5599         [ +  + ]:             18 :         while (p < endp)
                               5600                 :                :         {
                               5601                 :                :             int         sz;
                               5602                 :                : 
                               5603                 :             15 :             sz = pg_mblen(p);
                               5604                 :             15 :             dst -= sz;
                               5605                 :             15 :             memcpy(dst, p, sz);
                               5606                 :             15 :             p += sz;
                               5607                 :                :         }
                               5608                 :                :     }
                               5609                 :                :     else
                               5610                 :                :     {
                               5611                 :                :         /* single byte version */
 4982 itagaki.takahiro@gma     5612         [ #  # ]:UBC           0 :         while (p < endp)
                               5613                 :              0 :             *(--dst) = *p++;
                               5614                 :                :     }
                               5615                 :                : 
 4982 itagaki.takahiro@gma     5616                 :CBC           3 :     PG_RETURN_TEXT_P(result);
                               5617                 :                : }
                               5618                 :                : 
                               5619                 :                : 
                               5620                 :                : /*
                               5621                 :                :  * Support macros for text_format()
                               5622                 :                :  */
                               5623                 :                : #define TEXT_FORMAT_FLAG_MINUS  0x0001  /* is minus flag present? */
                               5624                 :                : 
                               5625                 :                : #define ADVANCE_PARSE_POINTER(ptr,end_ptr) \
                               5626                 :                :     do { \
                               5627                 :                :         if (++(ptr) >= (end_ptr)) \
                               5628                 :                :             ereport(ERROR, \
                               5629                 :                :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE), \
                               5630                 :                :                      errmsg("unterminated format() type specifier"), \
                               5631                 :                :                      errhint("For a single \"%%\" use \"%%%%\"."))); \
                               5632                 :                :     } while (0)
                               5633                 :                : 
                               5634                 :                : /*
                               5635                 :                :  * Returns a formatted string
                               5636                 :                :  */
                               5637                 :                : Datum
 4894 rhaas@postgresql.org     5638                 :          13068 : text_format(PG_FUNCTION_ARGS)
                               5639                 :                : {
                               5640                 :                :     text       *fmt;
                               5641                 :                :     StringInfoData str;
                               5642                 :                :     const char *cp;
                               5643                 :                :     const char *start_ptr;
                               5644                 :                :     const char *end_ptr;
                               5645                 :                :     text       *result;
                               5646                 :                :     int         arg;
                               5647                 :                :     bool        funcvariadic;
                               5648                 :                :     int         nargs;
 4097 tgl@sss.pgh.pa.us        5649                 :          13068 :     Datum      *elements = NULL;
                               5650                 :          13068 :     bool       *nulls = NULL;
                               5651                 :          13068 :     Oid         element_type = InvalidOid;
                               5652                 :          13068 :     Oid         prev_type = InvalidOid;
 4049                          5653                 :          13068 :     Oid         prev_width_type = InvalidOid;
                               5654                 :                :     FmgrInfo    typoutputfinfo;
                               5655                 :                :     FmgrInfo    typoutputinfo_width;
                               5656                 :                : 
                               5657                 :                :     /* When format string is null, immediately return null */
 4894 rhaas@postgresql.org     5658         [ +  + ]:          13068 :     if (PG_ARGISNULL(0))
                               5659                 :              3 :         PG_RETURN_NULL();
                               5660                 :                : 
                               5661                 :                :     /* If argument is marked VARIADIC, expand array into elements */
 4097 tgl@sss.pgh.pa.us        5662         [ +  + ]:          13065 :     if (get_fn_expr_variadic(fcinfo->flinfo))
                               5663                 :                :     {
                               5664                 :                :         ArrayType  *arr;
                               5665                 :                :         int16       elmlen;
                               5666                 :                :         bool        elmbyval;
                               5667                 :                :         char        elmalign;
                               5668                 :                :         int         nitems;
                               5669                 :                : 
                               5670                 :                :         /* Should have just the one argument */
                               5671         [ -  + ]:             24 :         Assert(PG_NARGS() == 2);
                               5672                 :                : 
                               5673                 :                :         /* If argument is NULL, we treat it as zero-length array */
                               5674         [ +  + ]:             24 :         if (PG_ARGISNULL(1))
                               5675                 :              3 :             nitems = 0;
                               5676                 :                :         else
                               5677                 :                :         {
                               5678                 :                :             /*
                               5679                 :                :              * Non-null argument had better be an array.  We assume that any
                               5680                 :                :              * call context that could let get_fn_expr_variadic return true
                               5681                 :                :              * will have checked that a VARIADIC-labeled parameter actually is
                               5682                 :                :              * an array.  So it should be okay to just Assert that it's an
                               5683                 :                :              * array rather than doing a full-fledged error check.
                               5684                 :                :              */
 3664                          5685         [ -  + ]:             21 :             Assert(OidIsValid(get_base_element_type(get_fn_expr_argtype(fcinfo->flinfo, 1))));
                               5686                 :                : 
                               5687                 :                :             /* OK, safe to fetch the array value */
 4097                          5688                 :             21 :             arr = PG_GETARG_ARRAYTYPE_P(1);
                               5689                 :                : 
                               5690                 :                :             /* Get info about array element type */
                               5691                 :             21 :             element_type = ARR_ELEMTYPE(arr);
                               5692                 :             21 :             get_typlenbyvalalign(element_type,
                               5693                 :                :                                  &elmlen, &elmbyval, &elmalign);
                               5694                 :                : 
                               5695                 :                :             /* Extract all array elements */
                               5696                 :             21 :             deconstruct_array(arr, element_type, elmlen, elmbyval, elmalign,
                               5697                 :                :                               &elements, &nulls, &nitems);
                               5698                 :                :         }
                               5699                 :                : 
                               5700                 :             24 :         nargs = nitems + 1;
                               5701                 :             24 :         funcvariadic = true;
                               5702                 :                :     }
                               5703                 :                :     else
                               5704                 :                :     {
                               5705                 :                :         /* Non-variadic case, we'll process the arguments individually */
                               5706                 :          13041 :         nargs = PG_NARGS();
                               5707                 :          13041 :         funcvariadic = false;
                               5708                 :                :     }
                               5709                 :                : 
                               5710                 :                :     /* Setup for main loop. */
 4894 rhaas@postgresql.org     5711                 :          13065 :     fmt = PG_GETARG_TEXT_PP(0);
                               5712         [ -  + ]:          13065 :     start_ptr = VARDATA_ANY(fmt);
                               5713   [ -  +  -  -  :          13065 :     end_ptr = start_ptr + VARSIZE_ANY_EXHDR(fmt);
                                     -  -  -  -  -  
                                                 + ]
                               5714                 :          13065 :     initStringInfo(&str);
 4049 tgl@sss.pgh.pa.us        5715                 :          13065 :     arg = 1;                    /* next argument position to print */
                               5716                 :                : 
                               5717                 :                :     /* Scan format string, looking for conversion specifiers. */
 4894 rhaas@postgresql.org     5718         [ +  + ]:         373344 :     for (cp = start_ptr; cp < end_ptr; cp++)
                               5719                 :                :     {
                               5720                 :                :         int         argpos;
                               5721                 :                :         int         widthpos;
                               5722                 :                :         int         flags;
                               5723                 :                :         int         width;
                               5724                 :                :         Datum       value;
                               5725                 :                :         bool        isNull;
                               5726                 :                :         Oid         typid;
                               5727                 :                : 
                               5728                 :                :         /*
                               5729                 :                :          * If it's not the start of a conversion specifier, just copy it to
                               5730                 :                :          * the output buffer.
                               5731                 :                :          */
                               5732         [ +  + ]:         360309 :         if (*cp != '%')
                               5733                 :                :         {
                               5734         [ -  + ]:         329934 :             appendStringInfoCharMacro(&str, *cp);
                               5735                 :         329943 :             continue;
                               5736                 :                :         }
                               5737                 :                : 
 4049 tgl@sss.pgh.pa.us        5738   [ -  +  -  - ]:          30375 :         ADVANCE_PARSE_POINTER(cp, end_ptr);
                               5739                 :                : 
                               5740                 :                :         /* Easy case: %% outputs a single % */
 4894 rhaas@postgresql.org     5741         [ +  + ]:          30375 :         if (*cp == '%')
                               5742                 :                :         {
                               5743         [ -  + ]:              9 :             appendStringInfoCharMacro(&str, *cp);
                               5744                 :              9 :             continue;
                               5745                 :                :         }
                               5746                 :                : 
                               5747                 :                :         /* Parse the optional portions of the format specifier */
 4049 tgl@sss.pgh.pa.us        5748                 :          30366 :         cp = text_format_parse_format(cp, end_ptr,
                               5749                 :                :                                       &argpos, &widthpos,
                               5750                 :                :                                       &flags, &width);
                               5751                 :                : 
                               5752                 :                :         /*
                               5753                 :                :          * Next we should see the main conversion specifier.  Whether or not
                               5754                 :                :          * an argument position was present, it's known that at least one
                               5755                 :                :          * character remains in the string at this point.  Experience suggests
                               5756                 :                :          * that it's worth checking that that character is one of the expected
                               5757                 :                :          * ones before we try to fetch arguments, so as to produce the least
                               5758                 :                :          * confusing response to a mis-formatted specifier.
                               5759                 :                :          */
                               5760         [ +  + ]:          30354 :         if (strchr("sIL", *cp) == NULL)
                               5761         [ +  - ]:              3 :             ereport(ERROR,
                               5762                 :                :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               5763                 :                :                      errmsg("unrecognized format() type specifier \"%.*s\"",
                               5764                 :                :                             pg_mblen(cp), cp),
                               5765                 :                :                      errhint("For a single \"%%\" use \"%%%%\".")));
                               5766                 :                : 
                               5767                 :                :         /* If indirect width was specified, get its value */
                               5768         [ +  + ]:          30351 :         if (widthpos >= 0)
                               5769                 :                :         {
                               5770                 :                :             /* Collect the specified or next argument position */
                               5771         [ +  + ]:             21 :             if (widthpos > 0)
                               5772                 :             18 :                 arg = widthpos;
                               5773         [ -  + ]:             21 :             if (arg >= nargs)
 4710 heikki.linnakangas@i     5774         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               5775                 :                :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               5776                 :                :                          errmsg("too few arguments for format()")));
                               5777                 :                : 
                               5778                 :                :             /* Get the value and type of the selected argument */
 4049 tgl@sss.pgh.pa.us        5779         [ +  - ]:CBC          21 :             if (!funcvariadic)
                               5780                 :                :             {
                               5781                 :             21 :                 value = PG_GETARG_DATUM(arg);
                               5782                 :             21 :                 isNull = PG_ARGISNULL(arg);
                               5783                 :             21 :                 typid = get_fn_expr_argtype(fcinfo->flinfo, arg);
                               5784                 :                :             }
                               5785                 :                :             else
                               5786                 :                :             {
 4049 tgl@sss.pgh.pa.us        5787                 :UBC           0 :                 value = elements[arg - 1];
                               5788                 :              0 :                 isNull = nulls[arg - 1];
                               5789                 :              0 :                 typid = element_type;
                               5790                 :                :             }
 4049 tgl@sss.pgh.pa.us        5791         [ -  + ]:CBC          21 :             if (!OidIsValid(typid))
 4049 tgl@sss.pgh.pa.us        5792         [ #  # ]:UBC           0 :                 elog(ERROR, "could not determine data type of format() input");
                               5793                 :                : 
 4049 tgl@sss.pgh.pa.us        5794                 :CBC          21 :             arg++;
                               5795                 :                : 
                               5796                 :                :             /* We can treat NULL width the same as zero */
                               5797         [ +  + ]:             21 :             if (isNull)
                               5798                 :              3 :                 width = 0;
                               5799         [ +  - ]:             18 :             else if (typid == INT4OID)
                               5800                 :             18 :                 width = DatumGetInt32(value);
 4049 tgl@sss.pgh.pa.us        5801         [ #  # ]:UBC           0 :             else if (typid == INT2OID)
                               5802                 :              0 :                 width = DatumGetInt16(value);
                               5803                 :                :             else
                               5804                 :                :             {
                               5805                 :                :                 /* For less-usual datatypes, convert to text then to int */
                               5806                 :                :                 char       *str;
                               5807                 :                : 
                               5808         [ #  # ]:              0 :                 if (typid != prev_width_type)
                               5809                 :                :                 {
                               5810                 :                :                     Oid         typoutputfunc;
                               5811                 :                :                     bool        typIsVarlena;
                               5812                 :                : 
                               5813                 :              0 :                     getTypeOutputInfo(typid, &typoutputfunc, &typIsVarlena);
                               5814                 :              0 :                     fmgr_info(typoutputfunc, &typoutputinfo_width);
                               5815                 :              0 :                     prev_width_type = typid;
                               5816                 :                :                 }
                               5817                 :                : 
                               5818                 :              0 :                 str = OutputFunctionCall(&typoutputinfo_width, value);
                               5819                 :                : 
                               5820                 :                :                 /* pg_strtoint32 will complain about bad data or overflow */
 2093 andres@anarazel.de       5821                 :              0 :                 width = pg_strtoint32(str);
                               5822                 :                : 
 4049 tgl@sss.pgh.pa.us        5823                 :              0 :                 pfree(str);
                               5824                 :                :             }
                               5825                 :                :         }
                               5826                 :                : 
                               5827                 :                :         /* Collect the specified or next argument position */
 4049 tgl@sss.pgh.pa.us        5828         [ +  + ]:CBC       30351 :         if (argpos > 0)
                               5829                 :             66 :             arg = argpos;
                               5830         [ +  + ]:          30351 :         if (arg >= nargs)
 4894 rhaas@postgresql.org     5831         [ +  - ]:             12 :             ereport(ERROR,
                               5832                 :                :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               5833                 :                :                      errmsg("too few arguments for format()")));
                               5834                 :                : 
                               5835                 :                :         /* Get the value and type of the selected argument */
 4097 tgl@sss.pgh.pa.us        5836         [ +  + ]:          30339 :         if (!funcvariadic)
                               5837                 :                :         {
                               5838                 :          29703 :             value = PG_GETARG_DATUM(arg);
                               5839                 :          29703 :             isNull = PG_ARGISNULL(arg);
                               5840                 :          29703 :             typid = get_fn_expr_argtype(fcinfo->flinfo, arg);
                               5841                 :                :         }
                               5842                 :                :         else
                               5843                 :                :         {
                               5844                 :            636 :             value = elements[arg - 1];
                               5845                 :            636 :             isNull = nulls[arg - 1];
                               5846                 :            636 :             typid = element_type;
                               5847                 :                :         }
                               5848         [ -  + ]:          30339 :         if (!OidIsValid(typid))
 4097 tgl@sss.pgh.pa.us        5849         [ #  # ]:UBC           0 :             elog(ERROR, "could not determine data type of format() input");
                               5850                 :                : 
 4049 tgl@sss.pgh.pa.us        5851                 :CBC       30339 :         arg++;
                               5852                 :                : 
                               5853                 :                :         /*
                               5854                 :                :          * Get the appropriate typOutput function, reusing previous one if
                               5855                 :                :          * same type as previous argument.  That's particularly useful in the
                               5856                 :                :          * variadic-array case, but often saves work even for ordinary calls.
                               5857                 :                :          */
 4097                          5858         [ +  + ]:          30339 :         if (typid != prev_type)
                               5859                 :                :         {
                               5860                 :                :             Oid         typoutputfunc;
                               5861                 :                :             bool        typIsVarlena;
                               5862                 :                : 
                               5863                 :          14622 :             getTypeOutputInfo(typid, &typoutputfunc, &typIsVarlena);
                               5864                 :          14622 :             fmgr_info(typoutputfunc, &typoutputfinfo);
                               5865                 :          14622 :             prev_type = typid;
                               5866                 :                :         }
                               5867                 :                : 
                               5868                 :                :         /*
                               5869                 :                :          * And now we can format the value.
                               5870                 :                :          */
 4894 rhaas@postgresql.org     5871         [ +  - ]:          30339 :         switch (*cp)
                               5872                 :                :         {
                               5873                 :          30339 :             case 's':
                               5874                 :                :             case 'I':
                               5875                 :                :             case 'L':
 4097 tgl@sss.pgh.pa.us        5876                 :          30339 :                 text_format_string_conversion(&str, *cp, &typoutputfinfo,
                               5877                 :                :                                               value, isNull,
                               5878                 :                :                                               flags, width);
 4894 rhaas@postgresql.org     5879                 :          30336 :                 break;
 4894 rhaas@postgresql.org     5880                 :UBC           0 :             default:
                               5881                 :                :                 /* should not get here, because of previous check */
                               5882         [ #  # ]:              0 :                 ereport(ERROR,
                               5883                 :                :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               5884                 :                :                          errmsg("unrecognized format() type specifier \"%.*s\"",
                               5885                 :                :                                 pg_mblen(cp), cp),
                               5886                 :                :                          errhint("For a single \"%%\" use \"%%%%\".")));
                               5887                 :                :                 break;
                               5888                 :                :         }
                               5889                 :                :     }
                               5890                 :                : 
                               5891                 :                :     /* Don't need deconstruct_array results anymore. */
 4097 tgl@sss.pgh.pa.us        5892         [ +  + ]:CBC       13035 :     if (elements != NULL)
                               5893                 :             21 :         pfree(elements);
                               5894         [ +  + ]:          13035 :     if (nulls != NULL)
                               5895                 :             21 :         pfree(nulls);
                               5896                 :                : 
                               5897                 :                :     /* Generate results. */
 4894 rhaas@postgresql.org     5898                 :          13035 :     result = cstring_to_text_with_len(str.data, str.len);
                               5899                 :          13035 :     pfree(str.data);
                               5900                 :                : 
                               5901                 :          13035 :     PG_RETURN_TEXT_P(result);
                               5902                 :                : }
                               5903                 :                : 
                               5904                 :                : /*
                               5905                 :                :  * Parse contiguous digits as a decimal number.
                               5906                 :                :  *
                               5907                 :                :  * Returns true if some digits could be parsed.
                               5908                 :                :  * The value is returned into *value, and *ptr is advanced to the next
                               5909                 :                :  * character to be parsed.
                               5910                 :                :  *
                               5911                 :                :  * Note parsing invariant: at least one character is known available before
                               5912                 :                :  * string end (end_ptr) at entry, and this is still true at exit.
                               5913                 :                :  */
                               5914                 :                : static bool
 4049 tgl@sss.pgh.pa.us        5915                 :          60714 : text_format_parse_digits(const char **ptr, const char *end_ptr, int *value)
                               5916                 :                : {
                               5917                 :          60714 :     bool        found = false;
                               5918                 :          60714 :     const char *cp = *ptr;
                               5919                 :          60714 :     int         val = 0;
                               5920                 :                : 
                               5921   [ +  +  +  + ]:          60870 :     while (*cp >= '0' && *cp <= '9')
                               5922                 :                :     {
 2315 andres@anarazel.de       5923                 :            159 :         int8        digit = (*cp - '0');
                               5924                 :                : 
                               5925         [ +  - ]:            159 :         if (unlikely(pg_mul_s32_overflow(val, 10, &val)) ||
                               5926         [ -  + ]:            159 :             unlikely(pg_add_s32_overflow(val, digit, &val)))
 4049 tgl@sss.pgh.pa.us        5927         [ #  # ]:UBC           0 :             ereport(ERROR,
                               5928                 :                :                     (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                               5929                 :                :                      errmsg("number is out of range")));
 4049 tgl@sss.pgh.pa.us        5930   [ +  +  +  - ]:CBC         159 :         ADVANCE_PARSE_POINTER(cp, end_ptr);
                               5931                 :            156 :         found = true;
                               5932                 :                :     }
                               5933                 :                : 
                               5934                 :          60711 :     *ptr = cp;
                               5935                 :          60711 :     *value = val;
                               5936                 :                : 
                               5937                 :          60711 :     return found;
                               5938                 :                : }
                               5939                 :                : 
                               5940                 :                : /*
                               5941                 :                :  * Parse a format specifier (generally following the SUS printf spec).
                               5942                 :                :  *
                               5943                 :                :  * We have already advanced over the initial '%', and we are looking for
                               5944                 :                :  * [argpos][flags][width]type (but the type character is not consumed here).
                               5945                 :                :  *
                               5946                 :                :  * Inputs are start_ptr (the position after '%') and end_ptr (string end + 1).
                               5947                 :                :  * Output parameters:
                               5948                 :                :  *  argpos: argument position for value to be printed.  -1 means unspecified.
                               5949                 :                :  *  widthpos: argument position for width.  Zero means the argument position
                               5950                 :                :  *          was unspecified (ie, take the next arg) and -1 means no width
                               5951                 :                :  *          argument (width was omitted or specified as a constant).
                               5952                 :                :  *  flags: bitmask of flags.
                               5953                 :                :  *  width: directly-specified width value.  Zero means the width was omitted
                               5954                 :                :  *          (note it's not necessary to distinguish this case from an explicit
                               5955                 :                :  *          zero width value).
                               5956                 :                :  *
                               5957                 :                :  * The function result is the next character position to be parsed, ie, the
                               5958                 :                :  * location where the type character is/should be.
                               5959                 :                :  *
                               5960                 :                :  * Note parsing invariant: at least one character is known available before
                               5961                 :                :  * string end (end_ptr) at entry, and this is still true at exit.
                               5962                 :                :  */
                               5963                 :                : static const char *
                               5964                 :          30366 : text_format_parse_format(const char *start_ptr, const char *end_ptr,
                               5965                 :                :                          int *argpos, int *widthpos,
                               5966                 :                :                          int *flags, int *width)
                               5967                 :                : {
                               5968                 :          30366 :     const char *cp = start_ptr;
                               5969                 :                :     int         n;
                               5970                 :                : 
                               5971                 :                :     /* set defaults for output parameters */
                               5972                 :          30366 :     *argpos = -1;
                               5973                 :          30366 :     *widthpos = -1;
                               5974                 :          30366 :     *flags = 0;
                               5975                 :          30366 :     *width = 0;
                               5976                 :                : 
                               5977                 :                :     /* try to identify first number */
                               5978         [ +  + ]:          30366 :     if (text_format_parse_digits(&cp, end_ptr, &n))
                               5979                 :                :     {
                               5980         [ +  + ]:             87 :         if (*cp != '$')
                               5981                 :                :         {
                               5982                 :                :             /* Must be just a width and a type, so we're done */
                               5983                 :             12 :             *width = n;
                               5984                 :             12 :             return cp;
                               5985                 :                :         }
                               5986                 :                :         /* The number was argument position */
                               5987                 :             75 :         *argpos = n;
                               5988                 :                :         /* Explicit 0 for argument index is immediately refused */
                               5989         [ +  + ]:             75 :         if (n == 0)
                               5990         [ +  - ]:              3 :             ereport(ERROR,
                               5991                 :                :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               5992                 :                :                      errmsg("format specifies argument 0, but arguments are numbered from 1")));
                               5993   [ +  +  +  - ]:             72 :         ADVANCE_PARSE_POINTER(cp, end_ptr);
                               5994                 :                :     }
                               5995                 :                : 
                               5996                 :                :     /* Handle flags (only minus is supported now) */
                               5997         [ +  + ]:          30363 :     while (*cp == '-')
                               5998                 :                :     {
                               5999                 :             15 :         *flags |= TEXT_FORMAT_FLAG_MINUS;
                               6000   [ -  +  -  - ]:             15 :         ADVANCE_PARSE_POINTER(cp, end_ptr);
                               6001                 :                :     }
                               6002                 :                : 
                               6003         [ +  + ]:          30348 :     if (*cp == '*')
                               6004                 :                :     {
                               6005                 :                :         /* Handle indirect width */
                               6006   [ -  +  -  - ]:             24 :         ADVANCE_PARSE_POINTER(cp, end_ptr);
                               6007         [ +  + ]:             24 :         if (text_format_parse_digits(&cp, end_ptr, &n))
                               6008                 :                :         {
                               6009                 :                :             /* number in this position must be closed by $ */
                               6010         [ -  + ]:             21 :             if (*cp != '$')
 4049 tgl@sss.pgh.pa.us        6011         [ #  # ]:UBC           0 :                 ereport(ERROR,
                               6012                 :                :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               6013                 :                :                          errmsg("width argument position must be ended by \"$\"")));
                               6014                 :                :             /* The number was width argument position */
 4049 tgl@sss.pgh.pa.us        6015                 :CBC          21 :             *widthpos = n;
                               6016                 :                :             /* Explicit 0 for argument index is immediately refused */
                               6017         [ +  + ]:             21 :             if (n == 0)
                               6018         [ +  - ]:              3 :                 ereport(ERROR,
                               6019                 :                :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               6020                 :                :                          errmsg("format specifies argument 0, but arguments are numbered from 1")));
                               6021   [ -  +  -  - ]:             18 :             ADVANCE_PARSE_POINTER(cp, end_ptr);
                               6022                 :                :         }
                               6023                 :                :         else
                               6024                 :              3 :             *widthpos = 0;      /* width's argument position is unspecified */
                               6025                 :                :     }
                               6026                 :                :     else
                               6027                 :                :     {
                               6028                 :                :         /* Check for direct width specification */
                               6029         [ +  + ]:          30324 :         if (text_format_parse_digits(&cp, end_ptr, &n))
                               6030                 :             15 :             *width = n;
                               6031                 :                :     }
                               6032                 :                : 
                               6033                 :                :     /* cp should now be pointing at type character */
                               6034                 :          30342 :     return cp;
                               6035                 :                : }
                               6036                 :                : 
                               6037                 :                : /*
                               6038                 :                :  * Format a %s, %I, or %L conversion
                               6039                 :                :  */
                               6040                 :                : static void
 4894 rhaas@postgresql.org     6041                 :          30339 : text_format_string_conversion(StringInfo buf, char conversion,
                               6042                 :                :                               FmgrInfo *typOutputInfo,
                               6043                 :                :                               Datum value, bool isNull,
                               6044                 :                :                               int flags, int width)
                               6045                 :                : {
                               6046                 :                :     char       *str;
                               6047                 :                : 
                               6048                 :                :     /* Handle NULL arguments before trying to stringify the value. */
                               6049         [ +  + ]:          30339 :     if (isNull)
                               6050                 :                :     {
 4049 tgl@sss.pgh.pa.us        6051         [ +  + ]:            171 :         if (conversion == 's')
                               6052                 :            135 :             text_format_append_string(buf, "", flags, width);
                               6053         [ +  + ]:             36 :         else if (conversion == 'L')
                               6054                 :             33 :             text_format_append_string(buf, "NULL", flags, width);
 4894 rhaas@postgresql.org     6055         [ +  - ]:              3 :         else if (conversion == 'I')
 4753 bruce@momjian.us         6056         [ +  - ]:              3 :             ereport(ERROR,
                               6057                 :                :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                               6058                 :                :                      errmsg("null values cannot be formatted as an SQL identifier")));
 4894 rhaas@postgresql.org     6059                 :            168 :         return;
                               6060                 :                :     }
                               6061                 :                : 
                               6062                 :                :     /* Stringify. */
 4097 tgl@sss.pgh.pa.us        6063                 :          30168 :     str = OutputFunctionCall(typOutputInfo, value);
                               6064                 :                : 
                               6065                 :                :     /* Escape. */
 4894 rhaas@postgresql.org     6066         [ +  + ]:          30168 :     if (conversion == 'I')
                               6067                 :                :     {
                               6068                 :                :         /* quote_identifier may or may not allocate a new string. */
 4049 tgl@sss.pgh.pa.us        6069                 :           1553 :         text_format_append_string(buf, quote_identifier(str), flags, width);
                               6070                 :                :     }
 4894 rhaas@postgresql.org     6071         [ +  + ]:          28615 :     else if (conversion == 'L')
                               6072                 :                :     {
 4753 bruce@momjian.us         6073                 :           1616 :         char       *qstr = quote_literal_cstr(str);
                               6074                 :                : 
 4049 tgl@sss.pgh.pa.us        6075                 :           1616 :         text_format_append_string(buf, qstr, flags, width);
                               6076                 :                :         /* quote_literal_cstr() always allocates a new string */
 4894 rhaas@postgresql.org     6077                 :           1616 :         pfree(qstr);
                               6078                 :                :     }
                               6079                 :                :     else
 4049 tgl@sss.pgh.pa.us        6080                 :          26999 :         text_format_append_string(buf, str, flags, width);
                               6081                 :                : 
                               6082                 :                :     /* Cleanup. */
 4894 rhaas@postgresql.org     6083                 :          30168 :     pfree(str);
                               6084                 :                : }
                               6085                 :                : 
                               6086                 :                : /*
                               6087                 :                :  * Append str to buf, padding as directed by flags/width
                               6088                 :                :  */
                               6089                 :                : static void
 4049 tgl@sss.pgh.pa.us        6090                 :          30336 : text_format_append_string(StringInfo buf, const char *str,
                               6091                 :                :                           int flags, int width)
                               6092                 :                : {
                               6093                 :          30336 :     bool        align_to_left = false;
                               6094                 :                :     int         len;
                               6095                 :                : 
                               6096                 :                :     /* fast path for typical easy case */
                               6097         [ +  + ]:          30336 :     if (width == 0)
                               6098                 :                :     {
                               6099                 :          30294 :         appendStringInfoString(buf, str);
                               6100                 :          30294 :         return;
                               6101                 :                :     }
                               6102                 :                : 
                               6103         [ +  + ]:             42 :     if (width < 0)
                               6104                 :                :     {
                               6105                 :                :         /* Negative width: implicit '-' flag, then take absolute value */
                               6106                 :              3 :         align_to_left = true;
                               6107                 :                :         /* -INT_MIN is undefined */
                               6108         [ -  + ]:              3 :         if (width <= INT_MIN)
 4049 tgl@sss.pgh.pa.us        6109         [ #  # ]:UBC           0 :             ereport(ERROR,
                               6110                 :                :                     (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                               6111                 :                :                      errmsg("number is out of range")));
 4049 tgl@sss.pgh.pa.us        6112                 :CBC           3 :         width = -width;
                               6113                 :                :     }
                               6114         [ +  + ]:             39 :     else if (flags & TEXT_FORMAT_FLAG_MINUS)
                               6115                 :             12 :         align_to_left = true;
                               6116                 :                : 
                               6117                 :             42 :     len = pg_mbstrlen(str);
                               6118         [ +  + ]:             42 :     if (align_to_left)
                               6119                 :                :     {
                               6120                 :                :         /* left justify */
                               6121                 :             15 :         appendStringInfoString(buf, str);
                               6122         [ +  - ]:             15 :         if (len < width)
                               6123                 :             15 :             appendStringInfoSpaces(buf, width - len);
                               6124                 :                :     }
                               6125                 :                :     else
                               6126                 :                :     {
                               6127                 :                :         /* right justify */
                               6128         [ +  - ]:             27 :         if (len < width)
                               6129                 :             27 :             appendStringInfoSpaces(buf, width - len);
                               6130                 :             27 :         appendStringInfoString(buf, str);
                               6131                 :                :     }
                               6132                 :                : }
                               6133                 :                : 
                               6134                 :                : /*
                               6135                 :                :  * text_format_nv - nonvariadic wrapper for text_format function.
                               6136                 :                :  *
                               6137                 :                :  * note: this wrapper is necessary to pass the sanity check in opr_sanity,
                               6138                 :                :  * which checks that all built-in functions that share the implementing C
                               6139                 :                :  * function take the same number of arguments.
                               6140                 :                :  */
                               6141                 :                : Datum
 4894 rhaas@postgresql.org     6142                 :             15 : text_format_nv(PG_FUNCTION_ARGS)
                               6143                 :                : {
                               6144                 :             15 :     return text_format(fcinfo);
                               6145                 :                : }
                               6146                 :                : 
                               6147                 :                : /*
                               6148                 :                :  * Helper function for Levenshtein distance functions. Faster than memcmp(),
                               6149                 :                :  * for this use case.
                               6150                 :                :  */
                               6151                 :                : static inline bool
 3440 rhaas@postgresql.org     6152                 :UBC           0 : rest_of_char_same(const char *s1, const char *s2, int len)
                               6153                 :                : {
                               6154         [ #  # ]:              0 :     while (len > 0)
                               6155                 :                :     {
                               6156                 :              0 :         len--;
                               6157         [ #  # ]:              0 :         if (s1[len] != s2[len])
                               6158                 :              0 :             return false;
                               6159                 :                :     }
                               6160                 :              0 :     return true;
                               6161                 :                : }
                               6162                 :                : 
                               6163                 :                : /* Expand each Levenshtein distance variant */
                               6164                 :                : #include "levenshtein.c"
                               6165                 :                : #define LEVENSHTEIN_LESS_EQUAL
                               6166                 :                : #include "levenshtein.c"
                               6167                 :                : 
                               6168                 :                : 
                               6169                 :                : /*
                               6170                 :                :  * The following *ClosestMatch() functions can be used to determine whether a
                               6171                 :                :  * user-provided string resembles any known valid values, which is useful for
                               6172                 :                :  * providing hints in log messages, among other things.  Use these functions
                               6173                 :                :  * like so:
                               6174                 :                :  *
                               6175                 :                :  *      initClosestMatch(&state, source_string, max_distance);
                               6176                 :                :  *
                               6177                 :                :  *      for (int i = 0; i < num_valid_strings; i++)
                               6178                 :                :  *          updateClosestMatch(&state, valid_strings[i]);
                               6179                 :                :  *
                               6180                 :                :  *      closestMatch = getClosestMatch(&state);
                               6181                 :                :  */
                               6182                 :                : 
                               6183                 :                : /*
                               6184                 :                :  * Initialize the given state with the source string and maximum Levenshtein
                               6185                 :                :  * distance to consider.
                               6186                 :                :  */
                               6187                 :                : void
  576 peter@eisentraut.org     6188                 :CBC          28 : initClosestMatch(ClosestMatchState *state, const char *source, int max_d)
                               6189                 :                : {
                               6190         [ -  + ]:             28 :     Assert(state);
                               6191         [ -  + ]:             28 :     Assert(max_d >= 0);
                               6192                 :                : 
                               6193                 :             28 :     state->source = source;
                               6194                 :             28 :     state->min_d = -1;
                               6195                 :             28 :     state->max_d = max_d;
                               6196                 :             28 :     state->match = NULL;
                               6197                 :             28 : }
                               6198                 :                : 
                               6199                 :                : /*
                               6200                 :                :  * If the candidate string is a closer match than the current one saved (or
                               6201                 :                :  * there is no match saved), save it as the closest match.
                               6202                 :                :  *
                               6203                 :                :  * If the source or candidate string is NULL, empty, or too long, this function
                               6204                 :                :  * takes no action.  Likewise, if the Levenshtein distance exceeds the maximum
                               6205                 :                :  * allowed or more than half the characters are different, no action is taken.
                               6206                 :                :  */
                               6207                 :                : void
                               6208                 :            168 : updateClosestMatch(ClosestMatchState *state, const char *candidate)
                               6209                 :                : {
                               6210                 :                :     int         dist;
                               6211                 :                : 
                               6212         [ -  + ]:            168 :     Assert(state);
                               6213                 :                : 
                               6214   [ +  -  +  -  :            168 :     if (state->source == NULL || state->source[0] == '\0' ||
                                              +  - ]
                               6215         [ -  + ]:            168 :         candidate == NULL || candidate[0] == '\0')
  576 peter@eisentraut.org     6216                 :UBC           0 :         return;
                               6217                 :                : 
                               6218                 :                :     /*
                               6219                 :                :      * To avoid ERROR-ing, we check the lengths here instead of setting
                               6220                 :                :      * 'trusted' to false in the call to varstr_levenshtein_less_equal().
                               6221                 :                :      */
  576 peter@eisentraut.org     6222         [ +  - ]:CBC         168 :     if (strlen(state->source) > MAX_LEVENSHTEIN_STRLEN ||
                               6223         [ -  + ]:            168 :         strlen(candidate) > MAX_LEVENSHTEIN_STRLEN)
  576 peter@eisentraut.org     6224                 :UBC           0 :         return;
                               6225                 :                : 
  576 peter@eisentraut.org     6226                 :CBC         168 :     dist = varstr_levenshtein_less_equal(state->source, strlen(state->source),
                               6227                 :            168 :                                          candidate, strlen(candidate), 1, 1, 1,
                               6228                 :                :                                          state->max_d, true);
                               6229         [ +  + ]:            168 :     if (dist <= state->max_d &&
                               6230         [ +  + ]:             28 :         dist <= strlen(state->source) / 2 &&
                               6231   [ -  +  -  - ]:              7 :         (state->min_d == -1 || dist < state->min_d))
                               6232                 :                :     {
                               6233                 :              7 :         state->min_d = dist;
                               6234                 :              7 :         state->match = candidate;
                               6235                 :                :     }
                               6236                 :                : }
                               6237                 :                : 
                               6238                 :                : /*
                               6239                 :                :  * Return the closest match.  If no suitable candidates were provided via
                               6240                 :                :  * updateClosestMatch(), return NULL.
                               6241                 :                :  */
                               6242                 :                : const char *
                               6243                 :             28 : getClosestMatch(ClosestMatchState *state)
                               6244                 :                : {
                               6245         [ -  + ]:             28 :     Assert(state);
                               6246                 :                : 
                               6247                 :             28 :     return state->match;
                               6248                 :                : }
                               6249                 :                : 
                               6250                 :                : 
                               6251                 :                : /*
                               6252                 :                :  * Unicode support
                               6253                 :                :  */
                               6254                 :                : 
                               6255                 :                : static UnicodeNormalizationForm
 1480                          6256                 :             93 : unicode_norm_form_from_string(const char *formstr)
                               6257                 :                : {
                               6258                 :             93 :     UnicodeNormalizationForm form = -1;
                               6259                 :                : 
                               6260                 :                :     /*
                               6261                 :                :      * Might as well check this while we're here.
                               6262                 :                :      */
                               6263         [ -  + ]:             93 :     if (GetDatabaseEncoding() != PG_UTF8)
 1480 peter@eisentraut.org     6264         [ #  # ]:UBC           0 :         ereport(ERROR,
                               6265                 :                :                 (errcode(ERRCODE_SYNTAX_ERROR),
                               6266                 :                :                  errmsg("Unicode normalization can only be performed if server encoding is UTF8")));
                               6267                 :                : 
 1480 peter@eisentraut.org     6268         [ +  + ]:CBC          93 :     if (pg_strcasecmp(formstr, "NFC") == 0)
                               6269                 :             33 :         form = UNICODE_NFC;
                               6270         [ +  + ]:             60 :     else if (pg_strcasecmp(formstr, "NFD") == 0)
                               6271                 :             18 :         form = UNICODE_NFD;
                               6272         [ +  + ]:             42 :     else if (pg_strcasecmp(formstr, "NFKC") == 0)
                               6273                 :             18 :         form = UNICODE_NFKC;
                               6274         [ +  + ]:             24 :     else if (pg_strcasecmp(formstr, "NFKD") == 0)
                               6275                 :             18 :         form = UNICODE_NFKD;
                               6276                 :                :     else
                               6277         [ +  - ]:              6 :         ereport(ERROR,
                               6278                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               6279                 :                :                  errmsg("invalid normalization form: %s", formstr)));
                               6280                 :                : 
                               6281                 :             87 :     return form;
                               6282                 :                : }
                               6283                 :                : 
                               6284                 :                : /*
                               6285                 :                :  * Returns version of Unicode used by Postgres in "major.minor" format (the
                               6286                 :                :  * same format as the Unicode version reported by ICU). The third component
                               6287                 :                :  * ("update version") never involves additions to the character repertiore and
                               6288                 :                :  * is unimportant for most purposes.
                               6289                 :                :  *
                               6290                 :                :  * See: https://unicode.org/versions/
                               6291                 :                :  */
                               6292                 :                : Datum
  165 jdavis@postgresql.or     6293                 :GNC           3 : unicode_version(PG_FUNCTION_ARGS)
                               6294                 :                : {
                               6295                 :              3 :     PG_RETURN_TEXT_P(cstring_to_text(PG_UNICODE_VERSION));
                               6296                 :                : }
                               6297                 :                : 
                               6298                 :                : /*
                               6299                 :                :  * Returns version of Unicode used by ICU, if enabled; otherwise NULL.
                               6300                 :                :  */
                               6301                 :                : Datum
                               6302                 :              1 : icu_unicode_version(PG_FUNCTION_ARGS)
                               6303                 :                : {
                               6304                 :                : #ifdef USE_ICU
                               6305                 :              1 :     PG_RETURN_TEXT_P(cstring_to_text(U_UNICODE_VERSION));
                               6306                 :                : #else
                               6307                 :                :     PG_RETURN_NULL();
                               6308                 :                : #endif
                               6309                 :                : }
                               6310                 :                : 
                               6311                 :                : /*
                               6312                 :                :  * Check whether the string contains only assigned Unicode code
                               6313                 :                :  * points. Requires that the database encoding is UTF-8.
                               6314                 :                :  */
                               6315                 :                : Datum
                               6316                 :              6 : unicode_assigned(PG_FUNCTION_ARGS)
                               6317                 :                : {
                               6318                 :              6 :     text       *input = PG_GETARG_TEXT_PP(0);
                               6319                 :                :     unsigned char *p;
                               6320                 :                :     int         size;
                               6321                 :                : 
                               6322         [ -  + ]:              6 :     if (GetDatabaseEncoding() != PG_UTF8)
  165 jdavis@postgresql.or     6323         [ #  # ]:UNC           0 :         ereport(ERROR,
                               6324                 :                :                 (errmsg("Unicode categorization can only be performed if server encoding is UTF8")));
                               6325                 :                : 
                               6326                 :                :     /* convert to pg_wchar */
  165 jdavis@postgresql.or     6327   [ -  +  -  -  :GNC           6 :     size = pg_mbstrlen_with_len(VARDATA_ANY(input), VARSIZE_ANY_EXHDR(input));
                                     -  -  -  -  -  
                                           +  -  + ]
                               6328         [ -  + ]:              6 :     p = (unsigned char *) VARDATA_ANY(input);
                               6329         [ +  + ]:             24 :     for (int i = 0; i < size; i++)
                               6330                 :                :     {
                               6331                 :             21 :         pg_wchar    uchar = utf8_to_unicode(p);
                               6332                 :             21 :         int         category = unicode_category(uchar);
                               6333                 :                : 
                               6334         [ +  + ]:             21 :         if (category == PG_U_UNASSIGNED)
                               6335                 :              3 :             PG_RETURN_BOOL(false);
                               6336                 :                : 
                               6337                 :             18 :         p += pg_utf_mblen(p);
                               6338                 :                :     }
                               6339                 :                : 
                               6340                 :              3 :     PG_RETURN_BOOL(true);
                               6341                 :                : }
                               6342                 :                : 
                               6343                 :                : Datum
 1480 peter@eisentraut.org     6344                 :CBC          24 : unicode_normalize_func(PG_FUNCTION_ARGS)
                               6345                 :                : {
                               6346                 :             24 :     text       *input = PG_GETARG_TEXT_PP(0);
                               6347                 :             24 :     char       *formstr = text_to_cstring(PG_GETARG_TEXT_PP(1));
                               6348                 :                :     UnicodeNormalizationForm form;
                               6349                 :                :     int         size;
                               6350                 :                :     pg_wchar   *input_chars;
                               6351                 :                :     pg_wchar   *output_chars;
                               6352                 :                :     unsigned char *p;
                               6353                 :                :     text       *result;
                               6354                 :                :     int         i;
                               6355                 :                : 
                               6356                 :             24 :     form = unicode_norm_form_from_string(formstr);
                               6357                 :                : 
                               6358                 :                :     /* convert to pg_wchar */
                               6359   [ -  +  -  -  :             21 :     size = pg_mbstrlen_with_len(VARDATA_ANY(input), VARSIZE_ANY_EXHDR(input));
                                     -  -  -  -  -  
                                           +  -  + ]
                               6360                 :             21 :     input_chars = palloc((size + 1) * sizeof(pg_wchar));
                               6361         [ -  + ]:             21 :     p = (unsigned char *) VARDATA_ANY(input);
                               6362         [ +  + ]:             84 :     for (i = 0; i < size; i++)
                               6363                 :                :     {
                               6364                 :             63 :         input_chars[i] = utf8_to_unicode(p);
                               6365                 :             63 :         p += pg_utf_mblen(p);
                               6366                 :                :     }
                               6367                 :             21 :     input_chars[i] = (pg_wchar) '\0';
                               6368   [ -  +  -  +  :             21 :     Assert((char *) p == VARDATA_ANY(input) + VARSIZE_ANY_EXHDR(input));
                                     -  -  -  -  -  
                                        -  -  +  -  
                                                 + ]
                               6369                 :                : 
                               6370                 :                :     /* action */
                               6371                 :             21 :     output_chars = unicode_normalize(form, input_chars);
                               6372                 :                : 
                               6373                 :                :     /* convert back to UTF-8 string */
                               6374                 :             21 :     size = 0;
                               6375         [ +  + ]:             81 :     for (pg_wchar *wp = output_chars; *wp; wp++)
                               6376                 :                :     {
                               6377                 :                :         unsigned char buf[4];
                               6378                 :                : 
                               6379                 :             60 :         unicode_to_utf8(*wp, buf);
                               6380                 :             60 :         size += pg_utf_mblen(buf);
                               6381                 :                :     }
                               6382                 :                : 
                               6383                 :             21 :     result = palloc(size + VARHDRSZ);
                               6384                 :             21 :     SET_VARSIZE(result, size + VARHDRSZ);
                               6385                 :                : 
                               6386         [ -  + ]:             21 :     p = (unsigned char *) VARDATA_ANY(result);
                               6387         [ +  + ]:             81 :     for (pg_wchar *wp = output_chars; *wp; wp++)
                               6388                 :                :     {
                               6389                 :             60 :         unicode_to_utf8(*wp, p);
                               6390                 :             60 :         p += pg_utf_mblen(p);
                               6391                 :                :     }
                               6392         [ -  + ]:             21 :     Assert((char *) p == (char *) result + size + VARHDRSZ);
                               6393                 :                : 
                               6394                 :             21 :     PG_RETURN_TEXT_P(result);
                               6395                 :                : }
                               6396                 :                : 
                               6397                 :                : /*
                               6398                 :                :  * Check whether the string is in the specified Unicode normalization form.
                               6399                 :                :  *
                               6400                 :                :  * This is done by converting the string to the specified normal form and then
                               6401                 :                :  * comparing that to the original string.  To speed that up, we also apply the
                               6402                 :                :  * "quick check" algorithm specified in UAX #15, which can give a yes or no
                               6403                 :                :  * answer for many strings by just scanning the string once.
                               6404                 :                :  *
                               6405                 :                :  * This function should generally be optimized for the case where the string
                               6406                 :                :  * is in fact normalized.  In that case, we'll end up looking at the entire
                               6407                 :                :  * string, so it's probably not worth doing any incremental conversion etc.
                               6408                 :                :  */
                               6409                 :                : Datum
                               6410                 :             69 : unicode_is_normalized(PG_FUNCTION_ARGS)
                               6411                 :                : {
                               6412                 :             69 :     text       *input = PG_GETARG_TEXT_PP(0);
                               6413                 :             69 :     char       *formstr = text_to_cstring(PG_GETARG_TEXT_PP(1));
                               6414                 :                :     UnicodeNormalizationForm form;
                               6415                 :                :     int         size;
                               6416                 :                :     pg_wchar   *input_chars;
                               6417                 :                :     pg_wchar   *output_chars;
                               6418                 :                :     unsigned char *p;
                               6419                 :                :     int         i;
                               6420                 :                :     UnicodeNormalizationQC quickcheck;
                               6421                 :                :     int         output_size;
                               6422                 :                :     bool        result;
                               6423                 :                : 
                               6424                 :             69 :     form = unicode_norm_form_from_string(formstr);
                               6425                 :                : 
                               6426                 :                :     /* convert to pg_wchar */
                               6427   [ -  +  -  -  :             66 :     size = pg_mbstrlen_with_len(VARDATA_ANY(input), VARSIZE_ANY_EXHDR(input));
                                     -  -  -  -  -  
                                           +  -  + ]
                               6428                 :             66 :     input_chars = palloc((size + 1) * sizeof(pg_wchar));
                               6429         [ -  + ]:             66 :     p = (unsigned char *) VARDATA_ANY(input);
                               6430         [ +  + ]:            252 :     for (i = 0; i < size; i++)
                               6431                 :                :     {
                               6432                 :            186 :         input_chars[i] = utf8_to_unicode(p);
                               6433                 :            186 :         p += pg_utf_mblen(p);
                               6434                 :                :     }
                               6435                 :             66 :     input_chars[i] = (pg_wchar) '\0';
                               6436   [ -  +  -  +  :             66 :     Assert((char *) p == VARDATA_ANY(input) + VARSIZE_ANY_EXHDR(input));
                                     -  -  -  -  -  
                                        -  -  +  -  
                                                 + ]
                               6437                 :                : 
                               6438                 :                :     /* quick check (see UAX #15) */
                               6439                 :             66 :     quickcheck = unicode_is_normalized_quickcheck(form, input_chars);
                               6440         [ +  + ]:             66 :     if (quickcheck == UNICODE_NORM_QC_YES)
                               6441                 :             21 :         PG_RETURN_BOOL(true);
                               6442         [ +  + ]:             45 :     else if (quickcheck == UNICODE_NORM_QC_NO)
                               6443                 :              6 :         PG_RETURN_BOOL(false);
                               6444                 :                : 
                               6445                 :                :     /* normalize and compare with original */
                               6446                 :             39 :     output_chars = unicode_normalize(form, input_chars);
                               6447                 :                : 
                               6448                 :             39 :     output_size = 0;
                               6449         [ +  + ]:            162 :     for (pg_wchar *wp = output_chars; *wp; wp++)
                               6450                 :            123 :         output_size++;
                               6451                 :                : 
                               6452         [ +  + ]:             57 :     result = (size == output_size) &&
                               6453         [ +  + ]:             18 :         (memcmp(input_chars, output_chars, size * sizeof(pg_wchar)) == 0);
                               6454                 :                : 
                               6455                 :             39 :     PG_RETURN_BOOL(result);
                               6456                 :                : }
                               6457                 :                : 
                               6458                 :                : /*
                               6459                 :                :  * Check if first n chars are hexadecimal digits
                               6460                 :                :  */
                               6461                 :                : static bool
 1113                          6462                 :             78 : isxdigits_n(const char *instr, size_t n)
                               6463                 :                : {
                               6464         [ +  + ]:            330 :     for (size_t i = 0; i < n; i++)
                               6465         [ +  + ]:            285 :         if (!isxdigit((unsigned char) instr[i]))
                               6466                 :             33 :             return false;
                               6467                 :                : 
                               6468                 :             45 :     return true;
                               6469                 :                : }
                               6470                 :                : 
                               6471                 :                : static unsigned int
                               6472                 :            252 : hexval(unsigned char c)
                               6473                 :                : {
                               6474   [ +  -  +  + ]:            252 :     if (c >= '0' && c <= '9')
                               6475                 :            192 :         return c - '0';
                               6476   [ +  +  +  - ]:             60 :     if (c >= 'a' && c <= 'f')
                               6477                 :             30 :         return c - 'a' + 0xA;
                               6478   [ +  -  +  - ]:             30 :     if (c >= 'A' && c <= 'F')
                               6479                 :             30 :         return c - 'A' + 0xA;
 1113 peter@eisentraut.org     6480         [ #  # ]:UBC           0 :     elog(ERROR, "invalid hexadecimal digit");
                               6481                 :                :     return 0;                   /* not reached */
                               6482                 :                : }
                               6483                 :                : 
                               6484                 :                : /*
                               6485                 :                :  * Translate string with hexadecimal digits to number
                               6486                 :                :  */
                               6487                 :                : static unsigned int
 1113 peter@eisentraut.org     6488                 :CBC          45 : hexval_n(const char *instr, size_t n)
                               6489                 :                : {
                               6490                 :             45 :     unsigned int result = 0;
                               6491                 :                : 
                               6492         [ +  + ]:            297 :     for (size_t i = 0; i < n; i++)
                               6493                 :            252 :         result += hexval(instr[i]) << (4 * (n - i - 1));
                               6494                 :                : 
                               6495                 :             45 :     return result;
                               6496                 :                : }
                               6497                 :                : 
                               6498                 :                : /*
                               6499                 :                :  * Replaces Unicode escape sequences by Unicode characters
                               6500                 :                :  */
                               6501                 :                : Datum
                               6502                 :             33 : unistr(PG_FUNCTION_ARGS)
                               6503                 :                : {
                               6504                 :             33 :     text       *input_text = PG_GETARG_TEXT_PP(0);
                               6505                 :                :     char       *instr;
                               6506                 :                :     int         len;
                               6507                 :                :     StringInfoData str;
                               6508                 :                :     text       *result;
                               6509                 :             33 :     pg_wchar    pair_first = 0;
                               6510                 :                :     char        cbuf[MAX_UNICODE_EQUIVALENT_STRING + 1];
                               6511                 :                : 
                               6512         [ -  + ]:             33 :     instr = VARDATA_ANY(input_text);
                               6513   [ -  +  -  -  :             33 :     len = VARSIZE_ANY_EXHDR(input_text);
                                     -  -  -  -  -  
                                                 + ]
                               6514                 :                : 
                               6515                 :             33 :     initStringInfo(&str);
                               6516                 :                : 
                               6517         [ +  + ]:            255 :     while (len > 0)
                               6518                 :                :     {
                               6519         [ +  + ]:            243 :         if (instr[0] == '\\')
                               6520                 :                :         {
                               6521         [ +  - ]:             51 :             if (len >= 2 &&
                               6522         [ +  + ]:             51 :                 instr[1] == '\\')
                               6523                 :                :             {
                               6524         [ -  + ]:              3 :                 if (pair_first)
 1113 peter@eisentraut.org     6525                 :UBC           0 :                     goto invalid_pair;
 1113 peter@eisentraut.org     6526                 :CBC           3 :                 appendStringInfoChar(&str, '\\');
                               6527                 :              3 :                 instr += 2;
                               6528                 :              3 :                 len -= 2;
                               6529                 :                :             }
                               6530   [ +  +  +  +  :             48 :             else if ((len >= 5 && isxdigits_n(instr + 1, 4)) ||
                                              +  + ]
                               6531   [ +  +  +  - ]:             33 :                      (len >= 6 && instr[1] == 'u' && isxdigits_n(instr + 2, 4)))
                               6532                 :             15 :             {
                               6533                 :                :                 pg_wchar    unicode;
                               6534         [ +  + ]:             21 :                 int         offset = instr[1] == 'u' ? 2 : 1;
                               6535                 :                : 
                               6536                 :             21 :                 unicode = hexval_n(instr + offset, 4);
                               6537                 :                : 
                               6538         [ -  + ]:             21 :                 if (!is_valid_unicode_codepoint(unicode))
 1113 peter@eisentraut.org     6539         [ #  # ]:UBC           0 :                     ereport(ERROR,
                               6540                 :                :                             errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               6541                 :                :                             errmsg("invalid Unicode code point: %04X", unicode));
                               6542                 :                : 
 1113 peter@eisentraut.org     6543         [ +  + ]:CBC          21 :                 if (pair_first)
                               6544                 :                :                 {
                               6545         [ -  + ]:              6 :                     if (is_utf16_surrogate_second(unicode))
                               6546                 :                :                     {
 1113 peter@eisentraut.org     6547                 :UBC           0 :                         unicode = surrogate_pair_to_codepoint(pair_first, unicode);
                               6548                 :              0 :                         pair_first = 0;
                               6549                 :                :                     }
                               6550                 :                :                     else
 1113 peter@eisentraut.org     6551                 :CBC           6 :                         goto invalid_pair;
                               6552                 :                :                 }
                               6553         [ -  + ]:             15 :                 else if (is_utf16_surrogate_second(unicode))
 1113 peter@eisentraut.org     6554                 :UBC           0 :                     goto invalid_pair;
                               6555                 :                : 
 1113 peter@eisentraut.org     6556         [ +  + ]:CBC          15 :                 if (is_utf16_surrogate_first(unicode))
                               6557                 :              9 :                     pair_first = unicode;
                               6558                 :                :                 else
                               6559                 :                :                 {
                               6560                 :              6 :                     pg_unicode_to_server(unicode, (unsigned char *) cbuf);
                               6561                 :              6 :                     appendStringInfoString(&str, cbuf);
                               6562                 :                :                 }
                               6563                 :                : 
                               6564                 :             15 :                 instr += 4 + offset;
                               6565                 :             15 :                 len -= 4 + offset;
                               6566                 :                :             }
                               6567   [ +  +  +  +  :             27 :             else if (len >= 8 && instr[1] == '+' && isxdigits_n(instr + 2, 6))
                                              +  - ]
                               6568                 :              6 :             {
                               6569                 :                :                 pg_wchar    unicode;
                               6570                 :                : 
                               6571                 :             12 :                 unicode = hexval_n(instr + 2, 6);
                               6572                 :                : 
                               6573         [ +  + ]:             12 :                 if (!is_valid_unicode_codepoint(unicode))
                               6574         [ +  - ]:              3 :                     ereport(ERROR,
                               6575                 :                :                             errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               6576                 :                :                             errmsg("invalid Unicode code point: %04X", unicode));
                               6577                 :                : 
                               6578         [ +  + ]:              9 :                 if (pair_first)
                               6579                 :                :                 {
                               6580         [ -  + ]:              3 :                     if (is_utf16_surrogate_second(unicode))
                               6581                 :                :                     {
 1113 peter@eisentraut.org     6582                 :UBC           0 :                         unicode = surrogate_pair_to_codepoint(pair_first, unicode);
                               6583                 :              0 :                         pair_first = 0;
                               6584                 :                :                     }
                               6585                 :                :                     else
 1113 peter@eisentraut.org     6586                 :CBC           3 :                         goto invalid_pair;
                               6587                 :                :                 }
                               6588         [ -  + ]:              6 :                 else if (is_utf16_surrogate_second(unicode))
 1113 peter@eisentraut.org     6589                 :UBC           0 :                     goto invalid_pair;
                               6590                 :                : 
 1113 peter@eisentraut.org     6591         [ +  + ]:CBC           6 :                 if (is_utf16_surrogate_first(unicode))
                               6592                 :              3 :                     pair_first = unicode;
                               6593                 :                :                 else
                               6594                 :                :                 {
                               6595                 :              3 :                     pg_unicode_to_server(unicode, (unsigned char *) cbuf);
                               6596                 :              3 :                     appendStringInfoString(&str, cbuf);
                               6597                 :                :                 }
                               6598                 :                : 
                               6599                 :              6 :                 instr += 8;
                               6600                 :              6 :                 len -= 8;
                               6601                 :                :             }
                               6602   [ +  +  +  -  :             15 :             else if (len >= 10 && instr[1] == 'U' && isxdigits_n(instr + 2, 8))
                                              +  - ]
                               6603                 :              6 :             {
                               6604                 :                :                 pg_wchar    unicode;
                               6605                 :                : 
                               6606                 :             12 :                 unicode = hexval_n(instr + 2, 8);
                               6607                 :                : 
                               6608         [ +  + ]:             12 :                 if (!is_valid_unicode_codepoint(unicode))
                               6609         [ +  - ]:              3 :                     ereport(ERROR,
                               6610                 :                :                             errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               6611                 :                :                             errmsg("invalid Unicode code point: %04X", unicode));
                               6612                 :                : 
                               6613         [ +  + ]:              9 :                 if (pair_first)
                               6614                 :                :                 {
                               6615         [ -  + ]:              3 :                     if (is_utf16_surrogate_second(unicode))
                               6616                 :                :                     {
 1113 peter@eisentraut.org     6617                 :UBC           0 :                         unicode = surrogate_pair_to_codepoint(pair_first, unicode);
                               6618                 :              0 :                         pair_first = 0;
                               6619                 :                :                     }
                               6620                 :                :                     else
 1113 peter@eisentraut.org     6621                 :CBC           3 :                         goto invalid_pair;
                               6622                 :                :                 }
                               6623         [ -  + ]:              6 :                 else if (is_utf16_surrogate_second(unicode))
 1113 peter@eisentraut.org     6624                 :UBC           0 :                     goto invalid_pair;
                               6625                 :                : 
 1113 peter@eisentraut.org     6626         [ +  + ]:CBC           6 :                 if (is_utf16_surrogate_first(unicode))
                               6627                 :              3 :                     pair_first = unicode;
                               6628                 :                :                 else
                               6629                 :                :                 {
                               6630                 :              3 :                     pg_unicode_to_server(unicode, (unsigned char *) cbuf);
                               6631                 :              3 :                     appendStringInfoString(&str, cbuf);
                               6632                 :                :                 }
                               6633                 :                : 
                               6634                 :              6 :                 instr += 10;
                               6635                 :              6 :                 len -= 10;
                               6636                 :                :             }
                               6637                 :                :             else
                               6638         [ +  - ]:              3 :                 ereport(ERROR,
                               6639                 :                :                         (errcode(ERRCODE_SYNTAX_ERROR),
                               6640                 :                :                          errmsg("invalid Unicode escape"),
                               6641                 :                :                          errhint("Unicode escapes must be \\XXXX, \\+XXXXXX, \\uXXXX, or \\UXXXXXXXX.")));
                               6642                 :                :         }
                               6643                 :                :         else
                               6644                 :                :         {
                               6645         [ -  + ]:            192 :             if (pair_first)
 1113 peter@eisentraut.org     6646                 :UBC           0 :                 goto invalid_pair;
                               6647                 :                : 
 1113 peter@eisentraut.org     6648                 :CBC         192 :             appendStringInfoChar(&str, *instr++);
                               6649                 :            192 :             len--;
                               6650                 :                :         }
                               6651                 :                :     }
                               6652                 :                : 
                               6653                 :                :     /* unfinished surrogate pair? */
                               6654         [ +  + ]:             12 :     if (pair_first)
                               6655                 :              3 :         goto invalid_pair;
                               6656                 :                : 
                               6657                 :              9 :     result = cstring_to_text_with_len(str.data, str.len);
                               6658                 :              9 :     pfree(str.data);
                               6659                 :                : 
                               6660                 :              9 :     PG_RETURN_TEXT_P(result);
                               6661                 :                : 
                               6662                 :             15 : invalid_pair:
                               6663         [ +  - ]:             15 :     ereport(ERROR,
                               6664                 :                :             (errcode(ERRCODE_SYNTAX_ERROR),
                               6665                 :                :              errmsg("invalid Unicode surrogate pair")));
                               6666                 :                :     PG_RETURN_NULL();           /* keep compiler quiet */
                               6667                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622