Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postgres/src/backend/utils/adt/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 42 kB image not shown  

Quelle  varbit.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * varbit.c
 *   Functions for the SQL datatypes BIT() and BIT VARYING().
 *
 * The data structure contains the following elements:
 *   header  -- length of the whole data structure (incl header)
 *              in bytes (as with all varying length datatypes)
 *   data section -- private data section for the bits data structures
 *     bitlength -- length of the bit string in bits
 *     bitdata   -- bit string, most significant byte first
 *
 * The length of the bitdata vector should always be exactly as many
 * bytes as are needed for the given bitlength.  If the bitlength is
 * not a multiple of 8, the extra low-order padding bits of the last
 * byte must be zeroes.
 *
 * attypmod is defined as the length of the bit string in bits, or for
 * varying bits the maximum length.
 *
 * Code originally contributed by Adriaan Joubert.
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *   src/backend/utils/adt/varbit.c
 *
 *-------------------------------------------------------------------------
 */


#include "postgres.h"

#include "access/htup_details.h"
#include "common/int.h"
#include "libpq/pqformat.h"
#include "nodes/nodeFuncs.h"
#include "nodes/supportnodes.h"
#include "port/pg_bitutils.h"
#include "utils/array.h"
#include "utils/fmgrprotos.h"
#include "utils/varbit.h"

#define HEXDIG(z)  ((z)<10 ? ((z)+'0') : ((z)-10+'A'))

/* Mask off any bits that should be zero in the last byte of a bitstring */
#define VARBIT_PAD(vb) \
 do { \
  int32 pad_ = VARBITPAD(vb); \
  Assert(pad_ >= 0 && pad_ < BITS_PER_BYTE); \
  if (pad_ > 0) \
   *(VARBITS(vb) + VARBITBYTES(vb) - 1) &= BITMASK << pad_; \
 } while (0)

/*
 * Many functions work byte-by-byte, so they have a pointer handy to the
 * last-plus-one byte, which saves a cycle or two.
 */

#define VARBIT_PAD_LAST(vb, ptr) \
 do { \
  int32 pad_ = VARBITPAD(vb); \
  Assert(pad_ >= 0 && pad_ < BITS_PER_BYTE); \
  if (pad_ > 0) \
   *((ptr) - 1) &= BITMASK << pad_; \
 } while (0)

/* Assert proper padding of a bitstring */
#ifdef USE_ASSERT_CHECKING
#define VARBIT_CORRECTLY_PADDED(vb) \
 do { \
  int32 pad_ = VARBITPAD(vb); \
  Assert(pad_ >= 0 && pad_ < BITS_PER_BYTE); \
  Assert(pad_ == 0 || \
      (*(VARBITS(vb) + VARBITBYTES(vb) - 1) & ~(BITMASK << pad_)) == 0); \
 } while (0)
#else
#define VARBIT_CORRECTLY_PADDED(vb) ((void0)
#endif

static VarBit *bit_catenate(VarBit *arg1, VarBit *arg2);
static VarBit *bitsubstring(VarBit *arg, int32 s, int32 l,
       bool length_not_specified);
static VarBit *bit_overlay(VarBit *t1, VarBit *t2, int sp, int sl);


/*
 * common code for bittypmodin and varbittypmodin
 */

static int32
anybit_typmodin(ArrayType *ta, const char *typename)
{
 int32  typmod;
 int32    *tl;
 int   n;

 tl = ArrayGetIntegerTypmods(ta, &n);

 /*
  * we're not too tense about good error message here because grammar
  * shouldn't allow wrong number of modifiers for BIT
 */

 if (n != 1)
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     errmsg("invalid type modifier")));

 if (*tl < 1)
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     errmsg("length for type %s must be at least 1",
      typename)));
 if (*tl > (MaxAttrSize * BITS_PER_BYTE))
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     errmsg("length for type %s cannot exceed %d",
      typename, MaxAttrSize * BITS_PER_BYTE)));

 typmod = *tl;

 return typmod;
}

/*
 * common code for bittypmodout and varbittypmodout
 */

static char *
anybit_typmodout(int32 typmod)
{
 char    *res = (char *) palloc(64);

 if (typmod >= 0)
  snprintf(res, 64"(%d)", typmod);
 else
  *res = '\0';

 return res;
}


/*
 * bit_in -
 *   converts a char string to the internal representation of a bitstring.
 *    The length is determined by the number of bits required plus
 *    VARHDRSZ bytes or from atttypmod.
 */

Datum
bit_in(PG_FUNCTION_ARGS)
{
 char    *input_string = PG_GETARG_CSTRING(0);
#ifdef NOT_USED
 Oid   typelem = PG_GETARG_OID(1);
#endif
 int32  atttypmod = PG_GETARG_INT32(2);
 Node    *escontext = fcinfo->context;
 VarBit    *result;   /* The resulting bit string   */
 char    *sp;    /* pointer into the character string  */
 bits8    *r;    /* pointer into the result */
 int   len,   /* Length of the whole data structure */
    bitlen,   /* Number of bits in the bit string   */
    slen;   /* Length of the input string   */
 bool  bit_not_hex; /* false = hex string  true = bit string */
 int   bc;
 bits8  x = 0;

 /* Check that the first character is a b or an x */
 if (input_string[0] == 'b' || input_string[0] == 'B')
 {
  bit_not_hex = true;
  sp = input_string + 1;
 }
 else if (input_string[0] == 'x' || input_string[0] == 'X')
 {
  bit_not_hex = false;
  sp = input_string + 1;
 }
 else
 {
  /*
   * Otherwise it's binary.  This allows things like cast('1001' as bit)
   * to work transparently.
 */

  bit_not_hex = true;
  sp = input_string;
 }

 /*
  * Determine bitlength from input string.  MaxAllocSize ensures a regular
  * input is small enough, but we must check hex input.
 */

 slen = strlen(sp);
 if (bit_not_hex)
  bitlen = slen;
 else
 {
  if (slen > VARBITMAXLEN / 4)
   ereturn(escontext, (Datum) 0,
     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
      errmsg("bit string length exceeds the maximum allowed (%d)",
       VARBITMAXLEN)));
  bitlen = slen * 4;
 }

 /*
  * Sometimes atttypmod is not supplied. If it is supplied we need to make
  * sure that the bitstring fits.
 */

 if (atttypmod <= 0)
  atttypmod = bitlen;
 else if (bitlen != atttypmod)
  ereturn(escontext, (Datum) 0,
    (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
     errmsg("bit string length %d does not match type bit(%d)",
      bitlen, atttypmod)));

 len = VARBITTOTALLEN(atttypmod);
 /* set to 0 so that *r is always initialised and string is zero-padded */
 result = (VarBit *) palloc0(len);
 SET_VARSIZE(result, len);
 VARBITLEN(result) = atttypmod;

 r = VARBITS(result);
 if (bit_not_hex)
 {
  /* Parse the bit representation of the string */
  /* We know it fits, as bitlen was compared to atttypmod */
  x = HIGHBIT;
  for (; *sp; sp++)
  {
   if (*sp == '1')
    *r |= x;
   else if (*sp != '0')
    ereturn(escontext, (Datum) 0,
      (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
       errmsg("\"%.*s\" is not a valid binary digit",
        pg_mblen_cstr(sp), sp)));

   x >>= 1;
   if (x == 0)
   {
    x = HIGHBIT;
    r++;
   }
  }
 }
 else
 {
  /* Parse the hex representation of the string */
  for (bc = 0; *sp; sp++)
  {
   if (*sp >= '0' && *sp <= '9')
    x = (bits8) (*sp - '0');
   else if (*sp >= 'A' && *sp <= 'F')
    x = (bits8) (*sp - 'A') + 10;
   else if (*sp >= 'a' && *sp <= 'f')
    x = (bits8) (*sp - 'a') + 10;
   else
    ereturn(escontext, (Datum) 0,
      (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
       errmsg("\"%.*s\" is not a valid hexadecimal digit",
        pg_mblen_cstr(sp), sp)));

   if (bc)
   {
    *r++ |= x;
    bc = 0;
   }
   else
   {
    *r = x << 4;
    bc = 1;
   }
  }
 }

 PG_RETURN_VARBIT_P(result);
}


