/*------------------------------------------------------------------------- * * varbit.c * Functions for the SQL datatypes BIT() and BIT VARYING(). * * Code originally contributed by Adriaan Joubert. * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.9 2000/08/26 21:53:41 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "catalog/pg_type.h" #include "utils/array.h" #include "utils/fmgroids.h" #include "utils/varbit.h" #define HEXDIG(z) ((z)<10 ? ((z)+'0') : ((z)-10+'A')) /*---------- * Prefixes: * zp -- zero-padded fixed length bit string * var -- varying bit string * * 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 *---------- */ /* * zpbit_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 zpbit_in(PG_FUNCTION_ARGS) { char *s = 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, ipad; bits8 x = 0; /* Check that the first character is a b or an x */ if (s[0] == 'b' || s[0] == 'B') bit_not_hex = true; else if (s[0] == 'x' || s[0] == 'X') bit_not_hex = false; else { elog(ERROR, "zpbit_in: %s is not a valid bitstring", s); bit_not_hex = false; /* keep compiler quiet */ } slen = strlen(s) - 1; /* 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. Note that the number of infered * bits can be larger than the number of actual bits needed, but only * if we are reading a hex string and not by more than 3 bits, as a * hex string gives an accurate length up to 4 bits */ if (atttypmod <= 0) atttypmod = bitlen; else if (bit_not_hex ? (bitlen > atttypmod) : (bitlen > atttypmod + 3)) elog(ERROR, "zpbit_in: bit string too long for 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; sp = s + 1; 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; } } } if (bitlen > atttypmod) { /* Check that this fitted */ r = VARBITEND(result) - 1; ipad = VARBITPAD(result); /* * The bottom ipad bits of the byte pointed to by r need to be * zero */ if (((*r << (BITS_PER_BYTE - ipad)) & BITMASK) != 0) elog(ERROR, "zpbit_in: bit string too long for bit(%d)", atttypmod); } PG_RETURN_VARBIT_P(result); } /* zpbit_out - * for the time being we print everything as hex strings, as this is likely * to be more compact than bit strings, and consequently much more efficient * for long strings */ Datum zpbit_out(PG_FUNCTION_ARGS) { 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); } /* zpbit() * Converts a bit() type to a specific internal length. * len is the bitlength specified in the column definition. */ Datum zpbit(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); rlen = VARBITTOTALLEN(len); result = (VarBit *) palloc(rlen); /* set to 0 so that result is zero-padded if input is shorter */ memset(result, 0, rlen); VARATT_SIZEP(result) = rlen; VARBITLEN(result) = len; memcpy(VARBITS(result), VARBITS(arg), Min(VARBITBYTES(result), VARBITBYTES(arg))); PG_RETURN_VARBIT_P(result); } /* _zpbit() * Converts an array of bit() elements to a specific internal length. * len is the bitlength specified in the column definition. */ Datum _zpbit(PG_FUNCTION_ARGS) { ArrayType *v = (ArrayType *) PG_GETARG_VARLENA_P(0); int32 len = PG_GETARG_INT32(1); FunctionCallInfoData locfcinfo; /* * Since zpbit() is a built-in function, we should only need to * look it up once per run. */ static FmgrInfo zpbit_finfo; if (zpbit_finfo.fn_oid == InvalidOid) fmgr_info(F_ZPBIT, &zpbit_finfo); MemSet(&locfcinfo, 0, sizeof(locfcinfo)); locfcinfo.flinfo = &zpbit_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, ZPBITOID, ZPBITOID); } /* * varbit_in - * converts a string to the internal representation of a bitstring. * This is the same as zpbit_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 *s = 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, ipad; bits8 x = 0; /* Check that the first character is a b or an x */ if (s[0] == 'b' || s[0] == 'B') bit_not_hex = true; else if (s[0] == 'x' || s[0] == 'X') bit_not_hex = false; else { elog(ERROR, "varbit_in: %s is not a valid bitstring", s); bit_not_hex = false; /* keep compiler quiet */ } slen = strlen(s) - 1; /* 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. Note that the number of infered * bits can be larger than the number of actual bits needed, but only * if we are reading a hex string and not by more than 3 bits, as a * hex string gives an accurate length up to 4 bits */ if (atttypmod <= 0) atttypmod = bitlen; else if (bit_not_hex ? (bitlen > atttypmod) : (bitlen > atttypmod + 3)) elog(ERROR, "varbit_in: bit string too long for 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); sp = s + 1; 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; } } } if (bitlen > atttypmod) { /* Check that this fitted */ r = VARBITEND(result) - 1; ipad = VARBITPAD(result); /* * The bottom ipad bits of the byte pointed to by r need to be * zero */ if (((*r << (BITS_PER_BYTE - ipad)) & BITMASK) != 0) elog(ERROR, "varbit_in: bit string too long for bit varying(%d)", atttypmod); } 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 + 2); sp = VARBITS(s); r = result; *r++ = 'B'; 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); 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(F_VARBIT, &varbit_finfo); 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. */ 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); if (bitlen1 != bitlen2) result = false; else { /* bit strings are always stored in a full number of bytes */ result = memcmp(VARBITS(arg1), VARBITS(arg2), VARBITBYTES(arg1)) == 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); if (bitlen1 != bitlen2) result = true; else { /* bit strings are always stored in a full number of bytes */ result = memcmp(VARBITS(arg1), VARBITS(arg2), VARBITBYTES(arg1)) != 0; } PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); PG_RETURN_BOOL(result); } /* 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 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); 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, "bitand: Cannot AND bitstrings 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, "bitor: Cannot OR bitstrings 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, "bitxor: Cannot XOR bitstrings 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 an int4"); 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); }