LCOV - code coverage report
Current view: top level - src/backend/utils/adt - bytea.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 374 395 94.7 %
Date: 2025-07-08 17:18:06 Functions: 38 38 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * bytea.c
       4             :  *    Functions for the bytea type.
       5             :  *
       6             :  * Portions Copyright (c) 2025, 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 "catalog/pg_collation_d.h"
      19             : #include "catalog/pg_type_d.h"
      20             : #include "common/int.h"
      21             : #include "fmgr.h"
      22             : #include "libpq/pqformat.h"
      23             : #include "port/pg_bitutils.h"
      24             : #include "utils/builtins.h"
      25             : #include "utils/bytea.h"
      26             : #include "utils/fmgrprotos.h"
      27             : #include "utils/memutils.h"
      28             : #include "utils/sortsupport.h"
      29             : #include "utils/varlena.h"
      30             : #include "varatt.h"
      31             : 
      32             : /* GUC variable */
      33             : int         bytea_output = BYTEA_OUTPUT_HEX;
      34             : 
      35             : static bytea *bytea_catenate(bytea *t1, bytea *t2);
      36             : static bytea *bytea_substring(Datum str, int S, int L,
      37             :                               bool length_not_specified);
      38             : static bytea *bytea_overlay(bytea *t1, bytea *t2, int sp, int sl);
      39             : 
      40             : /*
      41             :  * bytea_catenate
      42             :  *  Guts of byteacat(), broken out so it can be used by other functions
      43             :  *
      44             :  * Arguments can be in short-header form, but not compressed or out-of-line
      45             :  */
      46             : static bytea *
      47        1558 : bytea_catenate(bytea *t1, bytea *t2)
      48             : {
      49             :     bytea      *result;
      50             :     int         len1,
      51             :                 len2,
      52             :                 len;
      53             :     char       *ptr;
      54             : 
      55        1558 :     len1 = VARSIZE_ANY_EXHDR(t1);
      56        1558 :     len2 = VARSIZE_ANY_EXHDR(t2);
      57             : 
      58             :     /* paranoia ... probably should throw error instead? */
      59        1558 :     if (len1 < 0)
      60           0 :         len1 = 0;
      61        1558 :     if (len2 < 0)
      62           0 :         len2 = 0;
      63             : 
      64        1558 :     len = len1 + len2 + VARHDRSZ;
      65        1558 :     result = (bytea *) palloc(len);
      66             : 
      67             :     /* Set size of result string... */
      68        1558 :     SET_VARSIZE(result, len);
      69             : 
      70             :     /* Fill data field of result string... */
      71        1558 :     ptr = VARDATA(result);
      72        1558 :     if (len1 > 0)
      73        1558 :         memcpy(ptr, VARDATA_ANY(t1), len1);
      74        1558 :     if (len2 > 0)
      75        1540 :         memcpy(ptr + len1, VARDATA_ANY(t2), len2);
      76             : 
      77        1558 :     return result;
      78             : }
      79             : 
      80             : #define PG_STR_GET_BYTEA(str_) \
      81             :     DatumGetByteaPP(DirectFunctionCall1(byteain, CStringGetDatum(str_)))
      82             : 
      83             : static bytea *
      84        4058 : bytea_substring(Datum str,
      85             :                 int S,
      86             :                 int L,
      87             :                 bool length_not_specified)
      88             : {
      89             :     int32       S1;             /* adjusted start position */
      90             :     int32       L1;             /* adjusted substring length */
      91             :     int32       E;              /* end position */
      92             : 
      93             :     /*
      94             :      * The logic here should generally match text_substring().
      95             :      */
      96        4058 :     S1 = Max(S, 1);
      97             : 
      98        4058 :     if (length_not_specified)
      99             :     {
     100             :         /*
     101             :          * Not passed a length - DatumGetByteaPSlice() grabs everything to the
     102             :          * end of the string if we pass it a negative value for length.
     103             :          */
     104        3954 :         L1 = -1;
     105             :     }
     106         104 :     else if (L < 0)
     107             :     {
     108             :         /* SQL99 says to throw an error for E < S, i.e., negative length */
     109          12 :         ereport(ERROR,
     110             :                 (errcode(ERRCODE_SUBSTRING_ERROR),
     111             :                  errmsg("negative substring length not allowed")));
     112             :         L1 = -1;                /* silence stupider compilers */
     113             :     }
     114          92 :     else if (pg_add_s32_overflow(S, L, &E))
     115             :     {
     116             :         /*
     117             :          * L could be large enough for S + L to overflow, in which case the
     118             :          * substring must run to end of string.
     119             :          */
     120           6 :         L1 = -1;
     121             :     }
     122             :     else
     123             :     {
     124             :         /*
     125             :          * A zero or negative value for the end position can happen if the
     126             :          * start was negative or one. SQL99 says to return a zero-length
     127             :          * string.
     128             :          */
     129          86 :         if (E < 1)
     130           0 :             return PG_STR_GET_BYTEA("");
     131             : 
     132          86 :         L1 = E - S1;
     133             :     }
     134             : 
     135             :     /*
     136             :      * If the start position is past the end of the string, SQL99 says to
     137             :      * return a zero-length string -- DatumGetByteaPSlice() will do that for
     138             :      * us.  We need only convert S1 to zero-based starting position.
     139             :      */
     140        4046 :     return DatumGetByteaPSlice(str, S1 - 1, L1);
     141             : }
     142             : 
     143             : static bytea *
     144          18 : bytea_overlay(bytea *t1, bytea *t2, int sp, int sl)
     145             : {
     146             :     bytea      *result;
     147             :     bytea      *s1;
     148             :     bytea      *s2;
     149             :     int         sp_pl_sl;
     150             : 
     151             :     /*
     152             :      * Check for possible integer-overflow cases.  For negative sp, throw a
     153             :      * "substring length" error because that's what should be expected
     154             :      * according to the spec's definition of OVERLAY().
     155             :      */
     156          18 :     if (sp <= 0)
     157           0 :         ereport(ERROR,
     158             :                 (errcode(ERRCODE_SUBSTRING_ERROR),
     159             :                  errmsg("negative substring length not allowed")));
     160          18 :     if (pg_add_s32_overflow(sp, sl, &sp_pl_sl))
     161           0 :         ereport(ERROR,
     162             :                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     163             :                  errmsg("integer out of range")));
     164             : 
     165          18 :     s1 = bytea_substring(PointerGetDatum(t1), 1, sp - 1, false);
     166          18 :     s2 = bytea_substring(PointerGetDatum(t1), sp_pl_sl, -1, true);
     167          18 :     result = bytea_catenate(s1, t2);
     168          18 :     result = bytea_catenate(result, s2);
     169             : 
     170          18 :     return result;
     171             : }
     172             : 
     173             : /*****************************************************************************
     174             :  *   USER I/O ROUTINES                                                       *
     175             :  *****************************************************************************/
     176             : 
     177             : #define VAL(CH)         ((CH) - '0')
     178             : #define DIG(VAL)        ((VAL) + '0')
     179             : 
     180             : /*
     181             :  *      byteain         - converts from printable representation of byte array
     182             :  *
     183             :  *      Non-printable characters must be passed as '\nnn' (octal) and are
     184             :  *      converted to internal form.  '\' must be passed as '\\'.
     185             :  *      ereport(ERROR, ...) if bad form.
     186             :  *
     187             :  *      BUGS:
     188             :  *              The input is scanned twice.
     189             :  *              The error checking of input is minimal.
     190             :  */
     191             : Datum
     192     1387516 : byteain(PG_FUNCTION_ARGS)
     193             : {
     194     1387516 :     char       *inputText = PG_GETARG_CSTRING(0);
     195     1387516 :     Node       *escontext = fcinfo->context;
     196             :     char       *tp;
     197             :     char       *rp;
     198             :     int         bc;
     199             :     bytea      *result;
     200             : 
     201             :     /* Recognize hex input */
     202     1387516 :     if (inputText[0] == '\\' && inputText[1] == 'x')
     203             :     {
     204      112244 :         size_t      len = strlen(inputText);
     205             : 
     206      112244 :         bc = (len - 2) / 2 + VARHDRSZ;  /* maximum possible length */
     207      112244 :         result = palloc(bc);
     208      112244 :         bc = hex_decode_safe(inputText + 2, len - 2, VARDATA(result),
     209             :                              escontext);
     210      112232 :         SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */
     211             : 
     212      112232 :         PG_RETURN_BYTEA_P(result);
     213             :     }
     214             : 
     215             :     /* Else, it's the traditional escaped style */
     216     9569732 :     for (bc = 0, tp = inputText; *tp != '\0'; bc++)
     217             :     {
     218     8294472 :         if (tp[0] != '\\')
     219     8293540 :             tp++;
     220         932 :         else if ((tp[0] == '\\') &&
     221         932 :                  (tp[1] >= '0' && tp[1] <= '3') &&
     222         920 :                  (tp[2] >= '0' && tp[2] <= '7') &&
     223         920 :                  (tp[3] >= '0' && tp[3] <= '7'))
     224         920 :             tp += 4;
     225          12 :         else if ((tp[0] == '\\') &&
     226          12 :                  (tp[1] == '\\'))
     227           0 :             tp += 2;
     228             :         else
     229             :         {
     230             :             /*
     231             :              * one backslash, not followed by another or ### valid octal
     232             :              */
     233          12 :             ereturn(escontext, (Datum) 0,
     234             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     235             :                      errmsg("invalid input syntax for type %s", "bytea")));
     236             :         }
     237             :     }
     238             : 
     239     1275260 :     bc += VARHDRSZ;
     240             : 
     241     1275260 :     result = (bytea *) palloc(bc);
     242     1275260 :     SET_VARSIZE(result, bc);
     243             : 
     244     1275260 :     tp = inputText;
     245     1275260 :     rp = VARDATA(result);
     246     9569690 :     while (*tp != '\0')
     247             :     {
     248     8294430 :         if (tp[0] != '\\')
     249     8293510 :             *rp++ = *tp++;
     250         920 :         else if ((tp[0] == '\\') &&
     251         920 :                  (tp[1] >= '0' && tp[1] <= '3') &&
     252         920 :                  (tp[2] >= '0' && tp[2] <= '7') &&
     253         920 :                  (tp[3] >= '0' && tp[3] <= '7'))
     254             :         {
     255         920 :             bc = VAL(tp[1]);
     256         920 :             bc <<= 3;
     257         920 :             bc += VAL(tp[2]);
     258         920 :             bc <<= 3;
     259         920 :             *rp++ = bc + VAL(tp[3]);
     260             : 
     261         920 :             tp += 4;
     262             :         }
     263           0 :         else if ((tp[0] == '\\') &&
     264           0 :                  (tp[1] == '\\'))
     265             :         {
     266           0 :             *rp++ = '\\';
     267           0 :             tp += 2;
     268             :         }
     269             :         else
     270             :         {
     271             :             /*
     272             :              * We should never get here. The first pass should not allow it.
     273             :              */
     274           0 :             ereturn(escontext, (Datum) 0,
     275             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     276             :                      errmsg("invalid input syntax for type %s", "bytea")));
     277             :         }
     278             :     }
     279             : 
     280     1275260 :     PG_RETURN_BYTEA_P(result);
     281             : }
     282             : 
     283             : /*
     284             :  *      byteaout        - converts to printable representation of byte array
     285             :  *
     286             :  *      In the traditional escaped format, non-printable characters are
     287             :  *      printed as '\nnn' (octal) and '\' as '\\'.
     288             :  */
     289             : Datum
     290      562122 : byteaout(PG_FUNCTION_ARGS)
     291             : {
     292      562122 :     bytea      *vlena = PG_GETARG_BYTEA_PP(0);
     293             :     char       *result;
     294             :     char       *rp;
     295             : 
     296      562122 :     if (bytea_output == BYTEA_OUTPUT_HEX)
     297             :     {
     298             :         /* Print hex format */
     299      561738 :         rp = result = palloc(VARSIZE_ANY_EXHDR(vlena) * 2 + 2 + 1);
     300      561738 :         *rp++ = '\\';
     301      561738 :         *rp++ = 'x';
     302      561738 :         rp += hex_encode(VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena), rp);
     303             :     }
     304         384 :     else if (bytea_output == BYTEA_OUTPUT_ESCAPE)
     305             :     {
     306             :         /* Print traditional escaped format */
     307             :         char       *vp;
     308             :         uint64      len;
     309             :         int         i;
     310             : 
     311         384 :         len = 1;                /* empty string has 1 char */
     312         384 :         vp = VARDATA_ANY(vlena);
     313      217660 :         for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++)
     314             :         {
     315      217276 :             if (*vp == '\\')
     316           0 :                 len += 2;
     317      217276 :             else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e)
     318         498 :                 len += 4;
     319             :             else
     320      216778 :                 len++;
     321             :         }
     322             : 
     323             :         /*
     324             :          * In principle len can't overflow uint32 if the input fit in 1GB, but
     325             :          * for safety let's check rather than relying on palloc's internal
     326             :          * check.
     327             :          */
     328         384 :         if (len > MaxAllocSize)
     329           0 :             ereport(ERROR,
     330             :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     331             :                      errmsg_internal("result of bytea output conversion is too large")));
     332         384 :         rp = result = (char *) palloc(len);
     333             : 
     334         384 :         vp = VARDATA_ANY(vlena);
     335      217660 :         for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++)
     336             :         {
     337      217276 :             if (*vp == '\\')
     338             :             {
     339           0 :                 *rp++ = '\\';
     340           0 :                 *rp++ = '\\';
     341             :             }
     342      217276 :             else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e)
     343         498 :             {
     344             :                 int         val;    /* holds unprintable chars */
     345             : 
     346         498 :                 val = *vp;
     347         498 :                 rp[0] = '\\';
     348         498 :                 rp[3] = DIG(val & 07);
     349         498 :                 val >>= 3;
     350         498 :                 rp[2] = DIG(val & 07);
     351         498 :                 val >>= 3;
     352         498 :                 rp[1] = DIG(val & 03);
     353         498 :                 rp += 4;
     354             :             }
     355             :             else
     356      216778 :                 *rp++ = *vp;
     357             :         }
     358             :     }
     359             :     else
     360             :     {
     361           0 :         elog(ERROR, "unrecognized \"bytea_output\" setting: %d",
     362             :              bytea_output);
     363             :         rp = result = NULL;     /* keep compiler quiet */
     364             :     }
     365      562122 :     *rp = '\0';
     366      562122 :     PG_RETURN_CSTRING(result);
     367             : }
     368             : 
     369             : /*
     370             :  *      bytearecv           - converts external binary format to bytea
     371             :  */
     372             : Datum
     373      107714 : bytearecv(PG_FUNCTION_ARGS)
     374             : {
     375      107714 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     376             :     bytea      *result;
     377             :     int         nbytes;
     378             : 
     379      107714 :     nbytes = buf->len - buf->cursor;
     380      107714 :     result = (bytea *) palloc(nbytes + VARHDRSZ);
     381      107714 :     SET_VARSIZE(result, nbytes + VARHDRSZ);
     382      107714 :     pq_copymsgbytes(buf, VARDATA(result), nbytes);
     383      107714 :     PG_RETURN_BYTEA_P(result);
     384             : }
     385             : 
     386             : /*
     387             :  *      byteasend           - converts bytea to binary format
     388             :  *
     389             :  * This is a special case: just copy the input...
     390             :  */
     391             : Datum
     392       69038 : byteasend(PG_FUNCTION_ARGS)
     393             : {
     394       69038 :     bytea      *vlena = PG_GETARG_BYTEA_P_COPY(0);
     395             : 
     396       69038 :     PG_RETURN_BYTEA_P(vlena);
     397             : }
     398             : 
     399             : Datum
     400      258774 : bytea_string_agg_transfn(PG_FUNCTION_ARGS)
     401             : {
     402             :     StringInfo  state;
     403             : 
     404      258774 :     state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);
     405             : 
     406             :     /* Append the value unless null, preceding it with the delimiter. */
     407      258774 :     if (!PG_ARGISNULL(1))
     408             :     {
     409      243774 :         bytea      *value = PG_GETARG_BYTEA_PP(1);
     410      243774 :         bool        isfirst = false;
     411             : 
     412             :         /*
     413             :          * You might think we can just throw away the first delimiter, however
     414             :          * we must keep it as we may be a parallel worker doing partial
     415             :          * aggregation building a state to send to the main process.  We need
     416             :          * to keep the delimiter of every aggregation so that the combine
     417             :          * function can properly join up the strings of two separately
     418             :          * partially aggregated results.  The first delimiter is only stripped
     419             :          * off in the final function.  To know how much to strip off the front
     420             :          * of the string, we store the length of the first delimiter in the
     421             :          * StringInfo's cursor field, which we don't otherwise need here.
     422             :          */
     423      243774 :         if (state == NULL)
     424             :         {
     425             :             MemoryContext aggcontext;
     426             :             MemoryContext oldcontext;
     427             : 
     428         168 :             if (!AggCheckCallContext(fcinfo, &aggcontext))
     429             :             {
     430             :                 /* cannot be called directly because of internal-type argument */
     431           0 :                 elog(ERROR, "bytea_string_agg_transfn called in non-aggregate context");
     432             :             }
     433             : 
     434             :             /*
     435             :              * Create state in aggregate context.  It'll stay there across
     436             :              * subsequent calls.
     437             :              */
     438         168 :             oldcontext = MemoryContextSwitchTo(aggcontext);
     439         168 :             state = makeStringInfo();
     440         168 :             MemoryContextSwitchTo(oldcontext);
     441             : 
     442         168 :             isfirst = true;
     443             :         }
     444             : 
     445      243774 :         if (!PG_ARGISNULL(2))
     446             :         {
     447      243762 :             bytea      *delim = PG_GETARG_BYTEA_PP(2);
     448             : 
     449      243762 :             appendBinaryStringInfo(state, VARDATA_ANY(delim),
     450      243762 :                                    VARSIZE_ANY_EXHDR(delim));
     451      243762 :             if (isfirst)
     452         162 :                 state->cursor = VARSIZE_ANY_EXHDR(delim);
     453             :         }
     454             : 
     455      243774 :         appendBinaryStringInfo(state, VARDATA_ANY(value),
     456      243774 :                                VARSIZE_ANY_EXHDR(value));
     457             :     }
     458             : 
     459             :     /*
     460             :      * The transition type for string_agg() is declared to be "internal",
     461             :      * which is a pass-by-value type the same size as a pointer.
     462             :      */
     463      258774 :     if (state)
     464      258732 :         PG_RETURN_POINTER(state);
     465          42 :     PG_RETURN_NULL();
     466             : }
     467             : 
     468             : Datum
     469         154 : bytea_string_agg_finalfn(PG_FUNCTION_ARGS)
     470             : {
     471             :     StringInfo  state;
     472             : 
     473             :     /* cannot be called directly because of internal-type argument */
     474             :     Assert(AggCheckCallContext(fcinfo, NULL));
     475             : 
     476         154 :     state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);
     477             : 
     478         154 :     if (state != NULL)
     479             :     {
     480             :         /* As per comment in transfn, strip data before the cursor position */
     481             :         bytea      *result;
     482         148 :         int         strippedlen = state->len - state->cursor;
     483             : 
     484         148 :         result = (bytea *) palloc(strippedlen + VARHDRSZ);
     485         148 :         SET_VARSIZE(result, strippedlen + VARHDRSZ);
     486         148 :         memcpy(VARDATA(result), &state->data[state->cursor], strippedlen);
     487         148 :         PG_RETURN_BYTEA_P(result);
     488             :     }
     489             :     else
     490           6 :         PG_RETURN_NULL();
     491             : }
     492             : 
     493             : /*-------------------------------------------------------------
     494             :  * byteaoctetlen
     495             :  *
     496             :  * get the number of bytes contained in an instance of type 'bytea'
     497             :  *-------------------------------------------------------------
     498             :  */
     499             : Datum
     500         650 : byteaoctetlen(PG_FUNCTION_ARGS)
     501             : {
     502         650 :     Datum       str = PG_GETARG_DATUM(0);
     503             : 
     504             :     /* We need not detoast the input at all */
     505         650 :     PG_RETURN_INT32(toast_raw_datum_size(str) - VARHDRSZ);
     506             : }
     507             : 
     508             : /*
     509             :  * byteacat -
     510             :  *    takes two bytea* and returns a bytea* that is the concatenation of
     511             :  *    the two.
     512             :  *
     513             :  * Cloned from textcat and modified as required.
     514             :  */
     515             : Datum
     516        1522 : byteacat(PG_FUNCTION_ARGS)
     517             : {
     518        1522 :     bytea      *t1 = PG_GETARG_BYTEA_PP(0);
     519        1522 :     bytea      *t2 = PG_GETARG_BYTEA_PP(1);
     520             : 
     521        1522 :     PG_RETURN_BYTEA_P(bytea_catenate(t1, t2));
     522             : }
     523             : 
     524             : /*
     525             :  * byteaoverlay
     526             :  *  Replace specified substring of first string with second
     527             :  *
     528             :  * The SQL standard defines OVERLAY() in terms of substring and concatenation.
     529             :  * This code is a direct implementation of what the standard says.
     530             :  */
     531             : Datum
     532           6 : byteaoverlay(PG_FUNCTION_ARGS)
     533             : {
     534           6 :     bytea      *t1 = PG_GETARG_BYTEA_PP(0);
     535           6 :     bytea      *t2 = PG_GETARG_BYTEA_PP(1);
     536           6 :     int         sp = PG_GETARG_INT32(2);    /* substring start position */
     537           6 :     int         sl = PG_GETARG_INT32(3);    /* substring length */
     538             : 
     539           6 :     PG_RETURN_BYTEA_P(bytea_overlay(t1, t2, sp, sl));
     540             : }
     541             : 
     542             : Datum
     543          12 : byteaoverlay_no_len(PG_FUNCTION_ARGS)
     544             : {
     545          12 :     bytea      *t1 = PG_GETARG_BYTEA_PP(0);
     546          12 :     bytea      *t2 = PG_GETARG_BYTEA_PP(1);
     547          12 :     int         sp = PG_GETARG_INT32(2);    /* substring start position */
     548             :     int         sl;
     549             : 
     550          12 :     sl = VARSIZE_ANY_EXHDR(t2); /* defaults to length(t2) */
     551          12 :     PG_RETURN_BYTEA_P(bytea_overlay(t1, t2, sp, sl));
     552             : }
     553             : 
     554             : /*
     555             :  * bytea_substr()
     556             :  * Return a substring starting at the specified position.
     557             :  * Cloned from text_substr and modified as required.
     558             :  *
     559             :  * Input:
     560             :  *  - string
     561             :  *  - starting position (is one-based)
     562             :  *  - string length (optional)
     563             :  *
     564             :  * If the starting position is zero or less, then return from the start of the string
     565             :  * adjusting the length to be consistent with the "negative start" per SQL.
     566             :  * If the length is less than zero, an ERROR is thrown. If no third argument
     567             :  * (length) is provided, the length to the end of the string is assumed.
     568             :  */
     569             : Datum
     570          86 : bytea_substr(PG_FUNCTION_ARGS)
     571             : {
     572          86 :     PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
     573             :                                       PG_GETARG_INT32(1),
     574             :                                       PG_GETARG_INT32(2),
     575             :                                       false));
     576             : }
     577             : 
     578             : /*
     579             :  * bytea_substr_no_len -
     580             :  *    Wrapper to avoid opr_sanity failure due to
     581             :  *    one function accepting a different number of args.
     582             :  */
     583             : Datum
     584        3936 : bytea_substr_no_len(PG_FUNCTION_ARGS)
     585             : {
     586        3936 :     PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
     587             :                                       PG_GETARG_INT32(1),
     588             :                                       -1,
     589             :                                       true));
     590             : }
     591             : 
     592             : /*
     593             :  * bit_count
     594             :  */
     595             : Datum
     596           6 : bytea_bit_count(PG_FUNCTION_ARGS)
     597             : {
     598           6 :     bytea      *t1 = PG_GETARG_BYTEA_PP(0);
     599             : 
     600           6 :     PG_RETURN_INT64(pg_popcount(VARDATA_ANY(t1), VARSIZE_ANY_EXHDR(t1)));
     601             : }
     602             : 
     603             : /*
     604             :  * byteapos -
     605             :  *    Return the position of the specified substring.
     606             :  *    Implements the SQL POSITION() function.
     607             :  * Cloned from textpos and modified as required.
     608             :  */
     609             : Datum
     610          30 : byteapos(PG_FUNCTION_ARGS)
     611             : {
     612          30 :     bytea      *t1 = PG_GETARG_BYTEA_PP(0);
     613          30 :     bytea      *t2 = PG_GETARG_BYTEA_PP(1);
     614             :     int         pos;
     615             :     int         px,
     616             :                 p;
     617             :     int         len1,
     618             :                 len2;
     619             :     char       *p1,
     620             :                *p2;
     621             : 
     622          30 :     len1 = VARSIZE_ANY_EXHDR(t1);
     623          30 :     len2 = VARSIZE_ANY_EXHDR(t2);
     624             : 
     625          30 :     if (len2 <= 0)
     626           6 :         PG_RETURN_INT32(1);     /* result for empty pattern */
     627             : 
     628          24 :     p1 = VARDATA_ANY(t1);
     629          24 :     p2 = VARDATA_ANY(t2);
     630             : 
     631          24 :     pos = 0;
     632          24 :     px = (len1 - len2);
     633          54 :     for (p = 0; p <= px; p++)
     634             :     {
     635          42 :         if ((*p2 == *p1) && (memcmp(p1, p2, len2) == 0))
     636             :         {
     637          12 :             pos = p + 1;
     638          12 :             break;
     639             :         };
     640          30 :         p1++;
     641             :     };
     642             : 
     643          24 :     PG_RETURN_INT32(pos);
     644             : }
     645             : 
     646             : /*-------------------------------------------------------------
     647             :  * byteaGetByte
     648             :  *
     649             :  * this routine treats "bytea" as an array of bytes.
     650             :  * It returns the Nth byte (a number between 0 and 255).
     651             :  *-------------------------------------------------------------
     652             :  */
     653             : Datum
     654          76 : byteaGetByte(PG_FUNCTION_ARGS)
     655             : {
     656          76 :     bytea      *v = PG_GETARG_BYTEA_PP(0);
     657          76 :     int32       n = PG_GETARG_INT32(1);
     658             :     int         len;
     659             :     int         byte;
     660             : 
     661          76 :     len = VARSIZE_ANY_EXHDR(v);
     662             : 
     663          76 :     if (n < 0 || n >= len)
     664           6 :         ereport(ERROR,
     665             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     666             :                  errmsg("index %d out of valid range, 0..%d",
     667             :                         n, len - 1)));
     668             : 
     669          70 :     byte = ((unsigned char *) VARDATA_ANY(v))[n];
     670             : 
     671          70 :     PG_RETURN_INT32(byte);
     672             : }
     673             : 
     674             : /*-------------------------------------------------------------
     675             :  * byteaGetBit
     676             :  *
     677             :  * This routine treats a "bytea" type like an array of bits.
     678             :  * It returns the value of the Nth bit (0 or 1).
     679             :  *
     680             :  *-------------------------------------------------------------
     681             :  */
     682             : Datum
     683          12 : byteaGetBit(PG_FUNCTION_ARGS)
     684             : {
     685          12 :     bytea      *v = PG_GETARG_BYTEA_PP(0);
     686          12 :     int64       n = PG_GETARG_INT64(1);
     687             :     int         byteNo,
     688             :                 bitNo;
     689             :     int         len;
     690             :     int         byte;
     691             : 
     692          12 :     len = VARSIZE_ANY_EXHDR(v);
     693             : 
     694          12 :     if (n < 0 || n >= (int64) len * 8)
     695           6 :         ereport(ERROR,
     696             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     697             :                  errmsg("index %" PRId64 " out of valid range, 0..%" PRId64,
     698             :                         n, (int64) len * 8 - 1)));
     699             : 
     700             :     /* n/8 is now known < len, so safe to cast to int */
     701           6 :     byteNo = (int) (n / 8);
     702           6 :     bitNo = (int) (n % 8);
     703             : 
     704           6 :     byte = ((unsigned char *) VARDATA_ANY(v))[byteNo];
     705             : 
     706           6 :     if (byte & (1 << bitNo))
     707           6 :         PG_RETURN_INT32(1);
     708             :     else
     709           0 :         PG_RETURN_INT32(0);
     710             : }
     711             : 
     712             : /*-------------------------------------------------------------
     713             :  * byteaSetByte
     714             :  *
     715             :  * Given an instance of type 'bytea' creates a new one with
     716             :  * the Nth byte set to the given value.
     717             :  *
     718             :  *-------------------------------------------------------------
     719             :  */
     720             : Datum
     721          12 : byteaSetByte(PG_FUNCTION_ARGS)
     722             : {
     723          12 :     bytea      *res = PG_GETARG_BYTEA_P_COPY(0);
     724          12 :     int32       n = PG_GETARG_INT32(1);
     725          12 :     int32       newByte = PG_GETARG_INT32(2);
     726             :     int         len;
     727             : 
     728          12 :     len = VARSIZE(res) - VARHDRSZ;
     729             : 
     730          12 :     if (n < 0 || n >= len)
     731           6 :         ereport(ERROR,
     732             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     733             :                  errmsg("index %d out of valid range, 0..%d",
     734             :                         n, len - 1)));
     735             : 
     736             :     /*
     737             :      * Now set the byte.
     738             :      */
     739           6 :     ((unsigned char *) VARDATA(res))[n] = newByte;
     740             : 
     741           6 :     PG_RETURN_BYTEA_P(res);
     742             : }
     743             : 
     744             : /*-------------------------------------------------------------
     745             :  * byteaSetBit
     746             :  *
     747             :  * Given an instance of type 'bytea' creates a new one with
     748             :  * the Nth bit set to the given value.
     749             :  *
     750             :  *-------------------------------------------------------------
     751             :  */
     752             : Datum
     753          12 : byteaSetBit(PG_FUNCTION_ARGS)
     754             : {
     755          12 :     bytea      *res = PG_GETARG_BYTEA_P_COPY(0);
     756          12 :     int64       n = PG_GETARG_INT64(1);
     757          12 :     int32       newBit = PG_GETARG_INT32(2);
     758             :     int         len;
     759             :     int         oldByte,
     760             :                 newByte;
     761             :     int         byteNo,
     762             :                 bitNo;
     763             : 
     764          12 :     len = VARSIZE(res) - VARHDRSZ;
     765             : 
     766          12 :     if (n < 0 || n >= (int64) len * 8)
     767           6 :         ereport(ERROR,
     768             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     769             :                  errmsg("index %" PRId64 " out of valid range, 0..%" PRId64,
     770             :                         n, (int64) len * 8 - 1)));
     771             : 
     772             :     /* n/8 is now known < len, so safe to cast to int */
     773           6 :     byteNo = (int) (n / 8);
     774           6 :     bitNo = (int) (n % 8);
     775             : 
     776             :     /*
     777             :      * sanity check!
     778             :      */
     779           6 :     if (newBit != 0 && newBit != 1)
     780           0 :         ereport(ERROR,
     781             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     782             :                  errmsg("new bit must be 0 or 1")));
     783             : 
     784             :     /*
     785             :      * Update the byte.
     786             :      */
     787           6 :     oldByte = ((unsigned char *) VARDATA(res))[byteNo];
     788             : 
     789           6 :     if (newBit == 0)
     790           6 :         newByte = oldByte & (~(1 << bitNo));
     791             :     else
     792           0 :         newByte = oldByte | (1 << bitNo);
     793             : 
     794           6 :     ((unsigned char *) VARDATA(res))[byteNo] = newByte;
     795             : 
     796           6 :     PG_RETURN_BYTEA_P(res);
     797             : }
     798             : 
     799             : /*
     800             :  * Return reversed bytea
     801             :  */
     802             : Datum
     803          18 : bytea_reverse(PG_FUNCTION_ARGS)
     804             : {
     805          18 :     bytea      *v = PG_GETARG_BYTEA_PP(0);
     806          18 :     const char *p = VARDATA_ANY(v);
     807          18 :     int         len = VARSIZE_ANY_EXHDR(v);
     808          18 :     const char *endp = p + len;
     809          18 :     bytea      *result = palloc(len + VARHDRSZ);
     810          18 :     char       *dst = (char *) VARDATA(result) + len;
     811             : 
     812          18 :     SET_VARSIZE(result, len + VARHDRSZ);
     813             : 
     814          36 :     while (p < endp)
     815          18 :         *(--dst) = *p++;
     816             : 
     817          18 :     PG_RETURN_BYTEA_P(result);
     818             : }
     819             : 
     820             : 
     821             : /*****************************************************************************
     822             :  *  Comparison Functions used for bytea
     823             :  *
     824             :  * Note: btree indexes need these routines not to leak memory; therefore,
     825             :  * be careful to free working copies of toasted datums.  Most places don't
     826             :  * need to be so careful.
     827             :  *****************************************************************************/
     828             : 
     829             : Datum
     830       10478 : byteaeq(PG_FUNCTION_ARGS)
     831             : {
     832       10478 :     Datum       arg1 = PG_GETARG_DATUM(0);
     833       10478 :     Datum       arg2 = PG_GETARG_DATUM(1);
     834             :     bool        result;
     835             :     Size        len1,
     836             :                 len2;
     837             : 
     838             :     /*
     839             :      * We can use a fast path for unequal lengths, which might save us from
     840             :      * having to detoast one or both values.
     841             :      */
     842       10478 :     len1 = toast_raw_datum_size(arg1);
     843       10478 :     len2 = toast_raw_datum_size(arg2);
     844       10478 :     if (len1 != len2)
     845        4400 :         result = false;
     846             :     else
     847             :     {
     848        6078 :         bytea      *barg1 = DatumGetByteaPP(arg1);
     849        6078 :         bytea      *barg2 = DatumGetByteaPP(arg2);
     850             : 
     851        6078 :         result = (memcmp(VARDATA_ANY(barg1), VARDATA_ANY(barg2),
     852             :                          len1 - VARHDRSZ) == 0);
     853             : 
     854        6078 :         PG_FREE_IF_COPY(barg1, 0);
     855        6078 :         PG_FREE_IF_COPY(barg2, 1);
     856             :     }
     857             : 
     858       10478 :     PG_RETURN_BOOL(result);
     859             : }
     860             : 
     861             : Datum
     862         768 : byteane(PG_FUNCTION_ARGS)
     863             : {
     864         768 :     Datum       arg1 = PG_GETARG_DATUM(0);
     865         768 :     Datum       arg2 = PG_GETARG_DATUM(1);
     866             :     bool        result;
     867             :     Size        len1,
     868             :                 len2;
     869             : 
     870             :     /*
     871             :      * We can use a fast path for unequal lengths, which might save us from
     872             :      * having to detoast one or both values.
     873             :      */
     874         768 :     len1 = toast_raw_datum_size(arg1);
     875         768 :     len2 = toast_raw_datum_size(arg2);
     876         768 :     if (len1 != len2)
     877           0 :         result = true;
     878             :     else
     879             :     {
     880         768 :         bytea      *barg1 = DatumGetByteaPP(arg1);
     881         768 :         bytea      *barg2 = DatumGetByteaPP(arg2);
     882             : 
     883         768 :         result = (memcmp(VARDATA_ANY(barg1), VARDATA_ANY(barg2),
     884             :                          len1 - VARHDRSZ) != 0);
     885             : 
     886         768 :         PG_FREE_IF_COPY(barg1, 0);
     887         768 :         PG_FREE_IF_COPY(barg2, 1);
     888             :     }
     889             : 
     890         768 :     PG_RETURN_BOOL(result);
     891             : }
     892             : 
     893             : Datum
     894        8346 : bytealt(PG_FUNCTION_ARGS)
     895             : {
     896        8346 :     bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
     897        8346 :     bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
     898             :     int         len1,
     899             :                 len2;
     900             :     int         cmp;
     901             : 
     902        8346 :     len1 = VARSIZE_ANY_EXHDR(arg1);
     903        8346 :     len2 = VARSIZE_ANY_EXHDR(arg2);
     904             : 
     905        8346 :     cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
     906             : 
     907        8346 :     PG_FREE_IF_COPY(arg1, 0);
     908        8346 :     PG_FREE_IF_COPY(arg2, 1);
     909             : 
     910        8346 :     PG_RETURN_BOOL((cmp < 0) || ((cmp == 0) && (len1 < len2)));
     911             : }
     912             : 
     913             : Datum
     914        6356 : byteale(PG_FUNCTION_ARGS)
     915             : {
     916        6356 :     bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
     917        6356 :     bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
     918             :     int         len1,
     919             :                 len2;
     920             :     int         cmp;
     921             : 
     922        6356 :     len1 = VARSIZE_ANY_EXHDR(arg1);
     923        6356 :     len2 = VARSIZE_ANY_EXHDR(arg2);
     924             : 
     925        6356 :     cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
     926             : 
     927        6356 :     PG_FREE_IF_COPY(arg1, 0);
     928        6356 :     PG_FREE_IF_COPY(arg2, 1);
     929             : 
     930        6356 :     PG_RETURN_BOOL((cmp < 0) || ((cmp == 0) && (len1 <= len2)));
     931             : }
     932             : 
     933             : Datum
     934        6366 : byteagt(PG_FUNCTION_ARGS)
     935             : {
     936        6366 :     bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
     937        6366 :     bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
     938             :     int         len1,
     939             :                 len2;
     940             :     int         cmp;
     941             : 
     942        6366 :     len1 = VARSIZE_ANY_EXHDR(arg1);
     943        6366 :     len2 = VARSIZE_ANY_EXHDR(arg2);
     944             : 
     945        6366 :     cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
     946             : 
     947        6366 :     PG_FREE_IF_COPY(arg1, 0);
     948        6366 :     PG_FREE_IF_COPY(arg2, 1);
     949             : 
     950        6366 :     PG_RETURN_BOOL((cmp > 0) || ((cmp == 0) && (len1 > len2)));
     951             : }
     952             : 
     953             : Datum
     954        5054 : byteage(PG_FUNCTION_ARGS)
     955             : {
     956        5054 :     bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
     957        5054 :     bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
     958             :     int         len1,
     959             :                 len2;
     960             :     int         cmp;
     961             : 
     962        5054 :     len1 = VARSIZE_ANY_EXHDR(arg1);
     963        5054 :     len2 = VARSIZE_ANY_EXHDR(arg2);
     964             : 
     965        5054 :     cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
     966             : 
     967        5054 :     PG_FREE_IF_COPY(arg1, 0);
     968        5054 :     PG_FREE_IF_COPY(arg2, 1);
     969             : 
     970        5054 :     PG_RETURN_BOOL((cmp > 0) || ((cmp == 0) && (len1 >= len2)));
     971             : }
     972             : 
     973             : Datum
     974       94592 : byteacmp(PG_FUNCTION_ARGS)
     975             : {
     976       94592 :     bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
     977       94592 :     bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
     978             :     int         len1,
     979             :                 len2;
     980             :     int         cmp;
     981             : 
     982       94592 :     len1 = VARSIZE_ANY_EXHDR(arg1);
     983       94592 :     len2 = VARSIZE_ANY_EXHDR(arg2);
     984             : 
     985       94592 :     cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
     986       94592 :     if ((cmp == 0) && (len1 != len2))
     987        3400 :         cmp = (len1 < len2) ? -1 : 1;
     988             : 
     989       94592 :     PG_FREE_IF_COPY(arg1, 0);
     990       94592 :     PG_FREE_IF_COPY(arg2, 1);
     991             : 
     992       94592 :     PG_RETURN_INT32(cmp);
     993             : }
     994             : 
     995             : Datum
     996          24 : bytea_larger(PG_FUNCTION_ARGS)
     997             : {
     998          24 :     bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
     999          24 :     bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
    1000             :     bytea      *result;
    1001             :     int         len1,
    1002             :                 len2;
    1003             :     int         cmp;
    1004             : 
    1005          24 :     len1 = VARSIZE_ANY_EXHDR(arg1);
    1006          24 :     len2 = VARSIZE_ANY_EXHDR(arg2);
    1007             : 
    1008          24 :     cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
    1009          24 :     result = ((cmp > 0) || ((cmp == 0) && (len1 > len2)) ? arg1 : arg2);
    1010             : 
    1011          24 :     PG_RETURN_BYTEA_P(result);
    1012             : }
    1013             : 
    1014             : Datum
    1015          24 : bytea_smaller(PG_FUNCTION_ARGS)
    1016             : {
    1017          24 :     bytea      *arg1 = PG_GETARG_BYTEA_PP(0);
    1018          24 :     bytea      *arg2 = PG_GETARG_BYTEA_PP(1);
    1019             :     bytea      *result;
    1020             :     int         len1,
    1021             :                 len2;
    1022             :     int         cmp;
    1023             : 
    1024          24 :     len1 = VARSIZE_ANY_EXHDR(arg1);
    1025          24 :     len2 = VARSIZE_ANY_EXHDR(arg2);
    1026             : 
    1027          24 :     cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
    1028          24 :     result = ((cmp < 0) || ((cmp == 0) && (len1 < len2)) ? arg1 : arg2);
    1029             : 
    1030          24 :     PG_RETURN_BYTEA_P(result);
    1031             : }
    1032             : 
    1033             : Datum
    1034          44 : bytea_sortsupport(PG_FUNCTION_ARGS)
    1035             : {
    1036          44 :     SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
    1037             :     MemoryContext oldcontext;
    1038             : 
    1039          44 :     oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
    1040             : 
    1041             :     /* Use generic string SortSupport, forcing "C" collation */
    1042          44 :     varstr_sortsupport(ssup, BYTEAOID, C_COLLATION_OID);
    1043             : 
    1044          44 :     MemoryContextSwitchTo(oldcontext);
    1045             : 
    1046          44 :     PG_RETURN_VOID();
    1047             : }
    1048             : 
    1049             : /* Cast bytea -> int2 */
    1050             : Datum
    1051          36 : bytea_int2(PG_FUNCTION_ARGS)
    1052             : {
    1053          36 :     bytea      *v = PG_GETARG_BYTEA_PP(0);
    1054          36 :     int         len = VARSIZE_ANY_EXHDR(v);
    1055             :     uint16      result;
    1056             : 
    1057             :     /* Check that the byte array is not too long */
    1058          36 :     if (len > sizeof(result))
    1059           6 :         ereport(ERROR,
    1060             :                 errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1061             :                 errmsg("smallint out of range"));
    1062             : 
    1063             :     /* Convert it to an integer; most significant bytes come first */
    1064          30 :     result = 0;
    1065          72 :     for (int i = 0; i < len; i++)
    1066             :     {
    1067          42 :         result <<= BITS_PER_BYTE;
    1068          42 :         result |= ((unsigned char *) VARDATA_ANY(v))[i];
    1069             :     }
    1070             : 
    1071          30 :     PG_RETURN_INT16(result);
    1072             : }
    1073             : 
    1074             : /* Cast bytea -> int4 */
    1075             : Datum
    1076          36 : bytea_int4(PG_FUNCTION_ARGS)
    1077             : {
    1078          36 :     bytea      *v = PG_GETARG_BYTEA_PP(0);
    1079          36 :     int         len = VARSIZE_ANY_EXHDR(v);
    1080             :     uint32      result;
    1081             : 
    1082             :     /* Check that the byte array is not too long */
    1083          36 :     if (len > sizeof(result))
    1084           6 :         ereport(ERROR,
    1085             :                 errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1086             :                 errmsg("integer out of range"));
    1087             : 
    1088             :     /* Convert it to an integer; most significant bytes come first */
    1089          30 :     result = 0;
    1090         108 :     for (int i = 0; i < len; i++)
    1091             :     {
    1092          78 :         result <<= BITS_PER_BYTE;
    1093          78 :         result |= ((unsigned char *) VARDATA_ANY(v))[i];
    1094             :     }
    1095             : 
    1096          30 :     PG_RETURN_INT32(result);
    1097             : }
    1098             : 
    1099             : /* Cast bytea -> int8 */
    1100             : Datum
    1101          36 : bytea_int8(PG_FUNCTION_ARGS)
    1102             : {
    1103          36 :     bytea      *v = PG_GETARG_BYTEA_PP(0);
    1104          36 :     int         len = VARSIZE_ANY_EXHDR(v);
    1105             :     uint64      result;
    1106             : 
    1107             :     /* Check that the byte array is not too long */
    1108          36 :     if (len > sizeof(result))
    1109           6 :         ereport(ERROR,
    1110             :                 errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1111             :                 errmsg("bigint out of range"));
    1112             : 
    1113             :     /* Convert it to an integer; most significant bytes come first */
    1114          30 :     result = 0;
    1115         180 :     for (int i = 0; i < len; i++)
    1116             :     {
    1117         150 :         result <<= BITS_PER_BYTE;
    1118         150 :         result |= ((unsigned char *) VARDATA_ANY(v))[i];
    1119             :     }
    1120             : 
    1121          30 :     PG_RETURN_INT64(result);
    1122             : }
    1123             : 
    1124             : /* Cast int2 -> bytea; can just use int2send() */
    1125             : Datum
    1126          12 : int2_bytea(PG_FUNCTION_ARGS)
    1127             : {
    1128          12 :     return int2send(fcinfo);
    1129             : }
    1130             : 
    1131             : /* Cast int4 -> bytea; can just use int4send() */
    1132             : Datum
    1133       40972 : int4_bytea(PG_FUNCTION_ARGS)
    1134             : {
    1135       40972 :     return int4send(fcinfo);
    1136             : }
    1137             : 
    1138             : /* Cast int8 -> bytea; can just use int8send() */
    1139             : Datum
    1140          12 : int8_bytea(PG_FUNCTION_ARGS)
    1141             : {
    1142          12 :     return int8send(fcinfo);
    1143             : }

Generated by: LCOV version 1.16