Datum
bit_out(PG_FUNCTION_ARGS)
{
#if 1
 /* same as varbit output */
 return varbit_out(fcinfo);
#else

 /*
  * This is how one would print a hex string, in case someone wants to
  * write a formatting function.
 */

 VarBit    *s = PG_GETARG_VARBIT_P(0);
 char    *result,
      *r;
 bits8    *sp;
 int   i,
    len,
    bitlen;

 /* Assertion to help catch any bit functions that don't pad correctly */
 VARBIT_CORRECTLY_PADDED(s);

 bitlen = VARBITLEN(s);
 len = (bitlen + 3) / 4;
 result = (char *) palloc(len + 2);
 sp = VARBITS(s);
 r = result;
 *r++ = 'X';
 /* we cheat by knowing that we store full bytes zero padded */
 for (i = 0; i < len; i += 2, sp++)
 {
  *r++ = HEXDIG((*sp) >> 4);
  *r++ = HEXDIG((*sp) & 0xF);
 }

 /*
  * Go back one step if we printed a hex number that was not part of the
  * bitstring anymore
 */

 if (i > len)
  r--;
 *r = '\0';

 PG_RETURN_CSTRING(result);
#endif
}

/*
 *  bit_recv   - converts external binary format to bit
 */

Datum
bit_recv(PG_FUNCTION_ARGS)
{
 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);

#ifdef NOT_USED
 Oid   typelem = PG_GETARG_OID(1);
#endif
 int32  atttypmod = PG_GETARG_INT32(2);
 VarBit    *result;
 int   len,
    bitlen;

 bitlen = pq_getmsgint(buf, sizeof(int32));
 if (bitlen < 0 || bitlen > VARBITMAXLEN)
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
     errmsg("invalid length in external bit string")));

 /*
  * Sometimes atttypmod is not supplied. If it is supplied we need to make
  * sure that the bitstring fits.
 */

 if (atttypmod > 0 && bitlen != atttypmod)
  ereport(ERROR,
    (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
     errmsg("bit string length %d does not match type bit(%d)",
      bitlen, atttypmod)));

 len = VARBITTOTALLEN(bitlen);
 result = (VarBit *) palloc(len);
 SET_VARSIZE(result, len);
 VARBITLEN(result) = bitlen;

 pq_copymsgbytes(buf, VARBITS(result), VARBITBYTES(result));

 /* Make sure last byte is correctly zero-padded */
 VARBIT_PAD(result);

 PG_RETURN_VARBIT_P(result);
}

/*
 *  bit_send   - converts bit to binary format
 */

Datum
bit_send(PG_FUNCTION_ARGS)
{
 /* Exactly the same as varbit_send, so share code */
 return varbit_send(fcinfo);
}

/*
 * bit()
 * Converts a bit() type to a specific internal length.
 * len is the bitlength specified in the column definition.
 *
 * If doing implicit cast, raise error when source data is wrong length.
 * If doing explicit cast, silently truncate or zero-pad to specified length.
 */

Datum
bit(PG_FUNCTION_ARGS)
{
 VarBit    *arg = PG_GETARG_VARBIT_P(0);
 int32  len = PG_GETARG_INT32(1);
 bool  isExplicit = PG_GETARG_BOOL(2);
 VarBit    *result;
 int   rlen;

 /* No work if typmod is invalid or supplied data matches it already */
 if (len <= 0 || len > VARBITMAXLEN || len == VARBITLEN(arg))
  PG_RETURN_VARBIT_P(arg);

 if (!isExplicit)
  ereport(ERROR,
    (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
     errmsg("bit string length %d does not match type bit(%d)",
      VARBITLEN(arg), len)));

 rlen = VARBITTOTALLEN(len);
 /* set to 0 so that string is zero-padded */
 result = (VarBit *) palloc0(rlen);
 SET_VARSIZE(result, rlen);
 VARBITLEN(result) = len;

 memcpy(VARBITS(result), VARBITS(arg),
     Min(VARBITBYTES(result), VARBITBYTES(arg)));

 /*
  * Make sure last byte is zero-padded if needed.  This is useless but safe
  * if source data was shorter than target length (we assume the last byte
  * of the source data was itself correctly zero-padded).
 */

 VARBIT_PAD(result);

 PG_RETURN_VARBIT_P(result);
}

Datum
bittypmodin(PG_FUNCTION_ARGS)
{
 ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);

 PG_RETURN_INT32(anybit_typmodin(ta, "bit"));
}

Datum
bittypmodout(PG_FUNCTION_ARGS)
{
 int32  typmod = PG_GETARG_INT32(0);

 PG_RETURN_CSTRING(anybit_typmodout(typmod));
}


/*
 * varbit_in -
 *   converts a string to the internal representation of a bitstring.
 *  This is the same as bit_in except that atttypmod is taken as
 *  the maximum length, not the exact length to force the bitstring to.
 */

