diff options
Diffstat (limited to 'src/backend/utils/adt/varbit.c')
-rw-r--r-- | src/backend/utils/adt/varbit.c | 1227 |
1 files changed, 0 insertions, 1227 deletions
diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c deleted file mode 100644 index 2fad9aba048..00000000000 --- a/src/backend/utils/adt/varbit.c +++ /dev/null @@ -1,1227 +0,0 @@ -/*------------------------------------------------------------------------- - * - * varbit.c - * Functions for the SQL datatypes BIT() and BIT VARYING(). - * - * Code originally contributed by Adriaan Joubert. - * - * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.22 2002/06/20 20:29:38 momjian Exp $ - * - *------------------------------------------------------------------------- - */ - -#include "postgres.h" - -#include "catalog/pg_type.h" -#include "utils/array.h" -#include "utils/fmgroids.h" -#include "utils/memutils.h" -#include "utils/varbit.h" - -#define HEXDIG(z) ((z)<10 ? ((z)+'0') : ((z)-10+'A')) - - -/*---------- - * attypmod -- contains the length of the bit string in bits, or for - * varying bits the maximum length. - * - * 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 - *---------- - */ - -/* - * 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; - } - - slen = strlen(sp); - /* Determine bitlength from input string */ - if (bit_not_hex) - bitlen = slen; - else - 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) - elog(ERROR, "bit string length does not match type bit(%d)", - atttypmod); - - len = VARBITTOTALLEN(atttypmod); - result = (VarBit *) palloc(len); - /* set to 0 so that *r is always initialised and string is zero-padded */ - memset(result, 0, len); - VARATT_SIZEP(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 = BITHIGH; - for (; *sp; sp++) - { - if (*sp == '1') - *r |= x; - else if (*sp != '0') - elog(ERROR, "cannot parse %c as a binary digit", *sp); - x >>= 1; - if (x == 0) - { - x = BITHIGH; - 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 - elog(ERROR, "cannot parse %c as a hex digit", *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; - - 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() - * Converts a bit() type to a specific internal length. - * len is the bitlength specified in the column definition. - */ -Datum -bit(PG_FUNCTION_ARGS) -{ - VarBit *arg = PG_GETARG_VARBIT_P(0); - int32 len = PG_GETARG_INT32(1); - - /* No work if typmod is invalid or supplied data matches it already */ - if (len <= 0 || len == VARBITLEN(arg)) - PG_RETURN_VARBIT_P(arg); - else - elog(ERROR, "bit string length does not match type bit(%d)", - len); - return 0; /* quiet compiler */ -} - -/* _bit() - * Converts an array of bit() elements to a specific internal length. - * len is the bitlength specified in the column definition. - */ -Datum -_bit(PG_FUNCTION_ARGS) -{ - ArrayType *v = (ArrayType *) PG_GETARG_VARLENA_P(0); - int32 len = PG_GETARG_INT32(1); - FunctionCallInfoData locfcinfo; - - /* - * Since bit() is a built-in function, we should only need to look it - * up once per run. - */ - static FmgrInfo bit_finfo; - - if (bit_finfo.fn_oid == InvalidOid) - fmgr_info_cxt(F_BIT, &bit_finfo, TopMemoryContext); - - MemSet(&locfcinfo, 0, sizeof(locfcinfo)); - locfcinfo.flinfo = &bit_finfo; - locfcinfo.nargs = 2; - /* We assume we are "strict" and need not worry about null inputs */ - locfcinfo.arg[0] = PointerGetDatum(v); - locfcinfo.arg[1] = Int32GetDatum(len); - - return array_map(&locfcinfo, BITOID, BITOID); -} - -/* - * 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; - } - - slen = strlen(sp); - /* Determine bitlength from input string */ - if (bit_not_hex) - bitlen = slen; - else - 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) - elog(ERROR, "bit string too long for type bit varying(%d)", - atttypmod); - - len = VARBITTOTALLEN(bitlen); - result = (VarBit *) palloc(len); - /* set to 0 so that *r is always initialised and string is zero-padded */ - memset(result, 0, len); - VARATT_SIZEP(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 = BITHIGH; - for (; *sp; sp++) - { - if (*sp == '1') - *r |= x; - else if (*sp != '0') - elog(ERROR, "cannot parse %c as a binary digit", *sp); - x >>= 1; - if (x == 0) - { - x = BITHIGH; - 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 - elog(ERROR, "cannot parse %c as a hex digit", *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 - */ -Datum -varbit_out(PG_FUNCTION_ARGS) -{ - VarBit *s = PG_GETARG_VARBIT_P(0); - char *result, - *r; - bits8 *sp; - bits8 x; - int i, - k, - len; - - 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++) - { - x = *sp; - for (k = 0; k < BITS_PER_BYTE; k++) - { - *r++ = (x & BITHIGH) ? '1' : '0'; - x <<= 1; - } - } - x = *sp; - for (k = i; k < len; k++) - { - *r++ = (x & BITHIGH) ? '1' : '0'; - x <<= 1; - } - *r = '\0'; - - PG_RETURN_CSTRING(result); -} - -/* varbit() - * Converts a varbit() type to a specific internal length. - * len is the maximum bitlength specified in the column definition. - */ -Datum -varbit(PG_FUNCTION_ARGS) -{ - VarBit *arg = PG_GETARG_VARBIT_P(0); - int32 len = PG_GETARG_INT32(1); - 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 (len < VARBITLEN(arg)) - elog(ERROR, "bit string too long for type bit varying(%d)", len); - - rlen = VARBITTOTALLEN(len); - result = (VarBit *) palloc(rlen); - VARATT_SIZEP(result) = rlen; - VARBITLEN(result) = len; - - memcpy(VARBITS(result), VARBITS(arg), VARBITBYTES(result)); - - PG_RETURN_VARBIT_P(result); -} - -/* _varbit() - * Converts an array of bit() elements to a specific internal length. - * len is the maximum bitlength specified in the column definition. - */ -Datum -_varbit(PG_FUNCTION_ARGS) -{ - ArrayType *v = (ArrayType *) PG_GETARG_VARLENA_P(0); - int32 len = PG_GETARG_INT32(1); - FunctionCallInfoData locfcinfo; - - /* - * Since varbit() is a built-in function, we should only need to look - * it up once per run. - */ - static FmgrInfo varbit_finfo; - - if (varbit_finfo.fn_oid == InvalidOid) - fmgr_info_cxt(F_VARBIT, &varbit_finfo, TopMemoryContext); - - MemSet(&locfcinfo, 0, sizeof(locfcinfo)); - locfcinfo.flinfo = &varbit_finfo; - locfcinfo.nargs = 2; - /* We assume we are "strict" and need not worry about null inputs */ - locfcinfo.arg[0] = PointerGetDatum(v); - locfcinfo.arg[1] = Int32GetDatum(len); - - return array_map(&locfcinfo, VARBITOID, VARBITOID); -} - - -/* - * 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); - VarBit *result; - int bitlen1, - bitlen2, - bytelen, - bit1pad, - bit2shift; - bits8 *pr, - *pa; - - bitlen1 = VARBITLEN(arg1); - bitlen2 = VARBITLEN(arg2); - - bytelen = VARBITTOTALLEN(bitlen1 + bitlen2); - - result = (VarBit *) palloc(bytelen); - VARATT_SIZEP(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; - } - } - - PG_RETURN_VARBIT_P(result); -} - -/* bitsubstr - * retrieve a substring from the bit string. - * Note, s is 1-based. - * SQL draft 6.10 9) - */ -Datum -bitsubstr(PG_FUNCTION_ARGS) -{ - VarBit *arg = PG_GETARG_VARBIT_P(0); - int32 s = PG_GETARG_INT32(1); - int32 l = PG_GETARG_INT32(2); - VarBit *result; - int bitlen, - rbitlen, - len, - ipad = 0, - ishift, - i; - int e, - s1, - e1; - bits8 mask, - *r, - *ps; - - bitlen = VARBITLEN(arg); - /* If we do not have an upper bound, set bitlen */ - if (l == -1) - l = bitlen; - e = s + l; - s1 = Max(s, 1); - e1 = Min(e, bitlen + 1); - if (s1 > bitlen || e1 < 1) - { - /* Need to return a zero-length bitstring */ - len = VARBITTOTALLEN(0); - result = (VarBit *) palloc(len); - VARATT_SIZEP(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); - VARATT_SIZEP(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++; - } - } - /* Do we need to pad at the end? */ - ipad = VARBITPAD(result); - if (ipad > 0) - { - mask = BITMASK << ipad; - *(VARBITS(result) + len - 1) &= mask; - } - } - - PG_RETURN_VARBIT_P(result); -} - -/* 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)); -} - -/* bitand - * perform a logical AND on two bit strings. - */ -Datum -bitand(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) - elog(ERROR, "cannot AND bit strings of different sizes"); - len = VARSIZE(arg1); - result = (VarBit *) palloc(len); - VARATT_SIZEP(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 pad is 0 */ - - PG_RETURN_VARBIT_P(result); -} - -/* bitor - * perform a logical OR on two bit strings. - */ -Datum -bitor(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; - bits8 mask; - - bitlen1 = VARBITLEN(arg1); - bitlen2 = VARBITLEN(arg2); - if (bitlen1 != bitlen2) - elog(ERROR, "cannot OR bit strings of different sizes"); - len = VARSIZE(arg1); - result = (VarBit *) palloc(len); - VARATT_SIZEP(result) = len; - VARBITLEN(result) = bitlen1; - - p1 = VARBITS(arg1); - p2 = VARBITS(arg2); - r = VARBITS(result); - for (i = 0; i < VARBITBYTES(arg1); i++) - *r++ = *p1++ | *p2++; - - /* Pad the result */ - mask = BITMASK << VARBITPAD(result); - if (mask) - { - r--; - *r &= mask; - } - - 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; - bits8 mask; - - bitlen1 = VARBITLEN(arg1); - bitlen2 = VARBITLEN(arg2); - if (bitlen1 != bitlen2) - elog(ERROR, "cannot XOR bit strings of different sizes"); - len = VARSIZE(arg1); - result = (VarBit *) palloc(len); - VARATT_SIZEP(result) = len; - VARBITLEN(result) = bitlen1; - - p1 = VARBITS(arg1); - p2 = VARBITS(arg2); - r = VARBITS(result); - for (i = 0; i < VARBITBYTES(arg1); i++) - *r++ = *p1++ ^ *p2++; - - /* Pad the result */ - mask = BITMASK << VARBITPAD(result); - if (mask) - { - r--; - *r &= mask; - } - - 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; - bits8 mask; - - result = (VarBit *) palloc(VARSIZE(arg)); - VARATT_SIZEP(result) = VARSIZE(arg); - VARBITLEN(result) = VARBITLEN(arg); - - p = VARBITS(arg); - r = VARBITS(result); - for (; p < VARBITEND(arg); p++) - *r++ = ~*p; - - /* Pad the result */ - mask = BITMASK << VARBITPAD(result); - if (mask) - { - r--; - *r &= mask; - } - - 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) - PG_RETURN_DATUM(DirectFunctionCall2(bitshiftright, - VarBitPGetDatum(arg), - Int32GetDatum(-shft))); - - result = (VarBit *) palloc(VARSIZE(arg)); - VARATT_SIZEP(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; - } - - 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) - PG_RETURN_DATUM(DirectFunctionCall2(bitshiftleft, - VarBitPGetDatum(arg), - Int32GetDatum(-shft))); - - result = (VarBit *) palloc(VARSIZE(arg)); - VARATT_SIZEP(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); - } - 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; - } - } - - 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); - VarBit *result; - bits8 *r; - int len; - - /* allocate enough space for the bits in an int4 */ - len = VARBITTOTALLEN(sizeof(int4) * BITS_PER_BYTE); - result = (VarBit *) palloc(len); - VARATT_SIZEP(result) = len; - VARBITLEN(result) = sizeof(int4) * BITS_PER_BYTE; - - /* - * masks and shifts here are just too painful and we know that an int4 - * has got 4 bytes - */ - r = VARBITS(result); - r[0] = (bits8) ((a >> (3 * BITS_PER_BYTE)) & BITMASK); - r[1] = (bits8) ((a >> (2 * BITS_PER_BYTE)) & BITMASK); - r[2] = (bits8) ((a >> (1 * BITS_PER_BYTE)) & BITMASK); - r[3] = (bits8) (a & 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(int4) * BITS_PER_BYTE) - elog(ERROR, "bit string is too large to fit in type integer"); - 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); -} - - - -/* 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. - */ -Datum -bitposition(PG_FUNCTION_ARGS) -{ - VarBit *substr = PG_GETARG_VARBIT_P(1); - VarBit *arg = PG_GETARG_VARBIT_P(0); - int substr_length, - arg_length, - i, - is; - bits8 *s, /* pointer into substring */ - *p; /* pointer into arg */ - 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 */ - arg_mask; /* pad mask for last argument byte */ - bool is_match; - - /* Get the substring length */ - substr_length = VARBITLEN(substr); - arg_length = VARBITLEN(arg); - - /* Argument has 0 length or substring longer than argument, return 0 */ - if (arg_length == 0 || substr_length > arg_length) - PG_RETURN_INT32(0); - - /* 0-length means return 1 */ - if (substr_length == 0) - PG_RETURN_INT32(1); - - /* Initialise the padding masks */ - end_mask = BITMASK << VARBITPAD(substr); - arg_mask = BITMASK << VARBITPAD(arg); - for (i = 0; i < VARBITBYTES(arg) - VARBITBYTES(substr) + 1; i++) - { - for (is = 0; is < BITS_PER_BYTE; is++) - { - is_match = true; - p = VARBITS(arg) + 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(arg) - 1) - { - /* Check that there is enough of arg left */ - if (mask1 & ~arg_mask) - { - is_match = false; - break; - } - mask1 &= arg_mask; - } - } - is_match = ((cmp ^ *p) & mask1) == 0; - if (!is_match) - break; - /* Move on to the next byte */ - p++; - if (p == VARBITEND(arg)) - { - mask2 = end_mask << (BITS_PER_BYTE - is); - is_match = mask2 == 0; -#if 0 - elog(DEBUG3, "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(arg) - 1) - { - if (mask2 & ~arg_mask) - { - is_match = false; - break; - } - mask2 &= arg_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); -} |