summaryrefslogtreecommitdiffstats
path: root/src/backend/utils/adt/varbit.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:15:05 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:15:05 +0000
commit46651ce6fe013220ed397add242004d764fc0153 (patch)
tree6e5299f990f88e60174a1d3ae6e48eedd2688b2b /src/backend/utils/adt/varbit.c
parentInitial commit. (diff)
downloadpostgresql-14-upstream.tar.xz
postgresql-14-upstream.zip
Adding upstream version 14.5.upstream/14.5upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/backend/utils/adt/varbit.c')
-rw-r--r--src/backend/utils/adt/varbit.c1894
1 files changed, 1894 insertions, 0 deletions
diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c
new file mode 100644
index 0000000..0d0c0fd
--- /dev/null
+++ b/src/backend/utils/adt/varbit.c
@@ -0,0 +1,1894 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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-2021, 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/builtins.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) ((void) 0)
+#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);
+ 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)
+ ereport(ERROR,
+ (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)
+ ereport(ERROR,
+ (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')
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("\"%.*s\" is not a valid binary digit",
+ pg_mblen(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
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("\"%.*s\" is not a valid hexadecimal digit",
+ pg_mblen(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, (char *) 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);
+ 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)
+ ereport(ERROR,
+ (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)
+ ereport(ERROR,
+ (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')
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("\"%.*s\" is not a valid binary digit",
+ pg_mblen(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
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("\"%.*s\" is not a valid hexadecimal digit",
+ pg_mblen(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, (char *) 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, (char *) 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),
+ -1, true));
+}
+
+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 - 1, false);
+ s2 = bitsubstring(t1, sp_pl_sl, -1, true);
+ 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);
+}