Datum
varbit_in(PG_FUNCTION_ARGS)
{
 char    *input_string = PG_GETARG_CSTRING(0);
#ifdef NOT_USED
 Oid   typelem = PG_GETARG_OID(1);
#endif
 int32  atttypmod = PG_GETARG_INT32(2);
 Node    *escontext = fcinfo->context;
 VarBit    *result;   /* The resulting bit string   */
 char    *sp;    /* pointer into the character string  */
 bits8    *r;    /* pointer into the result */
 int   len,   /* Length of the whole data structure */
    bitlen,   /* Number of bits in the bit string   */
    slen;   /* Length of the input string   */
 bool  bit_not_hex; /* false = hex string  true = bit string */
 int   bc;
 bits8  x = 0;

 /* Check that the first character is a b or an x */
 if (input_string[0] == 'b' || input_string[0] == 'B')
 {
  bit_not_hex = true;
  sp = input_string + 1;
 }
 else if (input_string[0] == 'x' || input_string[0] == 'X')
 {
  bit_not_hex = false;
  sp = input_string + 1;
 }
 else
 {
  bit_not_hex = true;
  sp = input_string;
 }

 /*
  * Determine bitlength from input string.  MaxAllocSize ensures a regular
  * input is small enough, but we must check hex input.
 */

 slen = strlen(sp);
 if (bit_not_hex)
  bitlen = slen;
 else
 {
  if (slen > VARBITMAXLEN / 4)
   ereturn(escontext, (Datum) 0,
     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
      errmsg("bit string length exceeds the maximum allowed (%d)",
       VARBITMAXLEN)));
  bitlen = slen * 4;
 }

 /*
  * Sometimes atttypmod is not supplied. If it is supplied we need to make
  * sure that the bitstring fits.
 */

 if (atttypmod <= 0)
  atttypmod = bitlen;
 else if (bitlen > atttypmod)
  ereturn(escontext, (Datum) 0,
    (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
     errmsg("bit string too long for type bit varying(%d)",
      atttypmod)));

 len = VARBITTOTALLEN(bitlen);
 /* set to 0 so that *r is always initialised and string is zero-padded */
 result = (VarBit *) palloc0(len);
 SET_VARSIZE(result, len);
 VARBITLEN(result) = Min(bitlen, atttypmod);

 r = VARBITS(result);
 if (bit_not_hex)
 {
  /* Parse the bit representation of the string */
  /* We know it fits, as bitlen was compared to atttypmod */
  x = HIGHBIT;
  for (; *sp; sp++)
  {
   if (*sp == '1')
    *r |= x;
   else if (*sp != '0')
    ereturn(escontext, (Datum) 0,
      (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
       errmsg("\"%.*s\" is not a valid binary digit",
        pg_mblen_cstr(sp), sp)));

   x >>= 1;
   if (x == 0)
   {
    x = HIGHBIT;
    r++;
   }
  }
 }
 else
 {
  /* Parse the hex representation of the string */
  for (bc = 0; *sp; sp++)
  {
   if (*sp >= '0' && *sp <= '9')
    x = (bits8) (*sp - '0');
   else if (*sp >= 'A' && *sp <= 'F')
    x = (bits8) (*sp - 'A') + 10;
   else if (*sp >= 'a' && *sp <= 'f')
    x = (bits8) (*sp - 'a') + 10;
   else
    ereturn(escontext, (Datum) 0,
      (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
       errmsg("\"%.*s\" is not a valid hexadecimal digit",
        pg_mblen_cstr(sp), sp)));

   if (bc)
   {
    *r++ |= x;
    bc = 0;
   }
   else
   {
    *r = x << 4;
    bc = 1;
   }
  }
 }

 PG_RETURN_VARBIT_P(result);
}

/*
 * varbit_out -
 *   Prints the string as bits to preserve length accurately
 *
 * XXX varbit_recv() and hex input to varbit_in() can load a value that this
 * cannot emit.  Consider using hex output for such values.
 */

Datum
varbit_out(PG_FUNCTION_ARGS)
{
 VarBit    *s = PG_GETARG_VARBIT_P(0);
 char    *result,
      *r;
 bits8    *sp;
 bits8  x;
 int   i,
    k,
    len;

 /* Assertion to help catch any bit functions that don't pad correctly */
 VARBIT_CORRECTLY_PADDED(s);

 len = VARBITLEN(s);
 result = (char *) palloc(len + 1);
 sp = VARBITS(s);
 r = result;
 for (i = 0; i <= len - BITS_PER_BYTE; i += BITS_PER_BYTE, sp++)
 {
  /* print full bytes */
  x = *sp;
  for (k = 0; k < BITS_PER_BYTE; k++)
  {
   *r++ = IS_HIGHBIT_SET(x) ? '1' : '0';
   x <<= 1;
  }
 }
 if (i < len)
 {
  /* print the last partial byte */
  x = *sp;
  for (k = i; k < len; k++)
  {
   *r++ = IS_HIGHBIT_SET(x) ? '1' : '0';
   x <<= 1;
  }
 }
 *r = '\0';

 PG_RETURN_CSTRING(result);
}

/*
 *  varbit_recv   - converts external binary format to varbit
 *
 * External format is the bitlen as an int32, then the byte array.
 */

Datum
varbit_recv(PG_FUNCTION_ARGS)
{
 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);

#ifdef NOT_USED
 Oid   typelem = PG_GETARG_OID(1);
#endif
 int32  atttypmod = PG_GETARG_INT32(2);
 VarBit    *result;
 int   len,
    bitlen;

 bitlen = pq_getmsgint(buf, sizeof(int32));
 if (bitlen < 0 || bitlen > VARBITMAXLEN)
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
     errmsg("invalid length in external bit string")));

 /*
  * Sometimes atttypmod is not supplied. If it is supplied we need to make
  * sure that the bitstring fits.
 */

 if (atttypmod > 0 && bitlen > atttypmod)
  ereport(ERROR,
    (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
     errmsg("bit string too long for type bit varying(%d)",
      atttypmod)));

 len = VARBITTOTALLEN(bitlen);
 result = (VarBit *) palloc(len);
 SET_VARSIZE(result, len);
 VARBITLEN(result) = bitlen;

 pq_copymsgbytes(buf, VARBITS(result), VARBITBYTES(result));

 /* Make sure last byte is correctly zero-padded */
 VARBIT_PAD(result);

 PG_RETURN_VARBIT_P(result);
}

/*
 *  varbit_send   - converts varbit to binary format
 */

Datum
varbit_send(PG_FUNCTION_ARGS)
{
 VarBit    *s = PG_GETARG_VARBIT_P(0);
 StringInfoData buf;

 pq_begintypsend(&buf);
 pq_sendint32(&buf, VARBITLEN(s));
 pq_sendbytes(&buf, VARBITS(s), VARBITBYTES(s));
 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

/*
 * varbit_support()
 *
 * Planner support function for the varbit() length coercion function.
 *
 * Currently, the only interesting thing we can do is flatten calls that set
 * the new maximum length >= the previous maximum length.  We can ignore the
 * isExplicit argument, since that only affects truncation cases.
 */

Datum
varbit_support(PG_FUNCTION_ARGS)
{
 Node    *rawreq = (Node *) PG_GETARG_POINTER(0);
 Node    *ret = NULL;

 if (IsA(rawreq, SupportRequestSimplify))
 {
  SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
  FuncExpr   *expr = req->fcall;
  Node    *typmod;

  Assert(list_length(expr->args) >= 2);

  typmod = (Node *) lsecond(expr->args);

  if (IsA(typmod, Const) && !((Const *) typmod)->constisnull)
  {
   Node    *source = (Node *) linitial(expr->args);
   int32  new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
   int32  old_max = exprTypmod(source);
   int32  new_max = new_typmod;

   /* Note: varbit() treats typmod 0 as invalid, so we do too */
   if (new_max <= 0 || (old_max > 0 && old_max <= new_max))
    ret = relabel_to_typmod(source, new_typmod);
  }
 }

 PG_RETURN_POINTER(ret);
}

/*
 * varbit()
 * Converts a varbit() type to a specific internal length.
 * len is the maximum bitlength specified in the column definition.
 *
 * If doing implicit cast, raise error when source data is too long.
 * If doing explicit cast, silently truncate to max length.
 */

Datum
varbit(PG_FUNCTION_ARGS)
{
 VarBit    *arg = PG_GETARG_VARBIT_P(0);
 int32  len = PG_GETARG_INT32(1);
 bool  isExplicit = PG_GETARG_BOOL(2);
 VarBit    *result;
 int   rlen;

 /* No work if typmod is invalid or supplied data matches it already */
 if (len <= 0 || len >= VARBITLEN(arg))
  PG_RETURN_VARBIT_P(arg);

 if (!isExplicit)
  ereport(ERROR,
    (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
     errmsg("bit string too long for type bit varying(%d)",
      len)));

 rlen = VARBITTOTALLEN(len);
 result = (VarBit *) palloc(rlen);
 SET_VARSIZE(result, rlen);
 VARBITLEN(result) = len;

 memcpy(VARBITS(result), VARBITS(arg), VARBITBYTES(result));

 /* Make sure last byte is correctly zero-padded */
 VARBIT_PAD(result);

 PG_RETURN_VARBIT_P(result);
}

Datum
varbittypmodin(PG_FUNCTION_ARGS)
{
 ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);

 PG_RETURN_INT32(anybit_typmodin(ta, "varbit"));
}

