From 1f747c67222842b93ad833675aca20001a6dd9f8 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Mon, 29 Nov 1999 22:34:36 +0000 Subject: [PATCH] Attached are the C-routines that implement a BIT and BIT VARYING type. Adriaan Joubert --- contrib/bit/Makefile | 10 + contrib/bit/README | 77 ++++ contrib/bit/postgres.h | 74 ++++ contrib/bit/varbit.c | 832 +++++++++++++++++++++++++++++++++++++++++ contrib/bit/varbit.h | 48 +++ contrib/bit/vartest.c | 172 +++++++++ 6 files changed, 1213 insertions(+) create mode 100644 contrib/bit/Makefile create mode 100644 contrib/bit/README create mode 100644 contrib/bit/postgres.h create mode 100644 contrib/bit/varbit.c create mode 100644 contrib/bit/varbit.h create mode 100644 contrib/bit/vartest.c diff --git a/contrib/bit/Makefile b/contrib/bit/Makefile new file mode 100644 index 0000000000..9603cba27f --- /dev/null +++ b/contrib/bit/Makefile @@ -0,0 +1,10 @@ +CFLAGS = -g + +varbit: vartest.o varbit.o + $(CC) $(CFLAGS) -o $@ $^ + +varbit.o: varbit.c varbit.h +vartest.o: vartest.c varbit.h + +clean: + rm -f *.o varbit diff --git a/contrib/bit/README b/contrib/bit/README new file mode 100644 index 0000000000..b2ddb904b3 --- /dev/null +++ b/contrib/bit/README @@ -0,0 +1,77 @@ +A set of C routines to implement an SQL-compliant bitstring type. + +The file varbit.c contains the c-functions to implement both BIT and +BIT VARYING. Both types are implemented in essentially the same way, +except that BIT is zero padded to a specified length. I've tried to +make this code as independent as possible of the byte length, but it +is quite possible that there may be problems on machines that don't +have 8 bits/byte (are there still any around?). + +In the input routines I have assumed that the parser eats the quotes +in B'...' or X'...'. + +The SQL standard only defines comparison, SUBSTR and concatenation +operators, and these have been implemented. In addition all logical +operators have been implemented, i.e. ~,|,&,^,<< and >>. This is +useful if one wants to build bit masks. If the two strings are not of +the same length the longer string is truncated (truncation was the +only real option, as padding with zeros could give unintuitive results +for ^) and the result has the length of the shorter string. If there +is a requirement for any other functions, let me know, and I will have +a look. + +My knowledge of postgres is not up to integrating a type, so I'm hoping +that somebody can integrate this type for me, or give me some hints as +to what needs to be done. These routines were developed outside the +postgres source tree, with a hacked version of postgres.h. The header +files probably need some ammending. + +The included files are + +varbit.h -- bit string header type +varbit.c -- the routines +vartest.c -- a few calls to the routines to + +The following routines are available. + +char * zpbitin(char *s, int dummy, int32 atttypmod); + Read in a zero padded bit string of the form X'...' or B'...' + +char * zpbitout(char *s); + Print a zero padded bit string in hex X'...' + +char * zpbitsout(char *s); + Print a zero padded bit string in binary B'...' + +char * varbitin(char *s, int dummy, int32 atttypmod); + Read in a varying length bit string of the form X'...' or B'...' + +[There is no need for separate output functions for varying bit, as + zpbitout will print them out correctly] + +char * bitcat (char *arg1, char *arg2); + Bit concatenation. + +char * bitsubstr (char *arg, int32 s, int32 l); + Substring of a bit string. + +bool biteq (char *arg1, char *arg2); +bool bitne (char *arg1, char *arg2); +bool bitge (char *arg1, char *arg2); +bool bitgt (char *arg1, char *arg2); +bool bitle (char *arg1, char *arg2); +bool bitlt (char *arg1, char *arg2); +int bitcmp (char *arg1, char *arg2); + Comparison operators + +char * bitand (char * arg1, char * arg2); +char * bitor (char * arg1, char * arg2); +char * bitxor (char * arg1, char * arg2); +char * bitnot (char * arg); +char * bitshiftright (char * arg, int shft); +char * bitshiftleft (char * arg, int shft); + Bit operations. + +If anything else needs to be done, please let me know. + +Adriaan (adriaan@albourne.com) diff --git a/contrib/bit/postgres.h b/contrib/bit/postgres.h new file mode 100644 index 0000000000..44da5d7ac6 --- /dev/null +++ b/contrib/bit/postgres.h @@ -0,0 +1,74 @@ +#ifndef POSTGRES_H +#define POSTGRES_H + +#include + +typedef char bool; +typedef signed char int8; +typedef signed short int16; +typedef signed int int32; + +/*#define NULL ((void *) 0)*/ +#define Min(x, y) ((x) < (y) ? (x) : (y)) +#define Max(x, y) ((x) > (y) ? (x) : (y)) +#define PointerIsValid(pointer) (bool)((void*)(pointer) != NULL) + + +typedef unsigned int Oid; +typedef int16 int2; +typedef int32 int4; +typedef float float4; +typedef double float8; +typedef unsigned char uint8; /* == 8 bits */ +typedef unsigned short uint16; /* == 16 bits */ +typedef unsigned int uint32; /* == 32 bits */ +typedef uint8 bits8; /* >= 8 bits */ +typedef uint16 bits16; /* >= 16 bits */ +typedef uint32 bits32; /* >= 32 bits */ + + +typedef int4 aclitem; + +#define InvalidOid 0 +#define OidIsValid(objectId) ((bool) (objectId != InvalidOid)) + +/* unfortunately, both regproc and RegProcedure are used */ +typedef Oid regproc; +typedef Oid RegProcedure; + +typedef char *((*func_ptr) ()); + + +#define RegProcedureIsValid(p) OidIsValid(p) + +/* ---------------------------------------------------------------- + * Section 2: variable length and array types + * ---------------------------------------------------------------- + */ +/* ---------------- + * struct varlena + * ---------------- + */ +struct varlena +{ + int32 vl_len; + char vl_dat[1]; +}; + +#define VARSIZE(PTR) (((struct varlena *)(PTR))->vl_len) +#define VARDATA(PTR) (((struct varlena *)(PTR))->vl_dat) +#define VARHDRSZ sizeof(int32) + +typedef struct varlena bytea; +typedef struct varlena text; + +typedef int2 int28[8]; +typedef Oid oid8[8]; + +#define ERROR stderr +#define elog fprintf + +#define MaxAttrSize 10000 + +#define palloc malloc +#endif diff --git a/contrib/bit/varbit.c b/contrib/bit/varbit.c new file mode 100644 index 0000000000..257f9766fd --- /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>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 -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>(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>(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; +} diff --git a/contrib/bit/varbit.h b/contrib/bit/varbit.h new file mode 100644 index 0000000000..af55f486ea --- /dev/null +++ b/contrib/bit/varbit.h @@ -0,0 +1,48 @@ +#include "postgres.h" + +typedef bits8 *VarBit; +typedef uint32 BitIndex; + +#define HEXDIG(z) (z)<10 ? ((z)+'0') : ((z)-10+'A') + + +#define BITSPERBYTE 8 +#define VARBITHDRSZ sizeof(int32) +/* Number of bits in this bit string */ +#define VARBITLEN(PTR) (((struct varlena *)VARDATA(PTR))->vl_len) +/* Pointer tp the first byte containing bit string data */ +#define VARBITS(PTR) (((struct varlena *)VARDATA(PTR))->vl_dat) +/* Number of bytes in the data section of a bit string */ +#define VARBITBYTES(PTR) (VARSIZE(PTR) - VARHDRSZ - VARBITHDRSZ) +/* Padding of the bit string at the end */ +#define VARBITPAD(PTR) (VARBITBYTES(PTR)*BITSPERBYTE - VARBITLEN(PTR)) +/* Number of bytes needed to store a bit string of a given length */ +#define VARBITDATALEN(BITLEN) (BITLEN/BITSPERBYTE + \ + (BITLEN%BITSPERBYTE > 0 ? 1 : 0) + \ + VARHDRSZ + VARBITHDRSZ) +/* pointer beyond the end of the bit string (like end() in STL containers) */ +#define VARBITEND(PTR) ((bits8 *) (PTR + VARSIZE(PTR))) +/* Mask that will cover exactly one byte, i.e. BITSPERBYTE bits */ +#define BITMASK 0xFF +#define BITHIGH 0x80 + + +char * zpbitin(char *s, int dummy, int32 atttypmod); +char * zpbitout(char *s); +char * zpbitsout(char *s); +char * varbitin(char *s, int dummy, int32 atttypmod); +bool biteq (char *arg1, char *arg2); +bool bitne (char *arg1, char *arg2); +bool bitge (char *arg1, char *arg2); +bool bitgt (char *arg1, char *arg2); +bool bitle (char *arg1, char *arg2); +bool bitlt (char *arg1, char *arg2); +int bitcmp (char *arg1, char *arg2); +char * bitand (char * arg1, char * arg2); +char * bitor (char * arg1, char * arg2); +char * bitxor (char * arg1, char * arg2); +char * bitnot (char * arg); +char * bitshiftright (char * arg, int shft); +char * bitshiftleft (char * arg, int shft); +char * bitcat (char *arg1, char *arg2); +char * bitsubstr (char *arg, int32 s, int32 l); diff --git a/contrib/bit/vartest.c b/contrib/bit/vartest.c new file mode 100644 index 0000000000..732141e8df --- /dev/null +++ b/contrib/bit/vartest.c @@ -0,0 +1,172 @@ +#include "postgres.h" +#include "varbit.h" +#include + +const int numb = 8; +/* +const char *b[] = { "B0010", "B11011011", "B0001", "X3F12", "X27", "B", + "X11", "B100111"}; +int atttypmod[] = {-1, -1, -1,-1,-1,-1,-1,-1 }; +*/ +const char *b[] = { "B0010", "B11011011", "B10001", "X3D12", "X27", "B", + "X11", "B100111"}; +int atttypmod[] = { 7, 9, 6, 18, 11, 6, -1, -1 }; + + +void print_details (unsigned char *s) +{ + int i; + printf ("Length in bytes : %d\n",VARSIZE(s)); + printf ("Length of bitstring: %d\n",VARBITLEN(s)); + for (i=8; i>4,s[i]&0xF); + printf("\n"); +} + +void +main () +{ + int i, j; + char *s[numb]; + + for (i=0; i %s = %d\n",zpbitsout(s[i]),zpbitsout(s[j]), + bitcmp(s[i],s[j])); + + printf ("\nCONCATENATION:\n"); + for (i=0; i %s\n",zpbitsout(s[3]),1,8, + zpbitsout(bitsubstr(s[3],1,8))); + printf("%s (%d,%d) => %s\n",zpbitsout(s[3]),9,8, + zpbitsout(bitsubstr(s[3],9,8))); + printf("%s (%d,%d) => %s\n",zpbitsout(s[3]),1,9, + zpbitsout(bitsubstr(s[3],1,9))); + printf("%s (%d,%d) => %s\n",zpbitsout(s[3]),3,5, + zpbitsout(bitsubstr(s[3],3,5))); + printf("%s (%d,%d) => %s\n",zpbitsout(s[3]),3,9, + zpbitsout(bitsubstr(s[3],3,9))); + printf("%s (%d,%d) => %s\n",zpbitsout(s[3]),3,17, + zpbitsout(bitsubstr(s[3],3,17))); + printf ("\nLOGICAL AND:\n"); + for (i=0; i %s = %d\n",zpbitsout(s[i]),zpbitsout(s[j]), + bitcmp(s[i],s[j])); + + printf ("\nCONCATENATION:\n"); + for (i=0; i %s\n",zpbitsout(s[3]),1,8, + zpbitsout(bitsubstr(s[3],1,8))); + printf("%s (%d,%d) => %s\n",zpbitsout(s[3]),9,8, + zpbitsout(bitsubstr(s[3],9,8))); + printf("%s (%d,%d) => %s\n",zpbitsout(s[3]),1,9, + zpbitsout(bitsubstr(s[3],1,9))); + printf("%s (%d,%d) => %s\n",zpbitsout(s[3]),3,5, + zpbitsout(bitsubstr(s[3],3,5))); + printf("%s (%d,%d) => %s\n",zpbitsout(s[3]),3,9, + zpbitsout(bitsubstr(s[3],3,9))); + printf("%s (%d,%d) => %s\n",zpbitsout(s[3]),3,17, + zpbitsout(bitsubstr(s[3],3,17))); + printf ("\nLOGICAL AND:\n"); + for (i=0; i