mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			892 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			892 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*-------------------------------------------------------------------------
 | 
						|
 *
 | 
						|
 * varbit.c
 | 
						|
 *	  Functions for the built-in type bit() and varying bit().
 | 
						|
 *
 | 
						|
 * IDENTIFICATION
 | 
						|
 *	  $Header: /cvsroot/pgsql/contrib/bit/Attic/varbit.c,v 1.3 2000/04/12 17:14:21 momjian Exp $
 | 
						|
 *
 | 
						|
 *-------------------------------------------------------------------------
 | 
						|
 */
 | 
						|
#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??)
 | 
						|
 */
 | 
						|
bits8 *
 | 
						|
zpbitin(char *s, int dummy, int32 atttypmod)
 | 
						|
{
 | 
						|
	bits8	   *result;			/* the bits string that was read in   */
 | 
						|
	char	   *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;/* 0 = hex string  1=bit string		  */
 | 
						|
	int			bc,
 | 
						|
				ipad;
 | 
						|
	bits8		x = 0;
 | 
						|
 | 
						|
 | 
						|
	if (s == NULL)
 | 
						|
		return (bits8 *) 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 %ld",
 | 
						|
			 (MaxAttrSize - VARHDRSZ - VARBITHDRSZ) * BITSPERBYTE);
 | 
						|
 | 
						|
	result = (bits8 *) 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 = 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(bits8 *s)
 | 
						|
{
 | 
						|
	char	   *result,
 | 
						|
			   *r;
 | 
						|
	bits8	   *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 = 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(bits8 *s)
 | 
						|
{
 | 
						|
	char	   *result,
 | 
						|
			   *r;
 | 
						|
	bits8	   *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 = 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.
 | 
						|
*/
 | 
						|
bits8 *
 | 
						|
varbitin(char *s, int dummy, int32 atttypmod)
 | 
						|
{
 | 
						|
	bits8	   *result;			/* The resulting bit string			  */
 | 
						|
	char	   *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;
 | 
						|
	int			bc,
 | 
						|
				ipad;
 | 
						|
	bits8		x = 0;
 | 
						|
 | 
						|
 | 
						|
	if (s == NULL)
 | 
						|
		return (bits8 *) 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 %ld",
 | 
						|
			 (MaxAttrSize - VARHDRSZ - VARBITHDRSZ) * BITSPERBYTE);
 | 
						|
 | 
						|
	result = (bits8 *) 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 = 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(bits8 *arg1, bits8 *arg2)
 | 
						|
{
 | 
						|
	int			bitlen1,
 | 
						|
				bitlen2;
 | 
						|
 | 
						|
	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(bits8 *arg1, bits8 *arg2)
 | 
						|
{
 | 
						|
	int			bitlen1,
 | 
						|
				bitlen2;
 | 
						|
 | 
						|
	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(bits8 *arg1, bits8 *arg2)
 | 
						|
{
 | 
						|
	int			bitlen1,
 | 
						|
				bytelen1,
 | 
						|
				bitlen2,
 | 
						|
				bytelen2;
 | 
						|
	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(bits8 *arg1, bits8 *arg2)
 | 
						|
{
 | 
						|
	return (bool) (bitcmp(arg1, arg2) == -1);
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
bitle(bits8 *arg1, bits8 *arg2)
 | 
						|
{
 | 
						|
	return (bool) (bitcmp(arg1, arg2) <= 0);
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
bitge(bits8 *arg1, bits8 *arg2)
 | 
						|
{
 | 
						|
	return (bool) (bitcmp(arg1, arg2) >= 0);
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
bitgt(bits8 *arg1, bits8 *arg2)
 | 
						|
{
 | 
						|
	return (bool) (bitcmp(arg1, arg2) == 1);
 | 
						|
}
 | 
						|
 | 
						|
/* bitcat
 | 
						|
 * Concatenation of bit strings
 | 
						|
 */
 | 
						|
bits8 *
 | 
						|
bitcat(bits8 *arg1, bits8 *arg2)
 | 
						|
{
 | 
						|
	int			bitlen1,
 | 
						|
				bitlen2,
 | 
						|
				bytelen,
 | 
						|
				bit1pad,
 | 
						|
				bit2shift;
 | 
						|
	bits8	   *result;
 | 
						|
	bits8	   *pr,
 | 
						|
			   *pa;
 | 
						|
 | 
						|
	if (!PointerIsValid(arg1) || !PointerIsValid(arg2))
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	bitlen1 = VARBITLEN(arg1);
 | 
						|
	bitlen2 = VARBITLEN(arg2);
 | 
						|
 | 
						|
	bytelen = VARBITDATALEN(bitlen1 + bitlen2);
 | 
						|
 | 
						|
	result = (bits8 *) 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 = VARBITS(arg2);
 | 
						|
		pr = VARBITS(result) + VARBITBYTES(arg1) - 1;
 | 
						|
		for (; pa < VARBITEND(arg2); pa++)
 | 
						|
		{
 | 
						|
			*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)
 | 
						|
 */
 | 
						|
bits8 *
 | 
						|
bitsubstr(bits8 *arg, int32 s, int32 l)
 | 
						|
{
 | 
						|
	int			bitlen,
 | 
						|
				rbitlen,
 | 
						|
				len,
 | 
						|
				ipad = 0,
 | 
						|
				ishift,
 | 
						|
				i;
 | 
						|
	int			e,
 | 
						|
				s1,
 | 
						|
				e1;
 | 
						|
	bits8	   *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 = (bits8 *) 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 = (bits8 *) palloc(len);
 | 
						|
		VARBITLEN(result) = rbitlen;
 | 
						|
		VARSIZE(result) = len;
 | 
						|
		len -= VARHDRSZ + VARBITHDRSZ;
 | 
						|
		/* Are we copying from a byte boundary? */
 | 
						|
		if ((s1 - 1) % BITSPERBYTE == 0)
 | 
						|
		{
 | 
						|
			/* Yep, we are copying bytes */
 | 
						|
			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 = VARBITS(result);
 | 
						|
			ps = 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
 | 
						|
 */
 | 
						|
bits8 *
 | 
						|
bitand(bits8 *arg1, bits8 *arg2)
 | 
						|
{
 | 
						|
	int			len,
 | 
						|
				i;
 | 
						|
	bits8	   *result;
 | 
						|
	bits8	   *p1,
 | 
						|
			   *p2,
 | 
						|
			   *r;
 | 
						|
 | 
						|
	if (!PointerIsValid(arg1) || !PointerIsValid(arg2))
 | 
						|
		return (bool) 0;
 | 
						|
 | 
						|
	len = Min(VARSIZE(arg1), VARSIZE(arg2));
 | 
						|
	result = (bits8 *) 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.
 | 
						|
 */
 | 
						|
bits8 *
 | 
						|
bitor(bits8 *arg1, bits8 *arg2)
 | 
						|
{
 | 
						|
	int			len,
 | 
						|
				i;
 | 
						|
	bits8	   *result;
 | 
						|
	bits8	   *p1,
 | 
						|
			   *p2,
 | 
						|
			   *r;
 | 
						|
	bits8		mask;
 | 
						|
 | 
						|
	if (!PointerIsValid(arg1) || !PointerIsValid(arg2))
 | 
						|
		return (bool) 0;
 | 
						|
 | 
						|
	len = Min(VARSIZE(arg1), VARSIZE(arg2));
 | 
						|
	result = (bits8 *) 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.
 | 
						|
 */
 | 
						|
bits8 *
 | 
						|
bitxor(bits8 *arg1, bits8 *arg2)
 | 
						|
{
 | 
						|
	int			len,
 | 
						|
				i;
 | 
						|
	bits8	   *result;
 | 
						|
	bits8	   *p1,
 | 
						|
			   *p2,
 | 
						|
			   *r;
 | 
						|
	bits8		mask;
 | 
						|
 | 
						|
	if (!PointerIsValid(arg1) || !PointerIsValid(arg2))
 | 
						|
		return (bool) 0;
 | 
						|
 | 
						|
	len = Min(VARSIZE(arg1), VARSIZE(arg2));
 | 
						|
	result = (bits8 *) 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.
 | 
						|
 */
 | 
						|
bits8 *
 | 
						|
bitnot(bits8 *arg)
 | 
						|
{
 | 
						|
	bits8	   *result;
 | 
						|
	bits8	   *p,
 | 
						|
			   *r;
 | 
						|
	bits8		mask;
 | 
						|
 | 
						|
	if (!PointerIsValid(arg))
 | 
						|
		return (bool) 0;
 | 
						|
 | 
						|
	result = (bits8 *) 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
 | 
						|
 */
 | 
						|
bits8 *
 | 
						|
bitshiftleft(bits8 *arg, int shft)
 | 
						|
{
 | 
						|
	int			byte_shift,
 | 
						|
				ishift,
 | 
						|
				len;
 | 
						|
	bits8	   *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 = (bits8 *) 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
 | 
						|
 */
 | 
						|
bits8 *
 | 
						|
bitshiftright(bits8 *arg, int shft)
 | 
						|
{
 | 
						|
	int			byte_shift,
 | 
						|
				ishift,
 | 
						|
				len;
 | 
						|
	bits8	   *result;
 | 
						|
	bits8	   *p,
 | 
						|
			   *r;
 | 
						|
 | 
						|
	if (!PointerIsValid(arg))
 | 
						|
		return (bits8 *) 0;
 | 
						|
 | 
						|
	/* Negative shift is a shift to the left */
 | 
						|
	if (shft < 0)
 | 
						|
		return bitshiftleft(arg, -shft);
 | 
						|
 | 
						|
	result = (bits8 *) 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;
 | 
						|
}
 |