Datum
varbittypmodout(PG_FUNCTION_ARGS)
{
 int32  typmod = PG_GETARG_INT32(0);

 PG_RETURN_CSTRING(anybit_typmodout(typmod));
}


/*
 * Comparison operators
 *
 * We only need one set of comparison operators for bitstrings, as the lengths
 * are stored in the same way for zero-padded and varying bit strings.
 *
 * Note that the standard is not unambiguous about the comparison between
 * zero-padded bit strings and varying bitstrings. If the same value is written
 * into a zero padded bitstring as into a varying bitstring, but the zero
 * padded bitstring has greater length, it will be bigger.
 *
 * Zeros from the beginning of a bitstring cannot simply be ignored, as they
 * may be part of a bit string and may be significant.
 *
 * Note: btree indexes need these routines not to leak memory; therefore,
 * be careful to free working copies of toasted datums.  Most places don't
 * need to be so careful.
 */


/*
 * bit_cmp
 *
 * Compares two bitstrings and returns <0, 0, >0 depending on whether the first
 * string is smaller, equal, or bigger than the second. All bits are considered
 * and additional zero bits may make one string smaller/larger than the other,
 * even if their zero-padded values would be the same.
 */

static int32
bit_cmp(VarBit *arg1, VarBit *arg2)
{
 int   bitlen1,
    bytelen1,
    bitlen2,
    bytelen2;
 int32  cmp;

 bytelen1 = VARBITBYTES(arg1);
 bytelen2 = VARBITBYTES(arg2);

 cmp = memcmp(VARBITS(arg1), VARBITS(arg2), Min(bytelen1, bytelen2));
 if (cmp == 0)
 {
  bitlen1 = VARBITLEN(arg1);
  bitlen2 = VARBITLEN(arg2);
  if (bitlen1 != bitlen2)
   cmp = (bitlen1 < bitlen2) ? -1 : 1;
 }
 return cmp;
}

Datum
biteq(PG_FUNCTION_ARGS)
{
 VarBit    *arg1 = PG_GETARG_VARBIT_P(0);
 VarBit    *arg2 = PG_GETARG_VARBIT_P(1);
 bool  result;
 int   bitlen1,
    bitlen2;

 bitlen1 = VARBITLEN(arg1);
 bitlen2 = VARBITLEN(arg2);

 /* fast path for different-length inputs */
 if (bitlen1 != bitlen2)
  result = false;
 else
  result = (bit_cmp(arg1, arg2) == 0);

 PG_FREE_IF_COPY(arg1, 0);
 PG_FREE_IF_COPY(arg2, 1);

 PG_RETURN_BOOL(result);
}

Datum
bitne(PG_FUNCTION_ARGS)
{
 VarBit    *arg1 = PG_GETARG_VARBIT_P(0);
 VarBit    *arg2 = PG_GETARG_VARBIT_P(1);
 bool  result;
 int   bitlen1,
    bitlen2;

 bitlen1 = VARBITLEN(arg1);
 bitlen2 = VARBITLEN(arg2);

 /* fast path for different-length inputs */
 if (bitlen1 != bitlen2)
  result = true;
 else
  result = (bit_cmp(arg1, arg2) != 0);

 PG_FREE_IF_COPY(arg1, 0);
 PG_FREE_IF_COPY(arg2, 1);

 PG_RETURN_BOOL(result);
}

Datum
bitlt(PG_FUNCTION_ARGS)
{
 VarBit    *arg1 = PG_GETARG_VARBIT_P(0);
 VarBit    *arg2 = PG_GETARG_VARBIT_P(1);
 bool  result;

 result = (bit_cmp(arg1, arg2) < 0);

 PG_FREE_IF_COPY(arg1, 0);
 PG_FREE_IF_COPY(arg2, 1);

 PG_RETURN_BOOL(result);
}

Datum
bitle(PG_FUNCTION_ARGS)
{
 VarBit    *arg1 = PG_GETARG_VARBIT_P(0);
 VarBit    *arg2 = PG_GETARG_VARBIT_P(1);
 bool  result;

 result = (bit_cmp(arg1, arg2) <= 0);

 PG_FREE_IF_COPY(arg1, 0);
 PG_FREE_IF_COPY(arg2, 1);

 PG_RETURN_BOOL(result);
}

Datum
bitgt(PG_FUNCTION_ARGS)
{
 VarBit    *arg1 = PG_GETARG_VARBIT_P(0);
 VarBit    *arg2 = PG_GETARG_VARBIT_P(1);
 bool  result;

 result = (bit_cmp(arg1, arg2) > 0);

 PG_FREE_IF_COPY(arg1, 0);
 PG_FREE_IF_COPY(arg2, 1);

 PG_RETURN_BOOL(result);
}

Datum
bitge(PG_FUNCTION_ARGS)
{
 VarBit    *arg1 = PG_GETARG_VARBIT_P(0);
 VarBit    *arg2 = PG_GETARG_VARBIT_P(1);
 bool  result;

 result = (bit_cmp(arg1, arg2) >= 0);

 PG_FREE_IF_COPY(arg1, 0);
 PG_FREE_IF_COPY(arg2, 1);

 PG_RETURN_BOOL(result);
}

Datum
bitcmp(PG_FUNCTION_ARGS)
{
 VarBit    *arg1 = PG_GETARG_VARBIT_P(0);
 VarBit    *arg2 = PG_GETARG_VARBIT_P(1);
 int32  result;

 result = bit_cmp(arg1, arg2);

 PG_FREE_IF_COPY(arg1, 0);
 PG_FREE_IF_COPY(arg2, 1);

 PG_RETURN_INT32(result);
}

/*
 * bitcat
 * Concatenation of bit strings
 */

