Attached are the C-routines that implement a BIT and BIT VARYING type.

Adriaan Joubert
This commit is contained in:
Bruce Momjian 1999-11-29 22:34:36 +00:00
parent 47e51683e6
commit 1f747c6722
6 changed files with 1213 additions and 0 deletions

10
contrib/bit/Makefile Normal file
View File

@ -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

77
contrib/bit/README Normal file
View File

@ -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)

74
contrib/bit/postgres.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef POSTGRES_H
#define POSTGRES_H
#include <stdio.h>
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

832
contrib/bit/varbit.c Normal file
View File

@ -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;
}

48
contrib/bit/varbit.h Normal file
View File

@ -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);

172
contrib/bit/vartest.c Normal file
View File

@ -0,0 +1,172 @@
#include "postgres.h"
#include "varbit.h"
#include <stdio.h>
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<VARSIZE(s); i++)
printf ("%X%X ",s[i]>>4,s[i]&0xF);
printf("\n");
}
void
main ()
{
int i, j;
char *s[numb];
for (i=0; i<numb; i++) {
printf ("Input: %s\n",b[i]);
s[i] = zpbitin(b[i], 0, atttypmod[i]);
//print_details(s[i]);
printf ("%s = %s\n",zpbitout(s[i]),zpbitsout(s[i]));
}
printf ("\nCOMPARISONS:\n");
for (i=0; i<numb; i++)
for (j=i+1; j<numb; j++)
printf("%s <=> %s = %d\n",zpbitsout(s[i]),zpbitsout(s[j]),
bitcmp(s[i],s[j]));
printf ("\nCONCATENATION:\n");
for (i=0; i<numb; i++)
for (j=i+1; j<numb; j++)
printf("%s || %s = %s\n",zpbitsout(s[i]),zpbitsout(s[j]),
zpbitsout(bitcat(s[i],s[j])));
printf("\nSUBSTR:\n");
printf("%s (%d,%d) => %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<numb; i++)
for (j=i+1; j<numb; j++)
printf("%s & %s = %s\n",zpbitsout(s[i]),zpbitsout(s[j]),
zpbitsout(bitand(s[i],s[j])));
printf ("\nLOGICAL OR:\n");
for (i=0; i<numb; i++)
for (j=i+1; j<numb; j++)
printf("%s | %s = %s\n",zpbitsout(s[i]),zpbitsout(s[j]),
zpbitsout(bitor(s[i],s[j])));
printf ("\nLOGICAL XOR:\n");
for (i=0; i<numb; i++)
for (j=i+1; j<numb; j++)
printf("%s ^ %s = %s\n",zpbitsout(s[i]),zpbitsout(s[j]),
zpbitsout(bitxor(s[i],s[j])));
printf ("\nLOGICAL NOT:\n");
for (i=0; i<numb; i++)
printf("~%s = %s\n",zpbitsout(s[i]),zpbitsout(bitnot(s[i])));
printf ("\nSHIFT LEFT:\n");
for (i=0; i<numb; i++) {
printf("%s\n",zpbitsout(s[i]));
for (j=0; j<=VARBITLEN(s[i]); j++)
printf("\t%3d\t%s\n",j,zpbitsout(bitshiftleft(s[i],j)));
}
printf ("\nSHIFT RIGHT:\n");
for (i=0; i<numb; i++) {
printf("%s\n",zpbitsout(s[i]));
for (j=0; j<=VARBITLEN(s[i]); j++)
printf("\t%3d\t%s\n",j,zpbitsout(bitshiftright(s[i],j)));
}
printf ("\n\n ********** VARYING **********\n");
for (i=0; i<numb; i++) {
printf ("Input: %s\n",b[i]);
s[i] = varbitin(b[i], 0, atttypmod[i]);
/*print_details(s);*/
printf ("%s\n",zpbitout(s[i]));
printf ("%s\n",zpbitsout(s[i]));
}
printf ("\nCOMPARISONS:\n");
for (i=0; i<numb; i++)
for (j=i+1; j<numb; j++)
printf("%s <=> %s = %d\n",zpbitsout(s[i]),zpbitsout(s[j]),
bitcmp(s[i],s[j]));
printf ("\nCONCATENATION:\n");
for (i=0; i<numb; i++)
for (j=i+1; j<numb; j++)
printf("%s || %s = %s\n",zpbitsout(s[i]),zpbitsout(s[j]),
zpbitsout(bitcat(s[i],s[j])));
printf("\nSUBSTR:\n");
printf("%s (%d,%d) => %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<numb; i++)
for (j=i+1; j<numb; j++)
printf("%s & %s = %s\n",zpbitsout(s[i]),zpbitsout(s[j]),
zpbitsout(bitand(s[i],s[j])));
printf ("\nLOGICAL OR:\n");
for (i=0; i<numb; i++)
for (j=i+1; j<numb; j++)
printf("%s | %s = %s\n",zpbitsout(s[i]),zpbitsout(s[j]),
zpbitsout(bitor(s[i],s[j])));
printf ("\nLOGICAL XOR:\n");
for (i=0; i<numb; i++)
for (j=i+1; j<numb; j++)
printf("%s ^ %s = %s\n",zpbitsout(s[i]),zpbitsout(s[j]),
zpbitsout(bitxor(s[i],s[j])));
printf ("\nLOGICAL NOT:\n");
for (i=0; i<numb; i++)
printf("~%s = %s\n",zpbitsout(s[i]),zpbitsout(bitnot(s[i])));
printf ("\nSHIFT LEFT:\n");
for (i=0; i<numb; i++) {
printf("%s\n",zpbitsout(s[i]));
for (j=0; j<=VARBITLEN(s[i]); j++)
printf("\t%3d\t%s\n",j,zpbitsout(bitshiftleft(s[i],j)));
}
printf ("\nSHIFT RIGHT:\n");
for (i=0; i<numb; i++) {
printf("%s\n",zpbitsout(s[i]));
for (j=0; j<=VARBITLEN(s[i]); j++)
printf("\t%3d\t%s\n",j,zpbitsout(bitshiftright(s[i],j)));
}
}