LCOV - code coverage report
Current view: top level - src/backend/utils/adt - bytea.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 38.3 % 590 226
Test Date: 2026-01-26 10:56:24 Functions: 39.0 % 41 16
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 25.3 % 308 78

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * bytea.c
       4                 :             :  *        Functions for the bytea type.
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 2025-2026, PostgreSQL Global Development Group
       7                 :             :  *
       8                 :             :  *
       9                 :             :  * IDENTIFICATION
      10                 :             :  *        src/backend/utils/adt/bytea.c
      11                 :             :  *
      12                 :             :  *-------------------------------------------------------------------------
      13                 :             :  */
      14                 :             : 
      15                 :             : #include "postgres.h"
      16                 :             : 
      17                 :             : #include "access/detoast.h"
      18                 :             : #include "common/hashfn.h"
      19                 :             : #include "common/int.h"
      20                 :             : #include "fmgr.h"
      21                 :             : #include "lib/hyperloglog.h"
      22                 :             : #include "libpq/pqformat.h"
      23                 :             : #include "port/pg_bitutils.h"
      24                 :             : #include "port/pg_bswap.h"
      25                 :             : #include "utils/builtins.h"
      26                 :             : #include "utils/bytea.h"
      27                 :             : #include "utils/fmgrprotos.h"
      28                 :             : #include "utils/guc.h"
      29                 :             : #include "utils/memutils.h"
      30                 :             : #include "utils/sortsupport.h"
      31                 :             : #include "varatt.h"
      32                 :             : 
      33                 :             : /* GUC variable */
      34                 :             : int                     bytea_output = BYTEA_OUTPUT_HEX;
      35                 :             : 
      36                 :             : static bytea *bytea_catenate(bytea *t1, bytea *t2);
      37                 :             : static bytea *bytea_substring(Datum str, int S, int L,
      38                 :             :                                                           bool length_not_specified);
      39                 :             : static bytea *bytea_overlay(bytea *t1, bytea *t2, int sp, int sl);
      40                 :             : 
      41                 :             : typedef struct
      42                 :             : {
      43                 :             :         bool            abbreviate;             /* Should we abbreviate keys? */
      44                 :             :         hyperLogLogState abbr_card; /* Abbreviated key cardinality state */
      45                 :             :         hyperLogLogState full_card; /* Full key cardinality state */
      46                 :             :         double          prop_card;              /* Required cardinality proportion */
      47                 :             : } ByteaSortSupport;
      48                 :             : 
      49                 :             : /* Static function declarations for sort support */
      50                 :             : static int      byteafastcmp(Datum x, Datum y, SortSupport ssup);
      51                 :             : static Datum bytea_abbrev_convert(Datum original, SortSupport ssup);
      52                 :             : static bool bytea_abbrev_abort(int memtupcount, SortSupport ssup);
      53                 :             : 
      54                 :             : /*
      55                 :             :  * bytea_catenate
      56                 :             :  *      Guts of byteacat(), broken out so it can be used by other functions
      57                 :             :  *
      58                 :             :  * Arguments can be in short-header form, but not compressed or out-of-line
      59                 :             :  */
      60                 :             : static bytea *
      61                 :         259 : bytea_catenate(bytea *t1, bytea *t2)
      62                 :             : {
      63                 :         259 :         bytea      *result;
      64                 :         259 :         int                     len1,
      65                 :             :                                 len2,
      66                 :             :                                 len;
      67                 :         259 :         char       *ptr;
      68                 :             : 
      69                 :         259 :         len1 = VARSIZE_ANY_EXHDR(t1);
      70                 :         259 :         len2 = VARSIZE_ANY_EXHDR(t2);
      71                 :             : 
      72                 :             :         /* paranoia ... probably should throw error instead? */
      73         [ +  - ]:         259 :         if (len1 < 0)
      74                 :           0 :                 len1 = 0;
      75         [ +  - ]:         259 :         if (len2 < 0)
      76                 :           0 :                 len2 = 0;
      77                 :             : 
      78                 :         259 :         len = len1 + len2 + VARHDRSZ;
      79                 :         259 :         result = (bytea *) palloc(len);
      80                 :             : 
      81                 :             :         /* Set size of result string... */
      82                 :         259 :         SET_VARSIZE(result, len);
      83                 :             : 
      84                 :             :         /* Fill data field of result string... */
      85                 :         259 :         ptr = VARDATA(result);
      86         [ -  + ]:         259 :         if (len1 > 0)
      87                 :         259 :                 memcpy(ptr, VARDATA_ANY(t1), len1);
      88         [ +  + ]:         259 :         if (len2 > 0)
      89                 :         256 :                 memcpy(ptr + len1, VARDATA_ANY(t2), len2);
      90                 :             : 
      91                 :         518 :         return result;
      92                 :         259 : }
      93                 :             : 
      94                 :             : #define PG_STR_GET_BYTEA(str_) \
      95                 :             :         DatumGetByteaPP(DirectFunctionCall1(byteain, CStringGetDatum(str_)))
      96                 :             : 
      97                 :             : static bytea *
      98                 :         675 : bytea_substring(Datum str,
      99                 :             :                                 int S,
     100                 :             :                                 int L,
     101                 :             :                                 bool length_not_specified)
     102                 :             : {
     103                 :         675 :         int32           S1;                             /* adjusted start position */
     104                 :         675 :         int32           L1;                             /* adjusted substring length */
     105                 :         675 :         int32           E;                              /* end position */
     106                 :             : 
     107                 :             :         /*
     108                 :             :          * The logic here should generally match text_substring().
     109                 :             :          */
     110         [ +  + ]:         675 :         S1 = Max(S, 1);
     111                 :             : 
     112         [ +  + ]:         675 :         if (length_not_specified)
     113                 :             :         {
     114                 :             :                 /*
     115                 :             :                  * Not passed a length - DatumGetByteaPSlice() grabs everything to the
     116                 :             :                  * end of the string if we pass it a negative value for length.
     117                 :             :                  */
     118                 :         659 :                 L1 = -1;
     119                 :         659 :         }
     120         [ +  + ]:          16 :         else if (L < 0)
     121                 :             :         {
     122                 :             :                 /* SQL99 says to throw an error for E < S, i.e., negative length */
     123   [ +  -  +  - ]:           2 :                 ereport(ERROR,
     124                 :             :                                 (errcode(ERRCODE_SUBSTRING_ERROR),
     125                 :             :                                  errmsg("negative substring length not allowed")));
     126                 :           0 :                 L1 = -1;                                /* silence stupider compilers */
     127                 :           0 :         }
     128         [ +  + ]:          14 :         else if (pg_add_s32_overflow(S, L, &E))
     129                 :             :         {
     130                 :             :                 /*
     131                 :             :                  * L could be large enough for S + L to overflow, in which case the
     132                 :             :                  * substring must run to end of string.
     133                 :             :                  */
     134                 :           1 :                 L1 = -1;
     135                 :           1 :         }
     136                 :             :         else
     137                 :             :         {
     138                 :             :                 /*
     139                 :             :                  * A zero or negative value for the end position can happen if the
     140                 :             :                  * start was negative or one. SQL99 says to return a zero-length
     141                 :             :                  * string.
     142                 :             :                  */
     143         [ +  - ]:          13 :                 if (E < 1)
     144                 :           0 :                         return PG_STR_GET_BYTEA("");
     145                 :             : 
     146                 :          13 :                 L1 = E - S1;
     147                 :             :         }
     148                 :             : 
     149                 :             :         /*
     150                 :             :          * If the start position is past the end of the string, SQL99 says to
     151                 :             :          * return a zero-length string -- DatumGetByteaPSlice() will do that for
     152                 :             :          * us.  We need only convert S1 to zero-based starting position.
     153                 :             :          */
     154                 :         673 :         return DatumGetByteaPSlice(str, S1 - 1, L1);
     155                 :         673 : }
     156                 :             : 
     157                 :             : static bytea *
     158                 :           3 : bytea_overlay(bytea *t1, bytea *t2, int sp, int sl)
     159                 :             : {
     160                 :           3 :         bytea      *result;
     161                 :           3 :         bytea      *s1;
     162                 :           3 :         bytea      *s2;
     163                 :           3 :         int                     sp_pl_sl;
     164                 :             : 
     165                 :             :         /*
     166                 :             :          * Check for possible integer-overflow cases.  For negative sp, throw a
     167                 :             :          * "substring length" error because that's what should be expected
     168                 :             :          * according to the spec's definition of OVERLAY().
     169                 :             :          */
     170         [ +  - ]:           3 :         if (sp <= 0)
     171   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     172                 :             :                                 (errcode(ERRCODE_SUBSTRING_ERROR),
     173                 :             :                                  errmsg("negative substring length not allowed")));
     174         [ +  - ]:           3 :         if (pg_add_s32_overflow(sp, sl, &sp_pl_sl))
     175   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     176                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     177                 :             :                                  errmsg("integer out of range")));
     178                 :             : 
     179                 :           3 :         s1 = bytea_substring(PointerGetDatum(t1), 1, sp - 1, false);
     180                 :           3 :         s2 = bytea_substring(PointerGetDatum(t1), sp_pl_sl, -1, true);
     181                 :           3 :         result = bytea_catenate(s1, t2);
     182                 :           3 :         result = bytea_catenate(result, s2);
     183                 :             : 
     184                 :           6 :         return result;
     185                 :           3 : }
     186                 :             : 
     187                 :             : /*****************************************************************************
     188                 :             :  *       USER I/O ROUTINES                                                                                                               *
     189                 :             :  *****************************************************************************/
     190                 :             : 
     191                 :             : #define VAL(CH)                 ((CH) - '0')
     192                 :             : #define DIG(VAL)                ((VAL) + '0')
     193                 :             : 
     194                 :             : /*
     195                 :             :  *              byteain                 - converts from printable representation of byte array
     196                 :             :  *
     197                 :             :  *              Non-printable characters must be passed as '\nnn' (octal) and are
     198                 :             :  *              converted to internal form.  '\' must be passed as '\\'.
     199                 :             :  */
     200                 :             : Datum
     201                 :       45425 : byteain(PG_FUNCTION_ARGS)
     202                 :             : {
     203                 :       45425 :         char       *inputText = PG_GETARG_CSTRING(0);
     204                 :       45425 :         Node       *escontext = fcinfo->context;
     205                 :       45425 :         size_t          len = strlen(inputText);
     206                 :       45425 :         size_t          bc;
     207                 :       45425 :         char       *tp;
     208                 :       45425 :         char       *rp;
     209                 :       45425 :         bytea      *result;
     210                 :             : 
     211                 :             :         /* Recognize hex input */
     212   [ +  +  +  + ]:       45425 :         if (inputText[0] == '\\' && inputText[1] == 'x')
     213                 :             :         {
     214                 :         194 :                 bc = (len - 2) / 2 + VARHDRSZ;  /* maximum possible length */
     215                 :         194 :                 result = palloc(bc);
     216                 :         388 :                 bc = hex_decode_safe(inputText + 2, len - 2, VARDATA(result),
     217                 :         194 :                                                          escontext);
     218                 :         194 :                 SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */
     219                 :             : 
     220                 :         194 :                 PG_RETURN_BYTEA_P(result);
     221                 :             :         }
     222                 :             : 
     223                 :             :         /* Else, it's the traditional escaped style */
     224                 :       45231 :         result = (bytea *) palloc(len + VARHDRSZ);      /* maximum possible length */
     225                 :             : 
     226                 :       45231 :         tp = inputText;
     227                 :       45231 :         rp = VARDATA(result);
     228         [ +  + ]:      708542 :         while (*tp != '\0')
     229                 :             :         {
     230         [ +  + ]:      663314 :                 if (tp[0] != '\\')
     231                 :      663187 :                         *rp++ = *tp++;
     232   [ +  +  +  + ]:         127 :                 else if ((tp[1] >= '0' && tp[1] <= '3') &&
     233   [ +  -  +  -  :         244 :                                  (tp[2] >= '0' && tp[2] <= '7') &&
                   -  + ]
     234         [ +  - ]:         122 :                                  (tp[3] >= '0' && tp[3] <= '7'))
     235                 :             :                 {
     236                 :         122 :                         int                     v;
     237                 :             : 
     238                 :         122 :                         v = VAL(tp[1]);
     239                 :         122 :                         v <<= 3;
     240                 :         122 :                         v += VAL(tp[2]);
     241                 :         122 :                         v <<= 3;
     242                 :         122 :                         *rp++ = v + VAL(tp[3]);
     243                 :             : 
     244                 :         122 :                         tp += 4;
     245                 :         122 :                 }
     246         [ +  + ]:           5 :                 else if (tp[1] == '\\')
     247                 :             :                 {
     248                 :           2 :                         *rp++ = '\\';
     249                 :           2 :                         tp += 2;
     250                 :           2 :                 }
     251                 :             :                 else
     252                 :             :                 {
     253                 :             :                         /*
     254                 :             :                          * one backslash, not followed by another or ### valid octal
     255                 :             :                          */
     256         [ +  + ]:           3 :                         ereturn(escontext, (Datum) 0,
     257                 :             :                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     258                 :             :                                          errmsg("invalid input syntax for type %s", "bytea")));
     259                 :             :                 }
     260                 :             :         }
     261                 :             : 
     262                 :       45228 :         bc = rp - VARDATA(result);      /* actual length */
     263                 :       45228 :         SET_VARSIZE(result, bc + VARHDRSZ);
     264                 :             : 
     265                 :       45228 :         PG_RETURN_BYTEA_P(result);
     266                 :       45423 : }
     267                 :             : 
     268                 :             : /*
     269                 :             :  *              byteaout                - converts to printable representation of byte array
     270                 :             :  *
     271                 :             :  *              In the traditional escaped format, non-printable characters are
     272                 :             :  *              printed as '\nnn' (octal) and '\' as '\\'.
     273                 :             :  */
     274                 :             : Datum
     275                 :        1875 : byteaout(PG_FUNCTION_ARGS)
     276                 :             : {
     277                 :        1875 :         bytea      *vlena = PG_GETARG_BYTEA_PP(0);
     278                 :        1875 :         char       *result;
     279                 :        1875 :         char       *rp;
     280                 :             : 
     281         [ +  + ]:        1875 :         if (bytea_output == BYTEA_OUTPUT_HEX)
     282                 :             :         {
     283                 :             :                 /* Print hex format */
     284                 :        1815 :                 rp = result = palloc(VARSIZE_ANY_EXHDR(vlena) * 2 + 2 + 1);
     285                 :        1815 :                 *rp++ = '\\';
     286                 :        1815 :                 *rp++ = 'x';
     287                 :        1815 :                 rp += hex_encode(VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena), rp);
     288                 :        1815 :         }
     289         [ +  - ]:          60 :         else if (bytea_output == BYTEA_OUTPUT_ESCAPE)
     290                 :             :         {
     291                 :             :                 /* Print traditional escaped format */
     292                 :          60 :                 char       *vp;
     293                 :          60 :                 uint64          len;
     294                 :          60 :                 int                     i;
     295                 :             : 
     296                 :          60 :                 len = 1;                                /* empty string has 1 char */
     297                 :          60 :                 vp = VARDATA_ANY(vlena);
     298         [ +  + ]:       36268 :                 for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++)
     299                 :             :                 {
     300         [ +  + ]:       36208 :                         if (*vp == '\\')
     301                 :           1 :                                 len += 2;
     302   [ +  +  +  + ]:       36207 :                         else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e)
     303                 :          81 :                                 len += 4;
     304                 :             :                         else
     305                 :       36126 :                                 len++;
     306                 :       36208 :                 }
     307                 :             : 
     308                 :             :                 /*
     309                 :             :                  * In principle len can't overflow uint32 if the input fit in 1GB, but
     310                 :             :                  * for safety let's check rather than relying on palloc's internal
     311                 :             :                  * check.
     312                 :             :                  */
     313         [ +  - ]:          60 :                 if (len > MaxAllocSize)
     314   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     315                 :             :                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     316                 :             :                                          errmsg_internal("result of bytea output conversion is too large")));
     317                 :          60 :                 rp = result = (char *) palloc(len);
     318                 :             : 
     319                 :          60 :                 vp = VARDATA_ANY(vlena);
     320         [ +  + ]:       36268 :                 for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++)
     321                 :             :                 {
     322         [ +  + ]:       36208 :                         if (*vp == '\\')
     323                 :             :                         {
     324                 :           1 :                                 *rp++ = '\\';
     325                 :           1 :                                 *rp++ = '\\';
     326                 :           1 :                         }
     327   [ +  +  +  + ]:       36207 :                         else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e)
     328                 :             :                         {
     329                 :          81 :                                 int                     val;    /* holds unprintable chars */
     330                 :             : 
     331                 :          81 :                                 val = *vp;
     332                 :          81 :                                 rp[0] = '\\';
     333                 :          81 :                                 rp[3] = DIG(val & 07);
     334                 :          81 :                                 val >>= 3;
     335                 :          81 :                                 rp[2] = DIG(val & 07);
     336                 :          81 :                                 val >>= 3;
     337                 :          81 :                                 rp[1] = DIG(val & 03);
     338                 :          81 :                                 rp += 4;
     339                 :          81 :                         }
     340                 :             :                         else
     341                 :       36126 :                                 *rp++ = *vp;
     342                 :       36208 :                 }
     343                 :          60 :         }
     344                 :             :         else
     345                 :             :         {
     346   [ #  #  #  # ]:           0 :                 elog(ERROR, "unrecognized \"bytea_output\" setting: %d",
     347                 :             :                          bytea_output);
     348                 :           0 :                 rp = result = NULL;             /* keep compiler quiet */
     349                 :             :         }
     350                 :        1875 :         *rp = '\0';
     351                 :        3750 :         PG_RETURN_CSTRING(result);
     352                 :        1875 : }
     353                 :             : 
     354                 :             : /*
     355                 :             :  *              bytearecv                       - converts external binary format to bytea
     356                 :             :  */
     357                 :             : Datum
     358                 :         164 : bytearecv(PG_FUNCTION_ARGS)
     359                 :             : {
     360                 :         164 :         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
     361                 :         164 :         bytea      *result;
     362                 :         164 :         int                     nbytes;
     363                 :             : 
     364                 :         164 :         nbytes = buf->len - buf->cursor;
     365                 :         164 :         result = (bytea *) palloc(nbytes + VARHDRSZ);
     366                 :         164 :         SET_VARSIZE(result, nbytes + VARHDRSZ);
     367                 :         164 :         pq_copymsgbytes(buf, VARDATA(result), nbytes);
     368                 :         328 :         PG_RETURN_BYTEA_P(result);
     369                 :         164 : }
     370                 :             : 
     371                 :             : /*
     372                 :             :  *              byteasend                       - converts bytea to binary format
     373                 :             :  *
     374                 :             :  * This is a special case: just copy the input...
     375                 :             :  */
     376                 :             : Datum
     377                 :          83 : byteasend(PG_FUNCTION_ARGS)
     378                 :             : {
     379                 :          83 :         bytea      *vlena = PG_GETARG_BYTEA_P_COPY(0);
     380                 :             : 
     381                 :         166 :         PG_RETURN_BYTEA_P(vlena);
     382                 :          83 : }
     383                 :             : 
     384                 :             : Datum
     385                 :       10007 : bytea_string_agg_transfn(PG_FUNCTION_ARGS)
     386                 :             : {
     387                 :       10007 :         StringInfo      state;
     388                 :             : 
     389         [ +  + ]:       10007 :         state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);
     390                 :             : 
     391                 :             :         /* Append the value unless null, preceding it with the delimiter. */
     392         [ +  + ]:       10007 :         if (!PG_ARGISNULL(1))
     393                 :             :         {
     394                 :        7507 :                 bytea      *value = PG_GETARG_BYTEA_PP(1);
     395                 :        7507 :                 bool            isfirst = false;
     396                 :             : 
     397                 :             :                 /*
     398                 :             :                  * You might think we can just throw away the first delimiter, however
     399                 :             :                  * we must keep it as we may be a parallel worker doing partial
     400                 :             :                  * aggregation building a state to send to the main process.  We need
     401                 :             :                  * to keep the delimiter of every aggregation so that the combine
     402                 :             :                  * function can properly join up the strings of two separately
     403                 :             :                  * partially aggregated results.  The first delimiter is only stripped
     404                 :             :                  * off in the final function.  To know how much to strip off the front
     405                 :             :                  * of the string, we store the length of the first delimiter in the
     406                 :             :                  * StringInfo's cursor field, which we don't otherwise need here.
     407                 :             :                  */
     408         [ +  + ]:        7507 :                 if (state == NULL)
     409                 :             :                 {
     410                 :          34 :                         MemoryContext aggcontext;
     411                 :          34 :                         MemoryContext oldcontext;
     412                 :             : 
     413         [ +  - ]:          34 :                         if (!AggCheckCallContext(fcinfo, &aggcontext))
     414                 :             :                         {
     415                 :             :                                 /* cannot be called directly because of internal-type argument */
     416   [ #  #  #  # ]:           0 :                                 elog(ERROR, "bytea_string_agg_transfn called in non-aggregate context");
     417                 :           0 :                         }
     418                 :             : 
     419                 :             :                         /*
     420                 :             :                          * Create state in aggregate context.  It'll stay there across
     421                 :             :                          * subsequent calls.
     422                 :             :                          */
     423                 :          34 :                         oldcontext = MemoryContextSwitchTo(aggcontext);
     424                 :          34 :                         state = makeStringInfo();
     425                 :          34 :                         MemoryContextSwitchTo(oldcontext);
     426                 :             : 
     427                 :          34 :                         isfirst = true;
     428                 :          34 :                 }
     429                 :             : 
     430         [ +  + ]:        7507 :                 if (!PG_ARGISNULL(2))
     431                 :             :                 {
     432                 :        7505 :                         bytea      *delim = PG_GETARG_BYTEA_PP(2);
     433                 :             : 
     434                 :       15010 :                         appendBinaryStringInfo(state, VARDATA_ANY(delim),
     435                 :        7505 :                                                                    VARSIZE_ANY_EXHDR(delim));
     436         [ +  + ]:        7505 :                         if (isfirst)
     437                 :          33 :                                 state->cursor = VARSIZE_ANY_EXHDR(delim);
     438                 :        7505 :                 }
     439                 :             : 
     440                 :       15014 :                 appendBinaryStringInfo(state, VARDATA_ANY(value),
     441                 :        7507 :                                                            VARSIZE_ANY_EXHDR(value));
     442                 :        7507 :         }
     443                 :             : 
     444                 :             :         /*
     445                 :             :          * The transition type for string_agg() is declared to be "internal",
     446                 :             :          * which is a pass-by-value type the same size as a pointer.
     447                 :             :          */
     448         [ +  + ]:       10007 :         if (state)
     449                 :        9999 :                 PG_RETURN_POINTER(state);
     450                 :           8 :         PG_RETURN_NULL();
     451         [ -  + ]:       10007 : }
     452                 :             : 
     453                 :             : Datum
     454                 :          25 : bytea_string_agg_finalfn(PG_FUNCTION_ARGS)
     455                 :             : {
     456                 :          25 :         StringInfo      state;
     457                 :             : 
     458                 :             :         /* cannot be called directly because of internal-type argument */
     459         [ +  - ]:          25 :         Assert(AggCheckCallContext(fcinfo, NULL));
     460                 :             : 
     461         [ +  + ]:          25 :         state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);
     462                 :             : 
     463         [ +  + ]:          25 :         if (state != NULL)
     464                 :             :         {
     465                 :             :                 /* As per comment in transfn, strip data before the cursor position */
     466                 :          24 :                 bytea      *result;
     467                 :          24 :                 int                     strippedlen = state->len - state->cursor;
     468                 :             : 
     469                 :          24 :                 result = (bytea *) palloc(strippedlen + VARHDRSZ);
     470                 :          24 :                 SET_VARSIZE(result, strippedlen + VARHDRSZ);
     471                 :          24 :                 memcpy(VARDATA(result), &state->data[state->cursor], strippedlen);
     472                 :          24 :                 PG_RETURN_BYTEA_P(result);
     473                 :          24 :         }
     474                 :             :         else
     475                 :           1 :                 PG_RETURN_NULL();
     476         [ -  + ]:          25 : }
     477                 :             : 
     478                 :             : /*-------------------------------------------------------------
     479                 :             :  * byteaoctetlen
     480                 :             :  *
     481                 :             :  * get the number of bytes contained in an instance of type 'bytea'
     482                 :             :  *-------------------------------------------------------------
     483                 :             :  */
     484                 :             : Datum
     485                 :         104 : byteaoctetlen(PG_FUNCTION_ARGS)
     486                 :             : {
     487                 :         104 :         Datum           str = PG_GETARG_DATUM(0);
     488                 :             : 
     489                 :             :         /* We need not detoast the input at all */
     490                 :         208 :         PG_RETURN_INT32(toast_raw_datum_size(str) - VARHDRSZ);
     491                 :         104 : }
     492                 :             : 
     493                 :             : /*
     494                 :             :  * byteacat -
     495                 :             :  *        takes two bytea* and returns a bytea* that is the concatenation of
     496                 :             :  *        the two.
     497                 :             :  *
     498                 :             :  * Cloned from textcat and modified as required.
     499                 :             :  */
     500                 :             : Datum
     501                 :         253 : byteacat(PG_FUNCTION_ARGS)
     502                 :             : {
     503                 :         253 :         bytea      *t1 = PG_GETARG_BYTEA_PP(0);
     504                 :         253 :         bytea      *t2 = PG_GETARG_BYTEA_PP(1);
     505                 :             : 
     506                 :         506 :         PG_RETURN_BYTEA_P(bytea_catenate(t1, t2));
     507                 :         253 : }
     508                 :             : 
     509                 :             : /*
     510                 :             :  * byteaoverlay
     511                 :             :  *      Replace specified substring of first string with second
     512                 :             :  *
     513                 :             :  * The SQL standard defines OVERLAY() in terms of substring and concatenation.
     514                 :             :  * This code is a direct implementation of what the standard says.
     515                 :             :  */
     516                 :             : Datum
     517                 :           1 : byteaoverlay(PG_FUNCTION_ARGS)
     518                 :             : {
     519                 :           1 :         bytea      *t1 = PG_GETARG_BYTEA_PP(0);
     520                 :           1 :         bytea      *t2 = PG_GETARG_BYTEA_PP(1);
     521                 :           1 :         int                     sp = PG_GETARG_INT32(2);        /* substring start position */
     522                 :           1 :         int                     sl = PG_GETARG_INT32(3);        /* substring length */
     523                 :             : 
     524                 :           2 :         PG_RETURN_BYTEA_P(bytea_overlay(t1, t2, sp, sl));
     525                 :           1 : }
     526                 :             : 
     527                 :             : Datum
     528                 :           2 : byteaoverlay_no_len(PG_FUNCTION_ARGS)
     529                 :             : {
     530                 :           2 :         bytea      *t1 = PG_GETARG_BYTEA_PP(0);
     531                 :           2 :         bytea      *t2 = PG_GETARG_BYTEA_PP(1);
     532                 :           2 :         int                     sp = PG_GETARG_INT32(2);        /* substring start position */
     533                 :           2 :         int                     sl;
     534                 :             : 
     535                 :           2 :         sl = VARSIZE_ANY_EXHDR(t2); /* defaults to length(t2) */
     536                 :           4 :         PG_RETURN_BYTEA_P(bytea_overlay(t1, t2, sp, sl));
     537                 :           2 : }
     538                 :             : 
     539                 :             : /*
     540                 :             :  * bytea_substr()
     541                 :             :  * Return a substring starting at the specified position.
     542                 :             :  * Cloned from text_substr and modified as required.
     543                 :             :  *
     544                 :             :  * Input:
     545                 :             :  *      - string
     546                 :             :  *      - starting position (is one-based)
     547                 :             :  *      - string length (optional)
     548                 :             :  *
     549                 :             :  * If the starting position is zero or less, then return from the start of the string
     550                 :             :  * adjusting the length to be consistent with the "negative start" per SQL.
     551                 :             :  * If the length is less than zero, an ERROR is thrown. If no third argument
     552                 :             :  * (length) is provided, the length to the end of the string is assumed.
     553                 :             :  */
     554                 :             : Datum
     555                 :          13 : bytea_substr(PG_FUNCTION_ARGS)
     556                 :             : {
     557                 :          13 :         PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
     558                 :             :                                                                           PG_GETARG_INT32(1),
     559                 :             :                                                                           PG_GETARG_INT32(2),
     560                 :             :                                                                           false));
     561                 :             : }
     562                 :             : 
     563                 :             : /*
     564                 :             :  * bytea_substr_no_len -
     565                 :             :  *        Wrapper to avoid opr_sanity failure due to
     566                 :             :  *        one function accepting a different number of args.
     567                 :             :  */
     568                 :             : Datum
     569                 :         656 : bytea_substr_no_len(PG_FUNCTION_ARGS)
     570                 :             : {
     571                 :         656 :         PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
     572                 :             :                                                                           PG_GETARG_INT32(1),
     573                 :             :                                                                           -1,
     574                 :             :                                                                           true));
     575                 :             : }
     576                 :             : 
     577                 :             : /*
     578                 :             :  * bit_count
     579                 :             :  */
     580                 :             : Datum
     581                 :           1 : bytea_bit_count(PG_FUNCTION_ARGS)
     582                 :             : {
     583                 :           1 :         bytea      *t1 = PG_GETARG_BYTEA_PP(0);
     584                 :             : 
     585                 :           2 :         PG_RETURN_INT64(pg_popcount(VARDATA_ANY(t1), VARSIZE_ANY_EXHDR(t1)));
     586                 :           1 : }
     587                 :             : 
     588                 :             : /*
     589                 :             :  * byteapos -
     590                 :             :  *        Return the position of the specified substring.
     591                 :             :  *        Implements the SQL POSITION() function.
     592                 :             :  * Cloned from textpos and modified as required.
     593                 :             :  */
     594                 :             : Datum
     595                 :           0 : byteapos(PG_FUNCTION_ARGS)
     596                 :             : {
     597                 :           0 :         bytea      *t1 = PG_GETARG_BYTEA_PP(0);
     598                 :           0 :         bytea      *t2 = PG_GETARG_BYTEA_PP(1);
     599                 :           0 :         int                     pos;
     600                 :           0 :         int                     px,
     601                 :             :                                 p;
     602                 :           0 :         int                     len1,
     603                 :             :                                 len2;
     604                 :           0 :         char       *p1,
     605                 :             :                            *p2;
     606                 :             : 
     607                 :           0 :         len1 = VARSIZE_ANY_EXHDR(t1);
     608                 :           0 :         len2 = VARSIZE_ANY_EXHDR(t2);
     609                 :             : 
     610         [ #  # ]:           0 :         if (len2 <= 0)
     611                 :           0 :                 PG_RETURN_INT32(1);             /* result for empty pattern */
     612                 :             : 
     613                 :           0 :         p1 = VARDATA_ANY(t1);
     614                 :           0 :         p2 = VARDATA_ANY(t2);
     615                 :             : 
     616                 :           0 :         pos = 0;
     617                 :           0 :         px = (len1 - len2);
     618         [ #  # ]:           0 :         for (p = 0; p <= px; p++)
     619                 :             :         {
     620   [ #  #  #  # ]:           0 :                 if ((*p2 == *p1) && (memcmp(p1, p2, len2) == 0))
     621                 :             :                 {
     622                 :           0 :                         pos = p + 1;
     623                 :           0 :                         break;
     624                 :             :                 };
     625                 :           0 :                 p1++;
     626                 :           0 :         };
     627                 :             : 
     628                 :           0 :         PG_RETURN_INT32(pos);
     629                 :           0 : }
     630                 :             : 
     631                 :             : /*-------------------------------------------------------------
     632                 :             :  * byteaGetByte
     633                 :             :  *
     634                 :             :  * this routine treats "bytea" as an array of bytes.
     635                 :             :  * It returns the Nth byte (a number between 0 and 255).
     636                 :             :  *-------------------------------------------------------------
     637                 :             :  */
     638                 :             : Datum
     639                 :           0 : byteaGetByte(PG_FUNCTION_ARGS)
     640                 :             : {
     641                 :           0 :         bytea      *v = PG_GETARG_BYTEA_PP(0);
     642                 :           0 :         int32           n = PG_GETARG_INT32(1);
     643                 :           0 :         int                     len;
     644                 :           0 :         int                     byte;
     645                 :             : 
     646                 :           0 :         len = VARSIZE_ANY_EXHDR(v);
     647                 :             : 
     648         [ #  # ]:           0 :         if (n < 0 || n >= len)
     649   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     650                 :             :                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     651                 :             :                                  errmsg("index %d out of valid range, 0..%d",
     652                 :             :                                                 n, len - 1)));
     653                 :             : 
     654                 :           0 :         byte = ((unsigned char *) VARDATA_ANY(v))[n];
     655                 :             : 
     656                 :           0 :         PG_RETURN_INT32(byte);
     657                 :           0 : }
     658                 :             : 
     659                 :             : /*-------------------------------------------------------------
     660                 :             :  * byteaGetBit
     661                 :             :  *
     662                 :             :  * This routine treats a "bytea" type like an array of bits.
     663                 :             :  * It returns the value of the Nth bit (0 or 1).
     664                 :             :  *
     665                 :             :  *-------------------------------------------------------------
     666                 :             :  */
     667                 :             : Datum
     668                 :           0 : byteaGetBit(PG_FUNCTION_ARGS)
     669                 :             : {
     670                 :           0 :         bytea      *v = PG_GETARG_BYTEA_PP(0);
     671                 :           0 :         int64           n = PG_GETARG_INT64(1);
     672                 :           0 :         int                     byteNo,
     673                 :             :                                 bitNo;
     674                 :           0 :         int                     len;
     675                 :           0 :         int                     byte;
     676                 :             : 
     677                 :           0 :         len = VARSIZE_ANY_EXHDR(v);
     678                 :             : 
     679         [ #  # ]:           0 :         if (n < 0 || n >= (int64) len * 8)
     680   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     681                 :             :                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     682                 :             :                                  errmsg("index %" PRId64 " out of valid range, 0..%" PRId64,
     683                 :             :                                                 n, (int64) len * 8 - 1)));
     684                 :             : 
     685                 :             :         /* n/8 is now known < len, so safe to cast to int */
     686                 :           0 :         byteNo = (int) (n / 8);
     687                 :           0 :         bitNo = (int) (n % 8);
     688                 :             : 
     689                 :           0 :         byte = ((unsigned char *) VARDATA_ANY(v))[byteNo];
     690                 :             : 
     691         [ #  # ]:           0 :         if (byte & (1 << bitNo))
     692                 :           0 :                 PG_RETURN_INT32(1);
     693                 :             :         else
     694                 :           0 :                 PG_RETURN_INT32(0);
     695                 :           0 : }
     696                 :             : 
     697                 :             : /*-------------------------------------------------------------
     698                 :             :  * byteaSetByte
     699                 :             :  *
     700                 :             :  * Given an instance of type 'bytea' creates a new one with
     701                 :             :  * the Nth byte set to the given value.
     702                 :             :  *
     703                 :             :  *-------------------------------------------------------------
     704                 :             :  */
     705                 :             : Datum
     706                 :           0 : byteaSetByte(PG_FUNCTION_ARGS)
     707                 :             : {
     708                 :           0 :         bytea      *res = PG_GETARG_BYTEA_P_COPY(0);
     709                 :           0 :         int32           n = PG_GETARG_INT32(1);
     710                 :           0 :         int32           newByte = PG_GETARG_INT32(2);
     711                 :           0 :         int                     len;
     712                 :             : 
     713                 :           0 :         len = VARSIZE(res) - VARHDRSZ;
     714                 :             : 
     715         [ #  # ]:           0 :         if (n < 0 || n >= len)
     716   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     717                 :             :                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     718                 :             :                                  errmsg("index %d out of valid range, 0..%d",
     719                 :             :                                                 n, len - 1)));
     720                 :             : 
     721                 :             :         /*
     722                 :             :          * Now set the byte.
     723                 :             :          */
     724                 :           0 :         ((unsigned char *) VARDATA(res))[n] = newByte;
     725                 :             : 
     726                 :           0 :         PG_RETURN_BYTEA_P(res);
     727                 :           0 : }
     728                 :             : 
     729                 :             : /*-------------------------------------------------------------
     730                 :             :  * byteaSetBit
     731                 :             :  *
     732                 :             :  * Given an instance of type 'bytea' creates a new one with
     733                 :             :  * the Nth bit set to the given value.
     734                 :             :  *
     735                 :             :  *-------------------------------------------------------------
     736                 :             :  */
     737                 :             : Datum
     738                 :           0 : byteaSetBit(PG_FUNCTION_ARGS)
     739                 :             : {
     740                 :           0 :         bytea      *res = PG_GETARG_BYTEA_P_COPY(0);
     741                 :           0 :         int64           n = PG_GETARG_INT64(1);
     742                 :           0 :         int32           newBit = PG_GETARG_INT32(2);
     743                 :           0 :         int                     len;
     744                 :           0 :         int                     oldByte,
     745                 :             :                                 newByte;
     746                 :           0 :         int                     byteNo,
     747                 :             :                                 bitNo;
     748                 :             : 
     749                 :           0 :         len = VARSIZE(res) - VARHDRSZ;
     750                 :             : 
     751         [ #  # ]:           0 :         if (n < 0 || n >= (int64) len * 8)
     752   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     753                 :             :                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     754                 :             :                                  errmsg("index %" PRId64 " out of valid range, 0..%" PRId64,
     755                 :             :                                                 n, (int64) len * 8 - 1)));
     756                 :             : 
     757                 :             :         /* n/8 is now known < len, so safe to cast to int */
     758                 :           0 :         byteNo = (int) (n / 8);
     759                 :           0 :         bitNo = (int) (n % 8);
     760                 :             : 
     761                 :             :         /*
     762                 :             :          * sanity check!
     763                 :             :          */
     764   [ #  #  #  # ]:           0 :         if (newBit != 0 && newBit != 1)
     765   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     766                 :             :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     767                 :             :                                  errmsg("new bit must be 0 or 1")));
     768                 :             : 
     769                 :             :         /*
     770                 :             :          * Update the byte.
     771                 :             :          */
     772                 :           0 :         oldByte = ((unsigned char *) VARDATA(res))[byteNo];
     773                 :             : 
     774         [ #  # ]:           0 :         if (newBit == 0)
     775                 :           0 :                 newByte = oldByte & (~(1 << bitNo));
     776                 :             :         else
     777                 :           0 :                 newByte = oldByte | (1 << bitNo);
     778                 :             : 
     779                 :           0 :         ((unsigned char *) VARDATA(res))[byteNo] = newByte;
     780                 :             : 
     781                 :           0 :         PG_RETURN_BYTEA_P(res);
     782                 :           0 : }
     783                 :             : 
     784                 :             : /*
     785                 :             :  * Return reversed bytea
     786                 :             :  */
     787                 :             : Datum
     788                 :           0 : bytea_reverse(PG_FUNCTION_ARGS)
     789                 :             : {
     790                 :           0 :         bytea      *v = PG_GETARG_BYTEA_PP(0);
     791                 :           0 :         const char *p = VARDATA_ANY(v);
     792                 :           0 :         int                     len = VARSIZE_ANY_EXHDR(v);
     793                 :           0 :         const char *endp = p + len;
     794                 :           0 :         bytea      *result = palloc(len + VARHDRSZ);
     795                 :           0 :         char       *dst = (char *) VARDATA(result) + len;
     796                 :             : 
     797                 :           0 :         SET_VARSIZE(result, len + VARHDRSZ);
     798                 :             : 
     799         [ #  # ]:           0 :         while (p < endp)
     800                 :           0 :                 *(--dst) = *p++;
     801                 :             : 
     802                 :           0 :         PG_RETURN_BYTEA_P(result);
     803                 :           0 : }
     804                 :             : 
     805                 :             : 
     806                 :             : /*****************************************************************************
     807                 :             :  *      Comparison Functions used for bytea
     808                 :             :  *
     809                 :             :  * Note: btree indexes need these routines not to leak memory; therefore,
     810                 :             :  * be careful to free working copies of toasted datums.  Most places don't
     811                 :             :  * need to be so careful.
     812                 :             :  *****************************************************************************/
     813                 :             : 
     814                 :             : Datum
     815                 :           0 : byteaeq(PG_FUNCTION_ARGS)
     816                 :             : {
     817                 :           0 :         Datum           arg1 = PG_GETARG_DATUM(0);
     818                 :           0 :         Datum           arg2 = PG_GETARG_DATUM(1);
     819                 :           0 :         bool            result;
     820                 :           0 :         Size            len1,
     821                 :             :                                 len2;
     822                 :             : 
     823                 :             :         /*
     824                 :             :          * We can use a fast path for unequal lengths, which might save us from
     825                 :             :          * having to detoast one or both values.
     826                 :             :          */
     827                 :           0 :         len1 = toast_raw_datum_size(arg1);
     828                 :           0 :         len2 = toast_raw_datum_size(arg2);
     829         [ #  # ]:           0 :         if (len1 != len2)
     830                 :           0 :                 result = false;
     831                 :             :         else
     832                 :             :         {
     833                 :           0 :                 bytea      *barg1 = DatumGetByteaPP(arg1);
     834                 :           0 :                 bytea      *barg2 = DatumGetByteaPP(arg2);
     835                 :             : 
     836                 :           0 :                 result = (memcmp(VARDATA_ANY(barg1), VARDATA_ANY(barg2),
     837                 :           0 :                                                  len1 - VARHDRSZ) == 0);
     838                 :             : 
     839         [ #  # ]:           0 :                 PG_FREE_IF_COPY(barg1, 0);
     840         [ #  # ]:           0 :                 PG_FREE_IF_COPY(barg2, 1);
     841                 :           0 :         }
     842                 :             : 
     843                 :           0 :         PG_RETURN_BOOL(result);
     844                 :           0 : }
     845                 :             : 
     846                 :             : Datum
     847                 :           0 : byteane(PG_FUNCTION_ARGS)
     848                 :             : {
     849                 :           0 :         Datum           arg1 = PG_GETARG_DATUM(0);
     850                 :           0 :         Datum           arg2 = PG_GETARG_DATUM(1);
     851                 :           0 :         bool            result;
     852                 :           0 :         Size            len1,
     853                 :             :                                 len2;
     854                 :             : 
     855                 :             :         /*
     856                 :             :          * We can use a fast path for unequal lengths, which might save us from
     857                 :             :          * having to detoast one or both values.
     858                 :             :          */
     859                 :           0 :         len1 = toast_raw_datum_size(arg1);
     860                 :           0 :         len2 = toast_raw_datum_size(arg2);
     861         [ #  # ]:           0 :         if (len1 != len2)
     862                 :           0 :                 result = true;
     863                 :             :         else
     864                 :             :         {
     865                 :           0 :                 bytea      *barg1 = DatumGetByteaPP(arg1);
     866                 :           0 :                 bytea      *barg2 = DatumGetByteaPP(arg2);
     867                 :             : 
     868                 :           0 :                 result = (memcmp(VARDATA_ANY(barg1), VARDATA_ANY(barg2),
     869                 :           0 :                                                  len1 - VARHDRSZ) != 0);
     870                 :             : 
     871         [ #  # ]:           0 :                 PG_FREE_IF_COPY(barg1, 0);
     872         [ #  # ]:           0 :                 PG_FREE_IF_COPY(barg2, 1);
     873                 :           0 :         }
     874                 :             : 
     875                 :           0 :         PG_RETURN_BOOL(result);
     876                 :           0 : }
     877                 :             : 
     878                 :             : Datum
     879                 :           0 : bytealt(PG_FUNCTION_ARGS)
     880                 :             : {
     881                 :           0 :         bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
     882                 :           0 :         bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
     883                 :           0 :         int                     len1,
     884                 :             :                                 len2;
     885                 :           0 :         int                     cmp;
     886                 :             : 
     887                 :           0 :         len1 = VARSIZE_ANY_EXHDR(arg1);
     888                 :           0 :         len2 = VARSIZE_ANY_EXHDR(arg2);
     889                 :             : 
     890         [ #  # ]:           0 :         cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
     891                 :             : 
     892         [ #  # ]:           0 :         PG_FREE_IF_COPY(arg1, 0);
     893         [ #  # ]:           0 :         PG_FREE_IF_COPY(arg2, 1);
     894                 :             : 
     895   [ #  #  #  # ]:           0 :         PG_RETURN_BOOL((cmp < 0) || ((cmp == 0) && (len1 < len2)));
     896                 :           0 : }
     897                 :             : 
     898                 :             : Datum
     899                 :           0 : byteale(PG_FUNCTION_ARGS)
     900                 :             : {
     901                 :           0 :         bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
     902                 :           0 :         bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
     903                 :           0 :         int                     len1,
     904                 :             :                                 len2;
     905                 :           0 :         int                     cmp;
     906                 :             : 
     907                 :           0 :         len1 = VARSIZE_ANY_EXHDR(arg1);
     908                 :           0 :         len2 = VARSIZE_ANY_EXHDR(arg2);
     909                 :             : 
     910         [ #  # ]:           0 :         cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
     911                 :             : 
     912         [ #  # ]:           0 :         PG_FREE_IF_COPY(arg1, 0);
     913         [ #  # ]:           0 :         PG_FREE_IF_COPY(arg2, 1);
     914                 :             : 
     915   [ #  #  #  # ]:           0 :         PG_RETURN_BOOL((cmp < 0) || ((cmp == 0) && (len1 <= len2)));
     916                 :           0 : }
     917                 :             : 
     918                 :             : Datum
     919                 :           0 : byteagt(PG_FUNCTION_ARGS)
     920                 :             : {
     921                 :           0 :         bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
     922                 :           0 :         bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
     923                 :           0 :         int                     len1,
     924                 :             :                                 len2;
     925                 :           0 :         int                     cmp;
     926                 :             : 
     927                 :           0 :         len1 = VARSIZE_ANY_EXHDR(arg1);
     928                 :           0 :         len2 = VARSIZE_ANY_EXHDR(arg2);
     929                 :             : 
     930         [ #  # ]:           0 :         cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
     931                 :             : 
     932         [ #  # ]:           0 :         PG_FREE_IF_COPY(arg1, 0);
     933         [ #  # ]:           0 :         PG_FREE_IF_COPY(arg2, 1);
     934                 :             : 
     935   [ #  #  #  # ]:           0 :         PG_RETURN_BOOL((cmp > 0) || ((cmp == 0) && (len1 > len2)));
     936                 :           0 : }
     937                 :             : 
     938                 :             : Datum
     939                 :           0 : byteage(PG_FUNCTION_ARGS)
     940                 :             : {
     941                 :           0 :         bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
     942                 :           0 :         bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
     943                 :           0 :         int                     len1,
     944                 :             :                                 len2;
     945                 :           0 :         int                     cmp;
     946                 :             : 
     947                 :           0 :         len1 = VARSIZE_ANY_EXHDR(arg1);
     948                 :           0 :         len2 = VARSIZE_ANY_EXHDR(arg2);
     949                 :             : 
     950         [ #  # ]:           0 :         cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
     951                 :             : 
     952         [ #  # ]:           0 :         PG_FREE_IF_COPY(arg1, 0);
     953         [ #  # ]:           0 :         PG_FREE_IF_COPY(arg2, 1);
     954                 :             : 
     955   [ #  #  #  # ]:           0 :         PG_RETURN_BOOL((cmp > 0) || ((cmp == 0) && (len1 >= len2)));
     956                 :           0 : }
     957                 :             : 
     958                 :             : Datum
     959                 :           0 : byteacmp(PG_FUNCTION_ARGS)
     960                 :             : {
     961                 :           0 :         bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
     962                 :           0 :         bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
     963                 :           0 :         int                     len1,
     964                 :             :                                 len2;
     965                 :           0 :         int                     cmp;
     966                 :             : 
     967                 :           0 :         len1 = VARSIZE_ANY_EXHDR(arg1);
     968                 :           0 :         len2 = VARSIZE_ANY_EXHDR(arg2);
     969                 :             : 
     970         [ #  # ]:           0 :         cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
     971   [ #  #  #  # ]:           0 :         if ((cmp == 0) && (len1 != len2))
     972                 :           0 :                 cmp = (len1 < len2) ? -1 : 1;
     973                 :             : 
     974         [ #  # ]:           0 :         PG_FREE_IF_COPY(arg1, 0);
     975         [ #  # ]:           0 :         PG_FREE_IF_COPY(arg2, 1);
     976                 :             : 
     977                 :           0 :         PG_RETURN_INT32(cmp);
     978                 :           0 : }
     979                 :             : 
     980                 :             : Datum
     981                 :           0 : bytea_larger(PG_FUNCTION_ARGS)
     982                 :             : {
     983                 :           0 :         bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
     984                 :           0 :         bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
     985                 :           0 :         bytea      *result;
     986                 :           0 :         int                     len1,
     987                 :             :                                 len2;
     988                 :           0 :         int                     cmp;
     989                 :             : 
     990                 :           0 :         len1 = VARSIZE_ANY_EXHDR(arg1);
     991                 :           0 :         len2 = VARSIZE_ANY_EXHDR(arg2);
     992                 :             : 
     993         [ #  # ]:           0 :         cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
     994   [ #  #  #  #  :           0 :         result = ((cmp > 0) || ((cmp == 0) && (len1 > len2)) ? arg1 : arg2);
                   #  # ]
     995                 :             : 
     996                 :           0 :         PG_RETURN_BYTEA_P(result);
     997                 :           0 : }
     998                 :             : 
     999                 :             : Datum
    1000                 :           0 : bytea_smaller(PG_FUNCTION_ARGS)
    1001                 :             : {
    1002                 :           0 :         bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
    1003                 :           0 :         bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
    1004                 :           0 :         bytea      *result;
    1005                 :           0 :         int                     len1,
    1006                 :             :                                 len2;
    1007                 :           0 :         int                     cmp;
    1008                 :             : 
    1009                 :           0 :         len1 = VARSIZE_ANY_EXHDR(arg1);
    1010                 :           0 :         len2 = VARSIZE_ANY_EXHDR(arg2);
    1011                 :             : 
    1012         [ #  # ]:           0 :         cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
    1013   [ #  #  #  #  :           0 :         result = ((cmp < 0) || ((cmp == 0) && (len1 < len2)) ? arg1 : arg2);
                   #  # ]
    1014                 :             : 
    1015                 :           0 :         PG_RETURN_BYTEA_P(result);
    1016                 :           0 : }
    1017                 :             : 
    1018                 :             : /*
    1019                 :             :  * sortsupport comparison func
    1020                 :             :  */
    1021                 :             : static int
    1022                 :           0 : byteafastcmp(Datum x, Datum y, SortSupport ssup)
    1023                 :             : {
    1024                 :           0 :         bytea      *arg1 = DatumGetByteaPP(x);
    1025                 :           0 :         bytea      *arg2 = DatumGetByteaPP(y);
    1026                 :           0 :         char       *a1p,
    1027                 :             :                            *a2p;
    1028                 :           0 :         int                     len1,
    1029                 :             :                                 len2,
    1030                 :             :                                 result;
    1031                 :             : 
    1032                 :           0 :         a1p = VARDATA_ANY(arg1);
    1033                 :           0 :         a2p = VARDATA_ANY(arg2);
    1034                 :             : 
    1035                 :           0 :         len1 = VARSIZE_ANY_EXHDR(arg1);
    1036                 :           0 :         len2 = VARSIZE_ANY_EXHDR(arg2);
    1037                 :             : 
    1038         [ #  # ]:           0 :         result = memcmp(a1p, a2p, Min(len1, len2));
    1039   [ #  #  #  # ]:           0 :         if ((result == 0) && (len1 != len2))
    1040                 :           0 :                 result = (len1 < len2) ? -1 : 1;
    1041                 :             : 
    1042                 :             :         /* We can't afford to leak memory here. */
    1043         [ #  # ]:           0 :         if (PointerGetDatum(arg1) != x)
    1044                 :           0 :                 pfree(arg1);
    1045         [ #  # ]:           0 :         if (PointerGetDatum(arg2) != y)
    1046                 :           0 :                 pfree(arg2);
    1047                 :             : 
    1048                 :           0 :         return result;
    1049                 :           0 : }
    1050                 :             : 
    1051                 :             : /*
    1052                 :             :  * Conversion routine for sortsupport.  Converts original to abbreviated key
    1053                 :             :  * representation.  Our encoding strategy is simple -- pack the first 8 bytes
    1054                 :             :  * of the bytea data into a Datum (on little-endian machines, the bytes are
    1055                 :             :  * stored in reverse order), and treat it as an unsigned integer.
    1056                 :             :  */
    1057                 :             : static Datum
    1058                 :           0 : bytea_abbrev_convert(Datum original, SortSupport ssup)
    1059                 :             : {
    1060                 :           0 :         const size_t max_prefix_bytes = sizeof(Datum);
    1061                 :           0 :         ByteaSortSupport *bss = (ByteaSortSupport *) ssup->ssup_extra;
    1062                 :           0 :         bytea      *authoritative = DatumGetByteaPP(original);
    1063                 :           0 :         char       *authoritative_data = VARDATA_ANY(authoritative);
    1064                 :           0 :         Datum           res;
    1065                 :           0 :         char       *pres;
    1066                 :           0 :         int                     len;
    1067                 :           0 :         uint32          hash;
    1068                 :             : 
    1069                 :           0 :         pres = (char *) &res;
    1070                 :             : 
    1071                 :             :         /* memset(), so any non-overwritten bytes are NUL */
    1072                 :           0 :         memset(pres, 0, max_prefix_bytes);
    1073                 :           0 :         len = VARSIZE_ANY_EXHDR(authoritative);
    1074                 :             : 
    1075                 :             :         /*
    1076                 :             :          * Short byteas will have terminating NUL bytes in the abbreviated datum.
    1077                 :             :          * Abbreviated comparison need not make a distinction between these NUL
    1078                 :             :          * bytes, and NUL bytes representing actual NULs in the authoritative
    1079                 :             :          * representation.
    1080                 :             :          *
    1081                 :             :          * Hopefully a comparison at or past one abbreviated key's terminating NUL
    1082                 :             :          * byte will resolve the comparison without consulting the authoritative
    1083                 :             :          * representation; specifically, some later non-NUL byte in the longer
    1084                 :             :          * bytea can resolve the comparison against a subsequent terminating NUL
    1085                 :             :          * in the shorter bytea.  There will usually be what is effectively a
    1086                 :             :          * "length-wise" resolution there and then.
    1087                 :             :          *
    1088                 :             :          * If that doesn't work out -- if all bytes in the longer bytea positioned
    1089                 :             :          * at or past the offset of the smaller bytea (first) terminating NUL are
    1090                 :             :          * actually representative of NUL bytes in the authoritative binary bytea
    1091                 :             :          * (perhaps with some *terminating* NUL bytes towards the end of the
    1092                 :             :          * longer bytea iff it happens to still be small) -- then an authoritative
    1093                 :             :          * tie-breaker will happen, and do the right thing: explicitly consider
    1094                 :             :          * bytea length.
    1095                 :             :          */
    1096         [ #  # ]:           0 :         memcpy(pres, authoritative_data, Min(len, max_prefix_bytes));
    1097                 :             : 
    1098                 :             :         /*
    1099                 :             :          * Maintain approximate cardinality of both abbreviated keys and original,
    1100                 :             :          * authoritative keys using HyperLogLog.  Used as cheap insurance against
    1101                 :             :          * the worst case, where we do many string abbreviations for no saving in
    1102                 :             :          * full memcmp()-based comparisons.  These statistics are used by
    1103                 :             :          * bytea_abbrev_abort().
    1104                 :             :          *
    1105                 :             :          * First, Hash key proper, or a significant fraction of it.  Mix in length
    1106                 :             :          * in order to compensate for cases where differences are past
    1107                 :             :          * PG_CACHE_LINE_SIZE bytes, so as to limit the overhead of hashing.
    1108                 :             :          */
    1109                 :           0 :         hash = DatumGetUInt32(hash_any((unsigned char *) authoritative_data,
    1110         [ #  # ]:           0 :                                                                    Min(len, PG_CACHE_LINE_SIZE)));
    1111                 :             : 
    1112         [ #  # ]:           0 :         if (len > PG_CACHE_LINE_SIZE)
    1113                 :           0 :                 hash ^= DatumGetUInt32(hash_uint32((uint32) len));
    1114                 :             : 
    1115                 :           0 :         addHyperLogLog(&bss->full_card, hash);
    1116                 :             : 
    1117                 :             :         /* Hash abbreviated key */
    1118                 :             :         {
    1119                 :           0 :                 uint32          tmp;
    1120                 :             : 
    1121                 :           0 :                 tmp = DatumGetUInt32(res) ^ (uint32) (DatumGetUInt64(res) >> 32);
    1122                 :           0 :                 hash = DatumGetUInt32(hash_uint32(tmp));
    1123                 :           0 :         }
    1124                 :             : 
    1125                 :           0 :         addHyperLogLog(&bss->abbr_card, hash);
    1126                 :             : 
    1127                 :             :         /*
    1128                 :             :          * Byteswap on little-endian machines.
    1129                 :             :          *
    1130                 :             :          * This is needed so that ssup_datum_unsigned_cmp() works correctly on all
    1131                 :             :          * platforms.
    1132                 :             :          */
    1133                 :           0 :         res = DatumBigEndianToNative(res);
    1134                 :             : 
    1135                 :             :         /* Don't leak memory here */
    1136         [ #  # ]:           0 :         if (PointerGetDatum(authoritative) != original)
    1137                 :           0 :                 pfree(authoritative);
    1138                 :             : 
    1139                 :           0 :         return res;
    1140                 :           0 : }
    1141                 :             : 
    1142                 :             : /*
    1143                 :             :  * Callback for estimating effectiveness of abbreviated key optimization, using
    1144                 :             :  * heuristic rules.  Returns value indicating if the abbreviation optimization
    1145                 :             :  * should be aborted, based on its projected effectiveness.
    1146                 :             :  *
    1147                 :             :  * This is based on varstr_abbrev_abort(), but some comments have been elided
    1148                 :             :  * for brevity. See there for more details.
    1149                 :             :  */
    1150                 :             : static bool
    1151                 :           0 : bytea_abbrev_abort(int memtupcount, SortSupport ssup)
    1152                 :             : {
    1153                 :           0 :         ByteaSortSupport *bss = (ByteaSortSupport *) ssup->ssup_extra;
    1154                 :           0 :         double          abbrev_distinct,
    1155                 :             :                                 key_distinct;
    1156                 :             : 
    1157         [ #  # ]:           0 :         Assert(ssup->abbreviate);
    1158                 :             : 
    1159                 :             :         /* Have a little patience */
    1160         [ #  # ]:           0 :         if (memtupcount < 100)
    1161                 :           0 :                 return false;
    1162                 :             : 
    1163                 :           0 :         abbrev_distinct = estimateHyperLogLog(&bss->abbr_card);
    1164                 :           0 :         key_distinct = estimateHyperLogLog(&bss->full_card);
    1165                 :             : 
    1166                 :             :         /*
    1167                 :             :          * Clamp cardinality estimates to at least one distinct value.  While
    1168                 :             :          * NULLs are generally disregarded, if only NULL values were seen so far,
    1169                 :             :          * that might misrepresent costs if we failed to clamp.
    1170                 :             :          */
    1171         [ #  # ]:           0 :         if (abbrev_distinct < 1.0)
    1172                 :           0 :                 abbrev_distinct = 1.0;
    1173                 :             : 
    1174         [ #  # ]:           0 :         if (key_distinct < 1.0)
    1175                 :           0 :                 key_distinct = 1.0;
    1176                 :             : 
    1177         [ #  # ]:           0 :         if (trace_sort)
    1178                 :             :         {
    1179                 :           0 :                 double          norm_abbrev_card = abbrev_distinct / (double) memtupcount;
    1180                 :             : 
    1181   [ #  #  #  # ]:           0 :                 elog(LOG, "bytea_abbrev: abbrev_distinct after %d: %f "
    1182                 :             :                          "(key_distinct: %f, norm_abbrev_card: %f, prop_card: %f)",
    1183                 :             :                          memtupcount, abbrev_distinct, key_distinct, norm_abbrev_card,
    1184                 :             :                          bss->prop_card);
    1185                 :           0 :         }
    1186                 :             : 
    1187                 :             :         /*
    1188                 :             :          * If the number of distinct abbreviated keys approximately matches the
    1189                 :             :          * number of distinct original keys, continue with abbreviation.
    1190                 :             :          */
    1191         [ #  # ]:           0 :         if (abbrev_distinct > key_distinct * bss->prop_card)
    1192                 :             :         {
    1193                 :             :                 /*
    1194                 :             :                  * Decay required cardinality aggressively after 10,000 tuples.
    1195                 :             :                  */
    1196         [ #  # ]:           0 :                 if (memtupcount > 10000)
    1197                 :           0 :                         bss->prop_card *= 0.65;
    1198                 :             : 
    1199                 :           0 :                 return false;
    1200                 :             :         }
    1201                 :             : 
    1202                 :             :         /*
    1203                 :             :          * Abort abbreviation strategy.
    1204                 :             :          */
    1205         [ #  # ]:           0 :         if (trace_sort)
    1206   [ #  #  #  # ]:           0 :                 elog(LOG, "bytea_abbrev: aborted abbreviation at %d "
    1207                 :             :                          "(abbrev_distinct: %f, key_distinct: %f, prop_card: %f)",
    1208                 :             :                          memtupcount, abbrev_distinct, key_distinct, bss->prop_card);
    1209                 :             : 
    1210                 :           0 :         return true;
    1211                 :           0 : }
    1212                 :             : 
    1213                 :             : Datum
    1214                 :           0 : bytea_sortsupport(PG_FUNCTION_ARGS)
    1215                 :             : {
    1216                 :           0 :         SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
    1217                 :           0 :         MemoryContext oldcontext;
    1218                 :             : 
    1219                 :           0 :         oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
    1220                 :             : 
    1221                 :           0 :         ssup->comparator = byteafastcmp;
    1222                 :             : 
    1223                 :             :         /*
    1224                 :             :          * Set up abbreviation support if requested.
    1225                 :             :          */
    1226         [ #  # ]:           0 :         if (ssup->abbreviate)
    1227                 :             :         {
    1228                 :           0 :                 ByteaSortSupport *bss;
    1229                 :             : 
    1230                 :           0 :                 bss = palloc_object(ByteaSortSupport);
    1231                 :           0 :                 bss->abbreviate = true;
    1232                 :           0 :                 bss->prop_card = 0.20;
    1233                 :           0 :                 initHyperLogLog(&bss->abbr_card, 10);
    1234                 :           0 :                 initHyperLogLog(&bss->full_card, 10);
    1235                 :             : 
    1236                 :           0 :                 ssup->ssup_extra = bss;
    1237                 :           0 :                 ssup->abbrev_full_comparator = ssup->comparator;
    1238                 :           0 :                 ssup->comparator = ssup_datum_unsigned_cmp;
    1239                 :           0 :                 ssup->abbrev_converter = bytea_abbrev_convert;
    1240                 :           0 :                 ssup->abbrev_abort = bytea_abbrev_abort;
    1241                 :           0 :         }
    1242                 :             : 
    1243                 :           0 :         MemoryContextSwitchTo(oldcontext);
    1244                 :             : 
    1245                 :           0 :         PG_RETURN_VOID();
    1246                 :           0 : }
    1247                 :             : 
    1248                 :             : /* Cast bytea -> int2 */
    1249                 :             : Datum
    1250                 :           0 : bytea_int2(PG_FUNCTION_ARGS)
    1251                 :             : {
    1252                 :           0 :         bytea      *v = PG_GETARG_BYTEA_PP(0);
    1253                 :           0 :         int                     len = VARSIZE_ANY_EXHDR(v);
    1254                 :           0 :         uint16          result;
    1255                 :             : 
    1256                 :             :         /* Check that the byte array is not too long */
    1257         [ #  # ]:           0 :         if (len > sizeof(result))
    1258   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1259                 :             :                                 errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1260                 :             :                                 errmsg("smallint out of range"));
    1261                 :             : 
    1262                 :             :         /* Convert it to an integer; most significant bytes come first */
    1263                 :           0 :         result = 0;
    1264         [ #  # ]:           0 :         for (int i = 0; i < len; i++)
    1265                 :             :         {
    1266                 :           0 :                 result <<= BITS_PER_BYTE;
    1267                 :           0 :                 result |= ((unsigned char *) VARDATA_ANY(v))[i];
    1268                 :           0 :         }
    1269                 :             : 
    1270                 :           0 :         PG_RETURN_INT16(result);
    1271                 :           0 : }
    1272                 :             : 
    1273                 :             : /* Cast bytea -> int4 */
    1274                 :             : Datum
    1275                 :           0 : bytea_int4(PG_FUNCTION_ARGS)
    1276                 :             : {
    1277                 :           0 :         bytea      *v = PG_GETARG_BYTEA_PP(0);
    1278                 :           0 :         int                     len = VARSIZE_ANY_EXHDR(v);
    1279                 :           0 :         uint32          result;
    1280                 :             : 
    1281                 :             :         /* Check that the byte array is not too long */
    1282         [ #  # ]:           0 :         if (len > sizeof(result))
    1283   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1284                 :             :                                 errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1285                 :             :                                 errmsg("integer out of range"));
    1286                 :             : 
    1287                 :             :         /* Convert it to an integer; most significant bytes come first */
    1288                 :           0 :         result = 0;
    1289         [ #  # ]:           0 :         for (int i = 0; i < len; i++)
    1290                 :             :         {
    1291                 :           0 :                 result <<= BITS_PER_BYTE;
    1292                 :           0 :                 result |= ((unsigned char *) VARDATA_ANY(v))[i];
    1293                 :           0 :         }
    1294                 :             : 
    1295                 :           0 :         PG_RETURN_INT32(result);
    1296                 :           0 : }
    1297                 :             : 
    1298                 :             : /* Cast bytea -> int8 */
    1299                 :             : Datum
    1300                 :           0 : bytea_int8(PG_FUNCTION_ARGS)
    1301                 :             : {
    1302                 :           0 :         bytea      *v = PG_GETARG_BYTEA_PP(0);
    1303                 :           0 :         int                     len = VARSIZE_ANY_EXHDR(v);
    1304                 :           0 :         uint64          result;
    1305                 :             : 
    1306                 :             :         /* Check that the byte array is not too long */
    1307         [ #  # ]:           0 :         if (len > sizeof(result))
    1308   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1309                 :             :                                 errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1310                 :             :                                 errmsg("bigint out of range"));
    1311                 :             : 
    1312                 :             :         /* Convert it to an integer; most significant bytes come first */
    1313                 :           0 :         result = 0;
    1314         [ #  # ]:           0 :         for (int i = 0; i < len; i++)
    1315                 :             :         {
    1316                 :           0 :                 result <<= BITS_PER_BYTE;
    1317                 :           0 :                 result |= ((unsigned char *) VARDATA_ANY(v))[i];
    1318                 :           0 :         }
    1319                 :             : 
    1320                 :           0 :         PG_RETURN_INT64(result);
    1321                 :           0 : }
    1322                 :             : 
    1323                 :             : /* Cast int2 -> bytea; can just use int2send() */
    1324                 :             : Datum
    1325                 :           0 : int2_bytea(PG_FUNCTION_ARGS)
    1326                 :             : {
    1327                 :           0 :         return int2send(fcinfo);
    1328                 :             : }
    1329                 :             : 
    1330                 :             : /* Cast int4 -> bytea; can just use int4send() */
    1331                 :             : Datum
    1332                 :           0 : int4_bytea(PG_FUNCTION_ARGS)
    1333                 :             : {
    1334                 :           0 :         return int4send(fcinfo);
    1335                 :             : }
    1336                 :             : 
    1337                 :             : /* Cast int8 -> bytea; can just use int8send() */
    1338                 :             : Datum
    1339                 :           0 : int8_bytea(PG_FUNCTION_ARGS)
    1340                 :             : {
    1341                 :           0 :         return int8send(fcinfo);
    1342                 :             : }
        

Generated by: LCOV version 2.3.2-1