Datum
bitcat(PG_FUNCTION_ARGS)
{
 VarBit    *arg1 = PG_GETARG_VARBIT_P(0);
 VarBit    *arg2 = PG_GETARG_VARBIT_P(1);

 PG_RETURN_VARBIT_P(bit_catenate(arg1, arg2));
}

static VarBit *
bit_catenate(VarBit *arg1, VarBit *arg2)
{
 VarBit    *result;
 int   bitlen1,
    bitlen2,
    bytelen,
    bit1pad,
    bit2shift;
 bits8    *pr,
      *pa;

 bitlen1 = VARBITLEN(arg1);
 bitlen2 = VARBITLEN(arg2);

 if (bitlen1 > VARBITMAXLEN - bitlen2)
  ereport(ERROR,
    (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     errmsg("bit string length exceeds the maximum allowed (%d)",
      VARBITMAXLEN)));
 bytelen = VARBITTOTALLEN(bitlen1 + bitlen2);

 result = (VarBit *) palloc(bytelen);
 SET_VARSIZE(result, bytelen);
 VARBITLEN(result) = bitlen1 + bitlen2;

 /* Copy the first bitstring in */
 memcpy(VARBITS(result), VARBITS(arg1), VARBITBYTES(arg1));

 /* Copy the second bit string */
 bit1pad = VARBITPAD(arg1);
 if (bit1pad == 0)
 {
  memcpy(VARBITS(result) + VARBITBYTES(arg1), VARBITS(arg2),
      VARBITBYTES(arg2));
 }
 else if (bitlen2 > 0)
 {
  /* We need to shift all the bits to fit */
  bit2shift = BITS_PER_BYTE - bit1pad;
  pr = VARBITS(result) + VARBITBYTES(arg1) - 1;
  for (pa = VARBITS(arg2); pa < VARBITEND(arg2); pa++)
  {
   *pr |= ((*pa >> bit2shift) & BITMASK);
   pr++;
   if (pr < VARBITEND(result))
    *pr = (*pa << bit1pad) & BITMASK;
  }
 }

 /* The pad bits should be already zero at this point */

 return result;
}

/*
 * bitsubstr
 * retrieve a substring from the bit string.
 * Note, s is 1-based.
 * SQL draft 6.10 9)
 */

Datum
bitsubstr(PG_FUNCTION_ARGS)
{
 PG_RETURN_VARBIT_P(bitsubstring(PG_GETARG_VARBIT_P(0),
         PG_GETARG_INT32(1),
         PG_GETARG_INT32(2),
         false));
}

Datum
bitsubstr_no_len(PG_FUNCTION_ARGS)
{
 PG_RETURN_VARBIT_P(bitsubstring(PG_GETARG_VARBIT_P(0),
         PG_GETARG_INT32(1),
         -1true));
}

static VarBit *
bitsubstring(VarBit *arg, int32 s, int32 l, bool length_not_specified)
{
 VarBit    *result;
 int   bitlen,
    rbitlen,
    len,
    ishift,
    i;
 int32  e,
    s1,
    e1;
 bits8    *r,
      *ps;

 bitlen = VARBITLEN(arg);
 s1 = Max(s, 1);
 /* If we do not have an upper bound, use end of string */
 if (length_not_specified)
 {
  e1 = bitlen + 1;
 }
 else if (l < 0)
 {
  /* SQL99 says to throw an error for E < S, i.e., negative length */
  ereport(ERROR,
    (errcode(ERRCODE_SUBSTRING_ERROR),
     errmsg("negative substring length not allowed")));
  e1 = -1;    /* silence stupider compilers */
 }
 else if (pg_add_s32_overflow(s, l, &e))
 {
  /*
   * L could be large enough for S + L to overflow, in which case the
   * substring must run to end of string.
 */

  e1 = bitlen + 1;
 }
 else
 {
  e1 = Min(e, bitlen + 1);
 }
 if (s1 > bitlen || e1 <= s1)
 {
  /* Need to return a zero-length bitstring */
  len = VARBITTOTALLEN(0);
  result = (VarBit *) palloc(len);
  SET_VARSIZE(result, len);
  VARBITLEN(result) = 0;
 }
 else
 {
  /*
   * OK, we've got a true substring starting at position s1-1 and ending
   * at position e1-1
 */

  rbitlen = e1 - s1;
  len = VARBITTOTALLEN(rbitlen);
  result = (VarBit *) palloc(len);
  SET_VARSIZE(result, len);
  VARBITLEN(result) = rbitlen;
  len -= VARHDRSZ + VARBITHDRSZ;
  /* Are we copying from a byte boundary? */
  if ((s1 - 1) % BITS_PER_BYTE == 0)
  {
   /* Yep, we are copying bytes */
   memcpy(VARBITS(result), VARBITS(arg) + (s1 - 1) / BITS_PER_BYTE,
       len);
  }
  else
  {
   /* Figure out how much we need to shift the sequence by */
   ishift = (s1 - 1) % BITS_PER_BYTE;
   r = VARBITS(result);
   ps = VARBITS(arg) + (s1 - 1) / BITS_PER_BYTE;
   for (i = 0; i < len; i++)
   {
    *r = (*ps << ishift) & BITMASK;
    if ((++ps) < VARBITEND(arg))
     *r |= *ps >> (BITS_PER_BYTE - ishift);
    r++;
   }
  }

  /* Make sure last byte is correctly zero-padded */
  VARBIT_PAD(result);
 }

 return result;
}

/*
 * bitoverlay
 * Replace specified substring of first string with second
 *
 * The SQL standard defines OVERLAY() in terms of substring and concatenation.
 * This code is a direct implementation of what the standard says.
 */

Datum
bitoverlay(PG_FUNCTION_ARGS)
{
 VarBit    *t1 = PG_GETARG_VARBIT_P(0);
 VarBit    *t2 = PG_GETARG_VARBIT_P(1);
 int   sp = PG_GETARG_INT32(2); /* substring start position */
 int   sl = PG_GETARG_INT32(3); /* substring length */

 PG_RETURN_VARBIT_P(bit_overlay(t1, t2, sp, sl));
}

Datum
bitoverlay_no_len(PG_FUNCTION_ARGS)
{
 VarBit    *t1 = PG_GETARG_VARBIT_P(0);
 VarBit    *t2 = PG_GETARG_VARBIT_P(1);
 int   sp = PG_GETARG_INT32(2); /* substring start position */
 int   sl;

 sl = VARBITLEN(t2);   /* defaults to length(t2) */
 PG_RETURN_VARBIT_P(bit_overlay(t1, t2, sp, sl));
}

static VarBit *
bit_overlay(VarBit *t1, VarBit *t2, int sp, int sl)
{
 VarBit    *result;
 VarBit    *s1;
 VarBit    *s2;
 int   sp_pl_sl;

 /*
  * Check for possible integer-overflow cases.  For negative sp, throw a
  * "substring length" error because that's what should be expected
  * according to the spec's definition of OVERLAY().
 */

 if (sp <= 0)
  ereport(ERROR,
    (errcode(ERRCODE_SUBSTRING_ERROR),
     errmsg("negative substring length not allowed")));
 if (pg_add_s32_overflow(sp, sl, &sp_pl_sl))
  ereport(ERROR,
    (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     errmsg("integer out of range")));

 s1 = bitsubstring(t1, 1, sp - 1false);
 s2 = bitsubstring(t1, sp_pl_sl, -1true);
 result = bit_catenate(s1, t2);
 result = bit_catenate(result, s2);

 return result;
}

