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

Generated by: LCOV version 1.16