diff options
author | Bruce Momjian | 1999-11-29 22:34:36 +0000 |
---|---|---|
committer | Bruce Momjian | 1999-11-29 22:34:36 +0000 |
commit | 1f747c67222842b93ad833675aca20001a6dd9f8 (patch) | |
tree | a2fb1c141befbb54e3f1b417cbcb9b8e365d76d8 /contrib/bit/varbit.c | |
parent | 47e51683e66fc79132285f38bcf8f2d2fc49d2e5 (diff) |
Attached are the C-routines that implement a BIT and BIT VARYING type.
Adriaan Joubert
Diffstat (limited to 'contrib/bit/varbit.c')
-rw-r--r-- | contrib/bit/varbit.c | 832 |
1 files changed, 832 insertions, 0 deletions
diff --git a/contrib/bit/varbit.c b/contrib/bit/varbit.c new file mode 100644 index 00000000000..257f9766fd6 --- /dev/null +++ b/contrib/bit/varbit.c @@ -0,0 +1,832 @@ +/*------------------------------------------------------------------------- + * + * varbit.c + * Functions for the built-in type bit() and varying bit(). + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/contrib/bit/Attic/varbit.c,v 1.1 1999/11/29 22:34:36 momjian Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" +#include "varbit.h" +/* +#include "access/htup.h" +#include "catalog/pg_type.h" +#include "utils/builtins.h" +*/ + + + +/* + 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 -- lenght of the bit string in bits + bitdata -- least significant byte first string +*/ + +/* + * zpbitin - + + * converts a string to the internal representation of a bitstring. + * The length is determined by the number of bits required plus + * VARHDRSZ bytes or from atttypmod. + * (XXX dummy is here because we pass typelem as the second argument + * for array_in. copied this, no idea what it means??) + */ +char * +zpbitin(char *s, int dummy, int32 atttypmod) +{ + char *result, + *sp; /* pointer into the character string */ + bits8 *r; + int len, /* Length of the whole data structure */ + bitlen, /* Number of bits in the bit string */ + slen; /* Length of the input string */ + int bit_not_hex; /* 0 = hex string 1=bit string */ + int i, bc, ipad; + bits8 x, y; + + + if (s == NULL) + return NULL; + + /* Check that the first character is a b or an x */ + if (s[0]=='b' || s[0]=='B') + bit_not_hex = 1; + else if (s[0]=='x' || s[0]=='X') + bit_not_hex = 0; + else + elog(ERROR, "zpbitin: %s is not a valid bitstring",s); + + slen = strlen(s) - 1; + /* Determine bitlength from input string */ + bitlen = slen; + if (!bit_not_hex) + bitlen *= 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 + and accurate length upto 4 bits */ + if (atttypmod == -1) + atttypmod = bitlen; + else + if (bitlen>atttypmod && bit_not_hex || bitlen>atttypmod+3 && !bit_not_hex) + elog(ERROR, "zpbitin: bit string of size %d cannot be written into bits(%d)", + bitlen,atttypmod); + + + len = VARBITDATALEN(atttypmod); + + if (len > MaxAttrSize) + elog(ERROR, "zpbitin: length of bit() must be less than %d", + (MaxAttrSize-VARHDRSZ-VARBITHDRSZ)*BITSPERBYTE); + + result = (char *) palloc(len); + /* set to 0 so that *r is always initialised and strin is zero-padded */ + memset(result, 0, len); + VARSIZE(result) = len; + VARBITLEN(result) = atttypmod; + + /* We need to read the bitstring from the end, as we store it least + significant byte first. s points to the byte before the beginning + of the bitstring */ + sp = s+1; + r = (bits8 *) 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 (bc = 0; sp != s+slen+1; sp++, bc++) + { + if (*sp=='1') + *r |= x; + if (bc==7) { + bc = 0; + x = BITHIGH; + r++; + } else + x >>= 1; + } + } + else + { + /* Parse the hex representation of the string */ + for (bc = 0; sp != s+slen+1; 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) { + bc = 0; + *r++ |= x; + } else { + bc++; + *r = x<<4; + } + } + } + + if (bitlen > atttypmod) { + /* Check that this fitted */ + r = (bits8 *) (result + len - 1); + ipad = VARBITPAD(result); + /* The bottom ipad bits of the byte pointed to by r need to be zero */ + /* printf("Byte %X shift %X %d\n",*r,(*r << (8-ipad)) & BITMASK, + (*r << (8-ipad)) & BITMASK > 0); + */ + if (((*r << (BITSPERBYTE-ipad)) & BITMASK) > 0) + elog(ERROR, "zpbitin: bit string too large for bit(%d) data type", + atttypmod); + } + + return result; +} + +/* zpbitout - + * 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 + */ +char * +zpbitout(char *s) +{ + char *result, *r; + VarBit sp; + int i, len, bitlen; + + if (s == NULL) + { + result = (char *) palloc(2); + result[0] = '-'; + result[1] = '\0'; + } + else + { + bitlen = VARBITLEN(s); + len = bitlen/4 + (bitlen%4>0 ? 1 : 0); + result = (char *) palloc(len + 4); + sp = (bits8 *) VARBITS(s); + r = result; + *r++ = 'X'; + *r++ = '\''; + /* 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+1) + r--; + *r++ = '\''; + *r = '\0'; + } + return result; +} + +/* zpbitsout - + * Prints the string a bits + */ +char * +zpbitsout(char *s) +{ + char *result, *r; + VarBit sp; + bits8 x; + int i, k, len; + + if (s == NULL) + { + result = (char *) palloc(2); + result[0] = '-'; + result[1] = '\0'; + } + else + { + len = VARBITLEN(s); + result = (char *) palloc(len + 4); + sp = (bits8 *) VARBITS(s); + r = result; + *r++ = 'B'; + *r++ = '\''; + for (i=0; i<len-BITSPERBYTE; i+=BITSPERBYTE, sp++) { + x = *sp; + for (k=0; k<BITSPERBYTE; k++) + { + *r++ = (x & BITHIGH) ? '1' : '0'; + x <<= 1; + } + } + x = *sp; + for (k=i; k<len; k++) + { + *r++ = (x & BITHIGH) ? '1' : '0'; + x <<= 1; + } + *r++ = '\''; + *r = '\0'; + } + return result; +} + + +/* + * varbitin - + * converts a string to the internal representation of a bitstring. +*/ +char * +varbitin(char *s, int dummy, int32 atttypmod) +{ + char *result, + *sp; /* pointer into the character string */ + bits8 *r; + int len, /* Length of the whole data structure */ + bitlen, /* Number of bits in the bit string */ + slen; /* Length of the input string */ + int bit_not_hex; + int i, bc, ipad; + bits8 x, y; + + + if (s == NULL) + return NULL; + + /* Check that the first character is a b or an x */ + if (s[0]=='b' || s[0]=='B') + bit_not_hex = 1; + else if (s[0]=='x' || s[0]=='X') + bit_not_hex = 0; + else + elog(ERROR, "zpbitin: %s is not a valid bitstring",s); + + slen = strlen(s) - 1; + /* Determine bitlength from input string */ + bitlen = slen; + if (!bit_not_hex) + bitlen *= 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 + and accurate length upto 4 bits */ + if (atttypmod > -1) + if (bitlen>atttypmod && bit_not_hex || bitlen>atttypmod+3 && !bit_not_hex) + elog(ERROR, "varbitin: bit string of size %d cannot be written into varying bits(%d)", + bitlen,atttypmod); + + + len = VARBITDATALEN(bitlen); + + if (len > MaxAttrSize) + elog(ERROR, "varbitin: length of bit() must be less than %d", + (MaxAttrSize-VARHDRSZ-VARBITHDRSZ)*BITSPERBYTE); + + result = (char *) palloc(len); + /* set to 0 so that *r is always initialised and strin is zero-padded */ + memset(result, 0, len); + VARSIZE(result) = len; + VARBITLEN(result) = bitlen; + + /* We need to read the bitstring from the end, as we store it least + significant byte first. s points to the byte before the beginning + of the bitstring */ + sp = s + 1; + r = (VarBit) VARBITS(result); + if (bit_not_hex) + { + /* Parse the bit representation of the string */ + x = BITHIGH; + for (bc = 0; sp != s+slen+1; sp++, bc++) + { + if (*sp=='1') + *r |= x; + if (bc==7) { + bc = 0; + x = BITHIGH; + r++; + } else + x >>= 1; + } + } + else + { + for (bc = 0; sp != s+slen+1; 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) { + bc = 0; + *r++ |= x; + } else { + bc++; + *r = x<<4; + } + } + } + + if (bitlen > atttypmod) { + /* Check that this fitted */ + r = (bits8 *) (result + len - 1); + ipad = VARBITPAD(result); + /* The bottom ipad bits of the byte pointed to by r need to be zero */ + if (((*r << (BITSPERBYTE-ipad)) & BITMASK) > 0) + elog(ERROR, "varbitin: bit string too large for varying bit(%d) data type", + atttypmod); + } + + return result; +} + +/* + the zpbitout routines are fine for varying bits as well +*/ + + +/* + * 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. + */ + +bool +biteq (char *arg1, char *arg2) +{ + int bitlen1, + bitlen2; + bits8 *p1, *p2; + + if (!PointerIsValid(arg1) || !PointerIsValid(arg2)) + return (bool) 0; + bitlen1 = VARBITLEN(arg1); + bitlen2 = VARBITLEN(arg2); + if (bitlen1 != bitlen2) + return (bool) 0; + + /* bit strings are always stored in a full number of bytes */ + return memcmp((void *)VARBITS(arg1),(void *)VARBITS(arg2), + VARBITBYTES(arg1)) == 0; +} + +bool +bitne (char *arg1, char *arg2) +{ + int bitlen1, + bitlen2; + bits8 *p1, *p2; + + if (!PointerIsValid(arg1) || !PointerIsValid(arg2)) + return (bool) 0; + bitlen1 = VARBITLEN(arg1); + bitlen2 = VARBITLEN(arg2); + if (bitlen1 != bitlen2) + return (bool) 1; + + /* bit strings are always stored in a full number of bytes */ + return memcmp((void *)VARBITS(arg1),(void *)VARBITS(arg2), + VARBITBYTES(arg1)) != 0; +} + +/* bitcmp + * + * Compares two bitstrings and returns -1, 0, 1 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. + * Anything is equal to undefined. + */ +int +bitcmp (char *arg1, char *arg2) +{ + int bitlen1, bytelen1, + bitlen2, bytelen2; + bits8 *p1, *p2; + int cmp; + + if (!PointerIsValid(arg1) || !PointerIsValid(arg2)) + return (bool) 0; + 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) + return bitlen1 < bitlen2 ? -1 : 1; + } + return cmp; +} + +bool +bitlt (char *arg1, char *arg2) +{ + return (bool) (bitcmp(arg1,arg2) == -1); +} + +bool +bitle (char *arg1, char *arg2) +{ + return (bool) (bitcmp(arg1,arg2) <= 0); +} + +bool +bitge (char *arg1, char *arg2) +{ + return (bool) (bitcmp(arg1,arg2) >= 0); +} + +bool +bitgt (char *arg1, char *arg2) +{ + return (bool) (bitcmp(arg1,arg2) == 1); +} + +/* bitcat + * Concatenation of bit strings + */ +char * +bitcat (char *arg1, char *arg2) +{ + int bitlen1, bitlen2, bytelen, bit1pad, bit2shift; + char *result; + bits8 *pr, *pa; + + if (!PointerIsValid(arg1) || !PointerIsValid(arg2)) + return NULL; + + bitlen1 = VARBITLEN(arg1); + bitlen2 = VARBITLEN(arg2); + + bytelen = VARBITDATALEN(bitlen1+bitlen2); + + result = (char *) palloc(bytelen*sizeof(bits8)); + VARSIZE(result) = bytelen; + VARBITLEN(result) = bitlen1+bitlen2; + printf("%d %d %d \n",VARBITBYTES(arg1),VARBITLEN(arg1),VARBITPAD(arg1)); + /* 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 results to fit */ + bit2shift = BITSPERBYTE - bit1pad; + pa = (VarBit) VARBITS(arg2); + pr = (VarBit) VARBITS(result)+VARBITBYTES(arg1)-1; + for ( ; pa < VARBITEND(arg2); pa++) { + *pr = *pr | ((*pa >> bit2shift) & BITMASK); + pr++; + if (pr < VARBITEND(result)) + *pr = (*pa << bit1pad) & BITMASK; + } + } + + return result; +} + +/* bitsubstr + * retrieve a substring from the bit string. + * Note, s is 1-based. + * SQL draft 6.10 9) + */ +char * +bitsubstr (char *arg, int32 s, int32 l) +{ + int bitlen, + rbitlen, + len, + ipad, + ishift, + i; + int e, s1, e1; + char * result; + bits8 mask, *r, *ps; + + if (!PointerIsValid(arg)) + return NULL; + + bitlen = VARBITLEN(arg); + e = s+l; + s1 = Max(s,1); + e1 = Min(e,bitlen+1); + if (s1>bitlen || e1<1) + { + /* Need to return a null string */ + len = VARBITDATALEN(0); + result = (char *) palloc(len); + VARBITLEN(result) = 0; + VARSIZE(result) = len; + } + else + { + /* OK, we've got a true substring starting at position s1-1 and + ending at position e1-1 */ + rbitlen = e1-s1; + len = VARBITDATALEN(rbitlen); + result = (char *) palloc(len); + VARBITLEN(result) = rbitlen; + VARSIZE(result) = len; + /* Are we copying from a byte boundary? */ + if ((s1-1)%BITSPERBYTE==0) + { + /* Yep, we are copying bytes */ + len -= VARHDRSZ + VARBITHDRSZ; + memcpy(VARBITS(result),VARBITS(arg)+(s1-1)/BITSPERBYTE,len); + } + else + { + /* Figure out how much we need to shift the sequence by */ + ishift = (s1-1)%BITSPERBYTE; + r = (VarBit) VARBITS(result); + ps = (VarBit) VARBITS(arg) + (s1-1)/BITSPERBYTE; + for (i=0; i<len; i++) + { + *r = (*ps <<ishift) & BITMASK; + if ((++ps) < VARBITEND(arg)) + *r |= *ps >>(BITSPERBYTE-ishift); + r++; + } + } + /* Do we need to pad at the end? */ + ipad = VARBITPAD(result); + if (ipad > 0) + { + mask = BITMASK << ipad; + *(VARBITS(result) + len - 1) &= mask; + } + } + + return result; +} + +/* bitand + * perform a logical AND on two bit strings. The result is automatically + * truncated to the shorter bit string + */ +char * +bitand (char * arg1, char * arg2) +{ + int len, + i; + char *result; + bits8 *p1, + *p2, + *r; + + if (!PointerIsValid(arg1) || !PointerIsValid(arg2)) + return (bool) 0; + + len = Min(VARSIZE(arg1),VARSIZE(arg2)); + result = (char *) palloc(len); + VARSIZE(result) = len; + VARBITLEN(result) = Min(VARBITLEN(arg1),VARBITLEN(arg2)); + + p1 = (bits8 *) VARBITS(arg1); + p2 = (bits8 *) VARBITS(arg2); + r = (bits8 *) VARBITS(result); + for (i=0; i<Min(VARBITBYTES(arg1),VARBITBYTES(arg2)); i++) + *r++ = *p1++ & *p2++; + + /* Padding is not needed as & of 0 pad is 0 */ + + return result; +} + +/* bitor + * perform a logical OR on two bit strings. The result is automatically + * truncated to the shorter bit string. + */ +char * +bitor (char * arg1, char * arg2) +{ + int len, + i; + char *result; + bits8 *p1, + *p2, + *r; + bits8 mask; + + if (!PointerIsValid(arg1) || !PointerIsValid(arg2)) + return (bool) 0; + + len = Min(VARSIZE(arg1),VARSIZE(arg2)); + result = (char *) palloc(len); + VARSIZE(result) = len; + VARBITLEN(result) = Min(VARBITLEN(arg1),VARBITLEN(arg2)); + + p1 = (bits8 *) VARBITS(arg1); + p2 = (bits8 *) VARBITS(arg2); + r = (bits8 *) VARBITS(result); + for (i=0; i<Min(VARBITBYTES(arg1),VARBITBYTES(arg2)); i++) + *r++ = *p1++ | *p2++; + + /* Pad the result */ + mask = BITMASK << VARBITPAD(result); + *r &= mask; + + return result; +} + +/* bitxor + * perform a logical XOR on two bit strings. The result is automatically + * truncated to the shorter bit string. + */ +char * +bitxor (char * arg1, char * arg2) +{ + int len, + i; + char *result; + bits8 *p1, + *p2, + *r; + bits8 mask; + + if (!PointerIsValid(arg1) || !PointerIsValid(arg2)) + return (bool) 0; + + len = Min(VARSIZE(arg1),VARSIZE(arg2)); + result = (char *) palloc(len); + VARSIZE(result) = len; + VARBITLEN(result) = Min(VARBITLEN(arg1),VARBITLEN(arg2)); + + p1 = (bits8 *) VARBITS(arg1); + p2 = (bits8 *) VARBITS(arg2); + r = (bits8 *) VARBITS(result); + for (i=0; i<Min(VARBITBYTES(arg1),VARBITBYTES(arg2)); i++) + { + *r++ = *p1++ ^ *p2++; + } + + /* Pad the result */ + mask = BITMASK << VARBITPAD(result); + *r &= mask; + + return result; +} + +/* bitnot + * perform a logical NOT on a bit strings. + */ +char * +bitnot (char * arg) +{ + int len; + char *result; + bits8 *p, + *r; + bits8 mask; + + if (!PointerIsValid(arg)) + return (bool) 0; + + result = (char *) palloc(VARSIZE(arg)); + VARSIZE(result) = VARSIZE(arg); + VARBITLEN(result) = VARBITLEN(arg); + + p = (bits8 *) VARBITS(arg); + r = (bits8 *) VARBITS(result); + for ( ; p < VARBITEND(arg); p++, r++) + *r = ~*p; + + /* Pad the result */ + mask = BITMASK << VARBITPAD(result); + *r &= mask; + + return result; +} + +/* bitshiftleft + * do a left shift (i.e. to the beginning of the string) of the bit string + */ +char * +bitshiftleft (char * arg, int shft) +{ + int byte_shift, ishift, len; + char *result; + bits8 *p, + *r; + + if (!PointerIsValid(arg)) + return (bool) 0; + + /* Negative shift is a shift to the right */ + if (shft < 0) + return bitshiftright(arg, -shft); + + result = (char *) palloc(VARSIZE(arg)); + VARSIZE(result) = VARSIZE(arg); + VARBITLEN(result) = VARBITLEN(arg); + r = (bits8 *) VARBITS(result); + + byte_shift = shft/BITSPERBYTE; + ishift = shft % BITSPERBYTE; + p = ((bits8 *) 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 >>(BITSPERBYTE-ishift); + } + for ( ; r < VARBITEND(result) ; r++ ) + *r = (bits8) 0; + } + + return result; +} + +/* bitshiftright + * do a right shift (i.e. to the beginning of the string) of the bit string + */ +char * +bitshiftright (char * arg, int shft) +{ + int byte_shift, ishift, len; + char *result; + bits8 *p, + *r; + + if (!PointerIsValid(arg)) + return (bool) 0; + + /* Negative shift is a shift to the left */ + if (shft < 0) + return bitshiftleft(arg, -shft); + + result = (char *) palloc(VARSIZE(arg)); + VARSIZE(result) = VARSIZE(arg); + VARBITLEN(result) = VARBITLEN(arg); + r = (bits8 *) VARBITS(result); + + byte_shift = shft/BITSPERBYTE; + ishift = shft % BITSPERBYTE; + p = (bits8 *) VARBITS(arg); + + /* Set the first part of the result to 0 */ + memset(r, 0, byte_shift); + + if (ishift == 0) + { + /* Special case: we can do a memcpy */ + len = VARBITBYTES(arg) - byte_shift; + memcpy(r+byte_shift, p, len); + } + else + { + r += byte_shift; + *r = 0; /* Initialise first byte */ + for ( ; r < VARBITEND(result); p++) { + *r |= *p >> ishift; + if ((++r) < VARBITEND(result)) + *r = (*p <<(BITSPERBYTE-ishift)) & BITMASK; + } + } + + return result; +} |