/*
 * bit_count
 *
 * Returns the number of bits set in a bit string.
 */

Datum
bit_bit_count(PG_FUNCTION_ARGS)
{
 VarBit    *arg = PG_GETARG_VARBIT_P(0);

 PG_RETURN_INT64(pg_popcount((char *) VARBITS(arg), VARBITBYTES(arg)));
}

/*
 * bitlength, bitoctetlength
 * Return the length of a bit string
 */

Datum
bitlength(PG_FUNCTION_ARGS)
{
 VarBit    *arg = PG_GETARG_VARBIT_P(0);

 PG_RETURN_INT32(VARBITLEN(arg));
}

Datum
bitoctetlength(PG_FUNCTION_ARGS)
{
 VarBit    *arg = PG_GETARG_VARBIT_P(0);

 PG_RETURN_INT32(VARBITBYTES(arg));
}

/*
 * bit_and
 * perform a logical AND on two bit strings.
 */

Datum
bit_and(PG_FUNCTION_ARGS)
{
 VarBit    *arg1 = PG_GETARG_VARBIT_P(0);
 VarBit    *arg2 = PG_GETARG_VARBIT_P(1);
 VarBit    *result;
 int   len,
    bitlen1,
    bitlen2,
    i;
 bits8    *p1,
      *p2,
      *r;

 bitlen1 = VARBITLEN(arg1);
 bitlen2 = VARBITLEN(arg2);
 if (bitlen1 != bitlen2)
  ereport(ERROR,
    (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
     errmsg("cannot AND bit strings of different sizes")));

 len = VARSIZE(arg1);
 result = (VarBit *) palloc(len);
 SET_VARSIZE(result, len);
 VARBITLEN(result) = bitlen1;

 p1 = VARBITS(arg1);
 p2 = VARBITS(arg2);
 r = VARBITS(result);
 for (i = 0; i < VARBITBYTES(arg1); i++)
  *r++ = *p1++ & *p2++;

 /* Padding is not needed as & of 0 pads is 0 */

 PG_RETURN_VARBIT_P(result);
}

/*
 * bit_or
 * perform a logical OR on two bit strings.
 */

Datum
bit_or(PG_FUNCTION_ARGS)
{
 VarBit    *arg1 = PG_GETARG_VARBIT_P(0);
 VarBit    *arg2 = PG_GETARG_VARBIT_P(1);
 VarBit    *result;
 int   len,
    bitlen1,
    bitlen2,
    i;
 bits8    *p1,
      *p2,
      *r;

 bitlen1 = VARBITLEN(arg1);
 bitlen2 = VARBITLEN(arg2);
 if (bitlen1 != bitlen2)
  ereport(ERROR,
    (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
     errmsg("cannot OR bit strings of different sizes")));
 len = VARSIZE(arg1);
 result = (VarBit *) palloc(len);
 SET_VARSIZE(result, len);
 VARBITLEN(result) = bitlen1;

 p1 = VARBITS(arg1);
 p2 = VARBITS(arg2);
 r = VARBITS(result);
 for (i = 0; i < VARBITBYTES(arg1); i++)
  *r++ = *p1++ | *p2++;

 /* Padding is not needed as | of 0 pads is 0 */

 PG_RETURN_VARBIT_P(result);
}

/*
 * bitxor
 * perform a logical XOR on two bit strings.
 */

Datum
bitxor(PG_FUNCTION_ARGS)
{
 VarBit    *arg1 = PG_GETARG_VARBIT_P(0);
 VarBit    *arg2 = PG_GETARG_VARBIT_P(1);
 VarBit    *result;
 int   len,
    bitlen1,
    bitlen2,
    i;
 bits8    *p1,
      *p2,
      *r;

 bitlen1 = VARBITLEN(arg1);
 bitlen2 = VARBITLEN(arg2);
 if (bitlen1 != bitlen2)
  ereport(ERROR,
    (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
     errmsg("cannot XOR bit strings of different sizes")));

 len = VARSIZE(arg1);
 result = (VarBit *) palloc(len);
 SET_VARSIZE(result, len);
 VARBITLEN(result) = bitlen1;

 p1 = VARBITS(arg1);
 p2 = VARBITS(arg2);
 r = VARBITS(result);
 for (i = 0; i < VARBITBYTES(arg1); i++)
  *r++ = *p1++ ^ *p2++;

 /* Padding is not needed as ^ of 0 pads is 0 */

 PG_RETURN_VARBIT_P(result);
}

/*
 * bitnot
 * perform a logical NOT on a bit string.
 */

Datum
bitnot(PG_FUNCTION_ARGS)
{
 VarBit    *arg = PG_GETARG_VARBIT_P(0);
 VarBit    *result;
 bits8    *p,
      *r;

 result = (VarBit *) palloc(VARSIZE(arg));
 SET_VARSIZE(result, VARSIZE(arg));
 VARBITLEN(result) = VARBITLEN(arg);

 p = VARBITS(arg);
 r = VARBITS(result);
 for (; p < VARBITEND(arg); p++)
  *r++ = ~*p;

 /* Must zero-pad the result, because extra bits are surely 1's here */
 VARBIT_PAD_LAST(result, r);

 PG_RETURN_VARBIT_P(result);
}

/*
 * bitshiftleft
 * do a left shift (i.e. towards the beginning of the string)
 */

Datum
bitshiftleft(PG_FUNCTION_ARGS)
{
 VarBit    *arg = PG_GETARG_VARBIT_P(0);
 int32  shft = PG_GETARG_INT32(1);
 VarBit    *result;
 int   byte_shift,
    ishift,
    len;
 bits8    *p,
      *r;

 /* Negative shift is a shift to the right */
 if (shft < 0)
 {
  /* Prevent integer overflow in negation */
  if (shft < -VARBITMAXLEN)
   shft = -VARBITMAXLEN;
  PG_RETURN_DATUM(DirectFunctionCall2(bitshiftright,
           VarBitPGetDatum(arg),
           Int32GetDatum(-shft)));
 }

 result = (VarBit *) palloc(VARSIZE(arg));
 SET_VARSIZE(result, VARSIZE(arg));
 VARBITLEN(result) = VARBITLEN(arg);
 r = VARBITS(result);

 /* If we shifted all the bits out, return an all-zero string */
 if (shft >= VARBITLEN(arg))
 {
  MemSet(r, 0, VARBITBYTES(arg));
  PG_RETURN_VARBIT_P(result);
 }

 byte_shift = shft / BITS_PER_BYTE;
 ishift = shft % BITS_PER_BYTE;
 p = VARBITS(arg) + byte_shift;

 if (ishift == 0)
 {
  /* Special case: we can do a memcpy */
  len = VARBITBYTES(arg) - byte_shift;
  memcpy(r, p, len);
  MemSet(r + len, 0, byte_shift);
 }
 else
 {
  for (; p < VARBITEND(arg); r++)
  {
   *r = *p << ishift;
   if ((++p) < VARBITEND(arg))
    *r |= *p >> (BITS_PER_BYTE - ishift);
  }
  for (; r < VARBITEND(result); r++)
   *r = 0;
 }

 /* The pad bits should be already zero at this point */

 PG_RETURN_VARBIT_P(result);
}

/*
 * bitshiftright
 * do a right shift (i.e. towards the end of the string)
 */

Datum
bitshiftright(PG_FUNCTION_ARGS)
{
 VarBit    *arg = PG_GETARG_VARBIT_P(0);
 int32  shft = PG_GETARG_INT32(1);
 VarBit    *result;
 int   byte_shift,
    ishift,
    len;
 bits8    *p,
      *r;

 /* Negative shift is a shift to the left */
 if (shft < 0)
 {
  /* Prevent integer overflow in negation */
  if (shft < -VARBITMAXLEN)
   shft = -VARBITMAXLEN;
  PG_RETURN_DATUM(DirectFunctionCall2(bitshiftleft,
           VarBitPGetDatum(arg),
           Int32GetDatum(-shft)));
 }

 result = (VarBit *) palloc(VARSIZE(arg));
 SET_VARSIZE(result, VARSIZE(arg));
 VARBITLEN(result) = VARBITLEN(arg);
 r = VARBITS(result);

 /* If we shifted all the bits out, return an all-zero string */
 if (shft >= VARBITLEN(arg))
 {
  MemSet(r, 0, VARBITBYTES(arg));
  PG_RETURN_VARBIT_P(result);
 }

 byte_shift = shft / BITS_PER_BYTE;
 ishift = shft % BITS_PER_BYTE;
 p = VARBITS(arg);

 /* Set the first part of the result to 0 */
 MemSet(r, 0, byte_shift);
 r += byte_shift;

 if (ishift == 0)
 {
  /* Special case: we can do a memcpy */
  len = VARBITBYTES(arg) - byte_shift;
  memcpy(r, p, len);
  r += len;
 }
 else
 {
  if (r < VARBITEND(result))
   *r = 0;    /* initialize first byte */
  for (; r < VARBITEND(result); p++)
  {
   *r |= *p >> ishift;
   if ((++r) < VARBITEND(result))
    *r = (*p << (BITS_PER_BYTE - ishift)) & BITMASK;
  }
 }

 /* We may have shifted 1's into the pad bits, so fix that */
 VARBIT_PAD_LAST(result, r);

 PG_RETURN_VARBIT_P(result);
}

/*
 * This is not defined in any standard. We retain the natural ordering of
 * bits here, as it just seems more intuitive.
 */

Datum
bitfromint4(PG_FUNCTION_ARGS)
{
 int32  a = PG_GETARG_INT32(0);
 int32  typmod = PG_GETARG_INT32(1);
 VarBit    *result;
 bits8    *r;
 int   rlen;
 int   destbitsleft,
    srcbitsleft;

 if (typmod <= 0 || typmod > VARBITMAXLEN)
  typmod = 1;    /* default bit length */

 rlen = VARBITTOTALLEN(typmod);
 result = (VarBit *) palloc(rlen);
 SET_VARSIZE(result, rlen);
 VARBITLEN(result) = typmod;

 r = VARBITS(result);
 destbitsleft = typmod;
 srcbitsleft = 32;
 /* drop any input bits that don't fit */
 srcbitsleft = Min(srcbitsleft, destbitsleft);
 /* sign-fill any excess bytes in output */
 while (destbitsleft >= srcbitsleft + 8)
 {
  *r++ = (bits8) ((a < 0) ? BITMASK : 0);
  destbitsleft -= 8;
 }
 /* store first fractional byte */
 if (destbitsleft > srcbitsleft)
 {
  unsigned int val = (unsigned int) (a >> (destbitsleft - 8));

  /* Force sign-fill in case the compiler implements >> as zero-fill */
  if (a < 0)
   val |= ((unsigned int) -1) << (srcbitsleft + 8 - destbitsleft);
  *r++ = (bits8) (val & BITMASK);
  destbitsleft -= 8;
 }
 /* Now srcbitsleft and destbitsleft are the same, need not track both */
 /* store whole bytes */
 while (destbitsleft >= 8)
 {
  *r++ = (bits8) ((a >> (destbitsleft - 8)) & BITMASK);
  destbitsleft -= 8;
 }
 /* store last fractional byte */
 if (destbitsleft > 0)
  *r = (bits8) ((a << (8 - destbitsleft)) & BITMASK);

 PG_RETURN_VARBIT_P(result);
}

Datum
bittoint4(PG_FUNCTION_ARGS)
{
 VarBit    *arg = PG_GETARG_VARBIT_P(0);
 uint32  result;
 bits8    *r;

 /* Check that the bit string is not too long */
 if (VARBITLEN(arg) > sizeof(result) * BITS_PER_BYTE)
  ereport(ERROR,
    (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     errmsg("integer out of range")));

 result = 0;
 for (r = VARBITS(arg); r < VARBITEND(arg); r++)
 {
  result <<= BITS_PER_BYTE;
  result |= *r;
 }
 /* Now shift the result to take account of the padding at the end */
 result >>= VARBITPAD(arg);

 PG_RETURN_INT32(result);
}

Datum
bitfromint8(PG_FUNCTION_ARGS)
{
 int64  a = PG_GETARG_INT64(0);
 int32  typmod = PG_GETARG_INT32(1);
 VarBit    *result;
 bits8    *r;
 int   rlen;
 int   destbitsleft,
    srcbitsleft;

 if (typmod <= 0 || typmod > VARBITMAXLEN)
  typmod = 1;    /* default bit length */

 rlen = VARBITTOTALLEN(typmod);
 result = (VarBit *) palloc(rlen);
 SET_VARSIZE(result, rlen);
 VARBITLEN(result) = typmod;

 r = VARBITS(result);
 destbitsleft = typmod;
 srcbitsleft = 64;
 /* drop any input bits that don't fit */
 srcbitsleft = Min(srcbitsleft, destbitsleft);
 /* sign-fill any excess bytes in output */
 while (destbitsleft >= srcbitsleft + 8)
 {
  *r++ = (bits8) ((a < 0) ? BITMASK : 0);
  destbitsleft -= 8;
 }
 /* store first fractional byte */
 if (destbitsleft > srcbitsleft)
 {
  unsigned int val = (unsigned int) (a >> (destbitsleft - 8));

  /* Force sign-fill in case the compiler implements >> as zero-fill */
  if (a < 0)
   val |= ((unsigned int) -1) << (srcbitsleft + 8 - destbitsleft);
  *r++ = (bits8) (val & BITMASK);
  destbitsleft -= 8;
 }
 /* Now srcbitsleft and destbitsleft are the same, need not track both */
 /* store whole bytes */
 while (destbitsleft >= 8)
 {
  *r++ = (bits8) ((a >> (destbitsleft - 8)) & BITMASK);
  destbitsleft -= 8;
 }
 /* store last fractional byte */
 if (destbitsleft > 0)
  *r = (bits8) ((a << (8 - destbitsleft)) & BITMASK);

 PG_RETURN_VARBIT_P(result);
}

Datum
bittoint8(PG_FUNCTION_ARGS)
{
 VarBit    *arg = PG_GETARG_VARBIT_P(0);
 uint64  result;
 bits8    *r;

 /* Check that the bit string is not too long */
 if (VARBITLEN(arg) > sizeof(result) * BITS_PER_BYTE)
  ereport(ERROR,
    (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     errmsg("bigint out of range")));

 result = 0;
 for (r = VARBITS(arg); r < VARBITEND(arg); r++)
 {
  result <<= BITS_PER_BYTE;
  result |= *r;
 }
 /* Now shift the result to take account of the padding at the end */
 result >>= VARBITPAD(arg);

 PG_RETURN_INT64(result);
}


/*
 * Determines the position of S2 in the bitstring S1 (1-based string).
 * If S2 does not appear in S1 this function returns 0.
 * If S2 is of length 0 this function returns 1.
 * Compatible in usage with POSITION() functions for other data types.
 */

Datum
bitposition(PG_FUNCTION_ARGS)
{
 VarBit    *str = PG_GETARG_VARBIT_P(0);
 VarBit    *substr = PG_GETARG_VARBIT_P(1);
 int   substr_length,
    str_length,
    i,
    is;
 bits8    *s,    /* pointer into substring */
      *p;    /* pointer into str */
 bits8  cmp,   /* shifted substring byte to compare */
    mask1,   /* mask for substring byte shifted right */
    mask2,   /* mask for substring byte shifted left */
    end_mask,  /* pad mask for last substring byte */
    str_mask;  /* pad mask for last string byte */
 bool  is_match;

 /* Get the substring length */
 substr_length = VARBITLEN(substr);
 str_length = VARBITLEN(str);

 /* String has zero length or substring longer than string, return 0 */
 if ((str_length == 0) || (substr_length > str_length))
  PG_RETURN_INT32(0);

 /* zero-length substring means return 1 */
 if (substr_length == 0)
  PG_RETURN_INT32(1);

 /* Initialise the padding masks */
 end_mask = BITMASK << VARBITPAD(substr);
 str_mask = BITMASK << VARBITPAD(str);
 for (i = 0; i < VARBITBYTES(str) - VARBITBYTES(substr) + 1; i++)
 {
  for (is = 0; is < BITS_PER_BYTE; is++)
  {
   is_match = true;
   p = VARBITS(str) + i;
   mask1 = BITMASK >> is;
   mask2 = ~mask1;
   for (s = VARBITS(substr);
     is_match && s < VARBITEND(substr); s++)
   {
    cmp = *s >> is;
    if (s == VARBITEND(substr) - 1)
    {
     mask1 &= end_mask >> is;
     if (p == VARBITEND(str) - 1)
     {
      /* Check that there is enough of str left */
      if (mask1 & ~str_mask)
      {
       is_match = false;
       break;
      }
      mask1 &= str_mask;
     }
    }
    is_match = ((cmp ^ *p) & mask1) == 0;
    if (!is_match)
     break;
    /* Move on to the next byte */
    p++;
    if (p == VARBITEND(str))
    {
     mask2 = end_mask << (BITS_PER_BYTE - is);
     is_match = mask2 == 0;
#if 0
     elog(DEBUG4, "S. %d %d em=%2x sm=%2x r=%d",
       i, is, end_mask, mask2, is_match);
#endif
     break;
    }
    cmp = *s << (BITS_PER_BYTE - is);
    if (s == VARBITEND(substr) - 1)
    {
     mask2 &= end_mask << (BITS_PER_BYTE - is);
     if (p == VARBITEND(str) - 1)
     {
      if (mask2 & ~str_mask)
      {
       is_match = false;
       break;
      }
      mask2 &= str_mask;
     }
    }
    is_match = ((cmp ^ *p) & mask2) == 0;
   }
   /* Have we found a match? */
   if (is_match)
    PG_RETURN_INT32(i * BITS_PER_BYTE + is + 1);
  }
 }
 PG_RETURN_INT32(0);
}


/*
 * bitsetbit
 *
 * Given an instance of type 'bit' creates a new one with
 * the Nth bit set to the given value.
 *
 * The bit location is specified left-to-right in a zero-based fashion
 * consistent with the other get_bit and set_bit functions, but
 * inconsistent with the standard substring, position, overlay functions
 */

Datum
bitsetbit(PG_FUNCTION_ARGS)
{
 VarBit    *arg1 = PG_GETARG_VARBIT_P(0);
 int32  n = PG_GETARG_INT32(1);
 int32  newBit = PG_GETARG_INT32(2);
 VarBit    *result;
 int   len,
    bitlen;
 bits8    *r,
      *p;
 int   byteNo,
    bitNo;

 bitlen = VARBITLEN(arg1);
 if (n < 0 || n >= bitlen)
  ereport(ERROR,
    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     errmsg("bit index %d out of valid range (0..%d)",
      n, bitlen - 1)));

 /*
  * sanity check!
 */

 if (newBit != 0 && newBit != 1)
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     errmsg("new bit must be 0 or 1")));

 len = VARSIZE(arg1);
 result = (VarBit *) palloc(len);
 SET_VARSIZE(result, len);
 VARBITLEN(result) = bitlen;

 p = VARBITS(arg1);
 r = VARBITS(result);

 memcpy(r, p, VARBITBYTES(arg1));

 byteNo = n / BITS_PER_BYTE;
 bitNo = BITS_PER_BYTE - 1 - (n % BITS_PER_BYTE);

 /*
  * Update the byte.
 */

 if (newBit == 0)
  r[byteNo] &= (~(1 << bitNo));
 else
  r[byteNo] |= (1 << bitNo);

 PG_RETURN_VARBIT_P(result);
}

/*
 * bitgetbit
 *
 * returns the value of the Nth bit of a bit array (0 or 1).
 *
 * The bit location is specified left-to-right in a zero-based fashion
 * consistent with the other get_bit and set_bit functions, but
 * inconsistent with the standard substring, position, overlay functions
 */

Datum
bitgetbit(PG_FUNCTION_ARGS)
{
 VarBit    *arg1 = PG_GETARG_VARBIT_P(0);
 int32  n = PG_GETARG_INT32(1);
 int   bitlen;
 bits8    *p;
 int   byteNo,
    bitNo;

 bitlen = VARBITLEN(arg1);
 if (n < 0 || n >= bitlen)
  ereport(ERROR,
    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     errmsg("bit index %d out of valid range (0..%d)",
      n, bitlen - 1)));

 p = VARBITS(arg1);

 byteNo = n / BITS_PER_BYTE;
 bitNo = BITS_PER_BYTE - 1 - (n % BITS_PER_BYTE);

 if (p[byteNo] & (1 << bitNo))
  PG_RETURN_INT32(1);
 else
  PG_RETURN_INT32(0);
}

Messung V0.5 in Prozent
C=94 H=93 G=93

¤ Dauer der Verarbeitung: 0.35 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.