2000-04-08 04:13:11 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* varbit.c
|
2000-08-21 06:48:57 +02:00
|
|
|
* Functions for the SQL datatypes BIT() and BIT VARYING().
|
|
|
|
*
|
|
|
|
* Code originally contributed by Adriaan Joubert.
|
|
|
|
*
|
2010-01-02 17:58:17 +01:00
|
|
|
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
2000-08-21 06:48:57 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
2000-04-08 04:13:11 +02:00
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-02-26 03:01:40 +01:00
|
|
|
* $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.65 2010/02/26 02:01:10 momjian Exp $
|
2000-04-08 04:13:11 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
2000-07-13 00:59:15 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
#include "access/htup.h"
|
2003-05-13 01:08:52 +02:00
|
|
|
#include "libpq/pqformat.h"
|
2006-12-30 22:21:56 +01:00
|
|
|
#include "utils/array.h"
|
2000-06-15 05:33:12 +02:00
|
|
|
#include "utils/varbit.h"
|
2000-04-08 04:13:11 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
#define HEXDIG(z) ((z)<10 ? ((z)+'0') : ((z)-10+'A'))
|
|
|
|
|
2010-01-25 21:55:32 +01:00
|
|
|
static VarBit *bit_catenate(VarBit *arg1, VarBit *arg2);
|
2010-01-07 21:17:44 +01:00
|
|
|
static VarBit *bitsubstring(VarBit *arg, int32 s, int32 l,
|
2010-02-26 03:01:40 +01:00
|
|
|
bool length_not_specified);
|
2010-01-25 21:55:32 +01:00
|
|
|
static VarBit *bit_overlay(VarBit *t1, VarBit *t2, int sp, int sl);
|
2010-01-07 21:17:44 +01:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
/* common code for bittypmodin and varbittypmodin */
|
|
|
|
static int32
|
|
|
|
anybit_typmodin(ArrayType *ta, const char *typename)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
int32 typmod;
|
|
|
|
int32 *tl;
|
|
|
|
int n;
|
2006-12-30 22:21:56 +01:00
|
|
|
|
2007-06-15 22:56:52 +02:00
|
|
|
tl = ArrayGetIntegerTypmods(ta, &n);
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* we're not too tense about good error message here because grammar
|
|
|
|
* shouldn't allow wrong number of modifiers for BIT
|
|
|
|
*/
|
|
|
|
if (n != 1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("invalid type modifier")));
|
|
|
|
|
|
|
|
if (*tl < 1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("length for type %s must be at least 1",
|
|
|
|
typename)));
|
|
|
|
if (*tl > (MaxAttrSize * BITS_PER_BYTE))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("length for type %s cannot exceed %d",
|
|
|
|
typename, MaxAttrSize * BITS_PER_BYTE)));
|
|
|
|
|
|
|
|
typmod = *tl;
|
|
|
|
|
|
|
|
return typmod;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* common code for bittypmodout and varbittypmodout */
|
|
|
|
static char *
|
|
|
|
anybit_typmodout(int32 typmod)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
char *res = (char *) palloc(64);
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
if (typmod >= 0)
|
|
|
|
snprintf(res, 64, "(%d)", typmod);
|
|
|
|
else
|
|
|
|
*res = '\0';
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
/*----------
|
|
|
|
* attypmod -- contains the length of the bit string in bits, or for
|
|
|
|
* varying bits the maximum length.
|
|
|
|
*
|
|
|
|
* The data structure contains the following elements:
|
|
|
|
* header -- length of the whole data structure (incl header)
|
|
|
|
* in bytes. (as with all varying length datatypes)
|
|
|
|
* data section -- private data section for the bits data structures
|
|
|
|
* bitlength -- length of the bit string in bits
|
|
|
|
* bitdata -- bit string, most significant byte first
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
*
|
|
|
|
* The length of the bitdata vector should always be exactly as many
|
|
|
|
* bytes as are needed for the given bitlength. If the bitlength is
|
|
|
|
* not a multiple of 8, the extra low-order padding bits of the last
|
|
|
|
* byte must be zeroes.
|
2000-08-21 06:48:57 +02:00
|
|
|
*----------
|
|
|
|
*/
|
2000-04-08 04:13:11 +02:00
|
|
|
|
|
|
|
/*
|
2001-05-22 18:37:17 +02:00
|
|
|
* bit_in -
|
2000-08-21 06:48:57 +02:00
|
|
|
* converts a char string to the internal representation of a bitstring.
|
2000-04-12 19:17:23 +02:00
|
|
|
* The length is determined by the number of bits required plus
|
|
|
|
* VARHDRSZ bytes or from atttypmod.
|
2000-04-08 04:13:11 +02:00
|
|
|
*/
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
2001-05-22 18:37:17 +02:00
|
|
|
bit_in(PG_FUNCTION_ARGS)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2000-11-18 17:18:41 +01:00
|
|
|
char *input_string = PG_GETARG_CSTRING(0);
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
#ifdef NOT_USED
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
#endif
|
|
|
|
int32 atttypmod = PG_GETARG_INT32(2);
|
|
|
|
VarBit *result; /* The resulting bit string */
|
2000-04-12 19:17:23 +02:00
|
|
|
char *sp; /* pointer into the character string */
|
2000-08-21 06:48:57 +02:00
|
|
|
bits8 *r; /* pointer into the result */
|
2000-04-12 19:17:23 +02:00
|
|
|
int len, /* Length of the whole data structure */
|
|
|
|
bitlen, /* Number of bits in the bit string */
|
|
|
|
slen; /* Length of the input string */
|
2000-08-21 06:48:57 +02:00
|
|
|
bool bit_not_hex; /* false = hex string true = bit string */
|
2001-05-22 18:37:17 +02:00
|
|
|
int bc;
|
2000-04-12 19:17:23 +02:00
|
|
|
bits8 x = 0;
|
|
|
|
|
|
|
|
/* Check that the first character is a b or an x */
|
2000-11-18 17:18:41 +01:00
|
|
|
if (input_string[0] == 'b' || input_string[0] == 'B')
|
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
bit_not_hex = true;
|
2000-11-18 17:18:41 +01:00
|
|
|
sp = input_string + 1;
|
|
|
|
}
|
|
|
|
else if (input_string[0] == 'x' || input_string[0] == 'X')
|
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
bit_not_hex = false;
|
2000-11-18 17:18:41 +01:00
|
|
|
sp = input_string + 1;
|
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
else
|
2000-08-21 06:48:57 +02:00
|
|
|
{
|
2000-11-18 17:18:41 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Otherwise it's binary. This allows things like cast('1001' as bit)
|
|
|
|
* to work transparently.
|
2000-11-18 17:18:41 +01:00
|
|
|
*/
|
|
|
|
bit_not_hex = true;
|
|
|
|
sp = input_string;
|
2000-08-21 06:48:57 +02:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-11-18 17:18:41 +01:00
|
|
|
slen = strlen(sp);
|
2000-04-12 19:17:23 +02:00
|
|
|
/* Determine bitlength from input string */
|
2000-08-21 06:48:57 +02:00
|
|
|
if (bit_not_hex)
|
|
|
|
bitlen = slen;
|
|
|
|
else
|
|
|
|
bitlen = slen * 4;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Sometimes atttypmod is not supplied. If it is supplied we need to make
|
|
|
|
* sure that the bitstring fits.
|
2000-04-12 19:17:23 +02:00
|
|
|
*/
|
2000-08-21 06:48:57 +02:00
|
|
|
if (atttypmod <= 0)
|
2000-04-12 19:17:23 +02:00
|
|
|
atttypmod = bitlen;
|
2001-05-22 18:37:17 +02:00
|
|
|
else if (bitlen != atttypmod)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("bit string length %d does not match type bit(%d)",
|
|
|
|
bitlen, atttypmod)));
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
len = VARBITTOTALLEN(atttypmod);
|
|
|
|
/* set to 0 so that *r is always initialised and string is zero-padded */
|
2002-11-13 01:39:48 +01:00
|
|
|
result = (VarBit *) palloc0(len);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, len);
|
2000-04-12 19:17:23 +02:00
|
|
|
VARBITLEN(result) = atttypmod;
|
|
|
|
|
|
|
|
r = VARBITS(result);
|
|
|
|
if (bit_not_hex)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
/* Parse the bit representation of the string */
|
|
|
|
/* We know it fits, as bitlen was compared to atttypmod */
|
2005-12-25 03:14:19 +01:00
|
|
|
x = HIGHBIT;
|
2000-08-21 06:48:57 +02:00
|
|
|
for (; *sp; sp++)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
|
|
|
if (*sp == '1')
|
|
|
|
*r |= x;
|
2000-08-21 06:48:57 +02:00
|
|
|
else if (*sp != '0')
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("\"%c\" is not a valid binary digit",
|
|
|
|
*sp)));
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
x >>= 1;
|
|
|
|
if (x == 0)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2005-12-25 03:14:19 +01:00
|
|
|
x = HIGHBIT;
|
2000-04-12 19:17:23 +02:00
|
|
|
r++;
|
|
|
|
}
|
|
|
|
}
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
else
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
/* Parse the hex representation of the string */
|
2000-08-21 06:48:57 +02:00
|
|
|
for (bc = 0; *sp; sp++)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
|
|
|
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
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("\"%c\" is not a valid hexadecimal digit",
|
2003-07-27 06:53:12 +02:00
|
|
|
*sp)));
|
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
if (bc)
|
|
|
|
{
|
|
|
|
*r++ |= x;
|
2000-08-21 06:48:57 +02:00
|
|
|
bc = 0;
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*r = x << 4;
|
2000-08-21 06:48:57 +02:00
|
|
|
bc = 1;
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
|
|
|
}
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_VARBIT_P(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
2001-05-22 18:37:17 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
2001-05-22 18:37:17 +02:00
|
|
|
bit_out(PG_FUNCTION_ARGS)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-11-16 22:43:28 +01:00
|
|
|
#if 1
|
|
|
|
/* same as varbit output */
|
|
|
|
return varbit_out(fcinfo);
|
|
|
|
#else
|
|
|
|
/* This is how one would print a hex string, in case someone wants to
|
|
|
|
write a formatting function. */
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *s = PG_GETARG_VARBIT_P(0);
|
2000-04-12 19:17:23 +02:00
|
|
|
char *result,
|
|
|
|
*r;
|
|
|
|
bits8 *sp;
|
|
|
|
int i,
|
|
|
|
len,
|
|
|
|
bitlen;
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
bitlen = VARBITLEN(s);
|
|
|
|
len = (bitlen + 3) / 4;
|
|
|
|
result = (char *) palloc(len + 2);
|
|
|
|
sp = VARBITS(s);
|
|
|
|
r = result;
|
|
|
|
*r++ = 'X';
|
|
|
|
/* we cheat by knowing that we store full bytes zero padded */
|
|
|
|
for (i = 0; i < len; i += 2, sp++)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
*r++ = HEXDIG((*sp) >> 4);
|
|
|
|
*r++ = HEXDIG((*sp) & 0xF);
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Go back one step if we printed a hex number that was not part of the
|
|
|
|
* bitstring anymore
|
2000-08-21 06:48:57 +02:00
|
|
|
*/
|
|
|
|
if (i > len)
|
|
|
|
r--;
|
|
|
|
*r = '\0';
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(result);
|
2000-11-16 22:43:28 +01:00
|
|
|
#endif
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
/*
|
|
|
|
* bit_recv - converts external binary format to bit
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
bit_recv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2005-07-10 23:14:00 +02:00
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-07-10 23:14:00 +02:00
|
|
|
#ifdef NOT_USED
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
#endif
|
|
|
|
int32 atttypmod = PG_GETARG_INT32(2);
|
|
|
|
VarBit *result;
|
|
|
|
int len,
|
|
|
|
bitlen;
|
|
|
|
int ipad;
|
|
|
|
bits8 mask;
|
|
|
|
|
|
|
|
bitlen = pq_getmsgint(buf, sizeof(int32));
|
|
|
|
if (bitlen < 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
|
|
|
|
errmsg("invalid length in external bit string")));
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Sometimes atttypmod is not supplied. If it is supplied we need to make
|
|
|
|
* sure that the bitstring fits.
|
2005-07-10 23:14:00 +02:00
|
|
|
*/
|
|
|
|
if (atttypmod > 0 && bitlen != atttypmod)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("bit string length %d does not match type bit(%d)",
|
|
|
|
bitlen, atttypmod)));
|
2005-07-10 23:14:00 +02:00
|
|
|
|
|
|
|
len = VARBITTOTALLEN(bitlen);
|
|
|
|
result = (VarBit *) palloc(len);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, len);
|
2005-07-10 23:14:00 +02:00
|
|
|
VARBITLEN(result) = bitlen;
|
|
|
|
|
|
|
|
pq_copymsgbytes(buf, (char *) VARBITS(result), VARBITBYTES(result));
|
|
|
|
|
|
|
|
/* Make sure last byte is zero-padded if needed */
|
|
|
|
ipad = VARBITPAD(result);
|
|
|
|
if (ipad > 0)
|
|
|
|
{
|
|
|
|
mask = BITMASK << ipad;
|
|
|
|
*(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_VARBIT_P(result);
|
2003-05-13 01:08:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bit_send - converts bit to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
bit_send(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as varbit_send, so share code */
|
|
|
|
return varbit_send(fcinfo);
|
|
|
|
}
|
|
|
|
|
2001-05-22 18:37:17 +02:00
|
|
|
/* bit()
|
2000-08-21 06:48:57 +02:00
|
|
|
* Converts a bit() type to a specific internal length.
|
|
|
|
* len is the bitlength specified in the column definition.
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
*
|
|
|
|
* If doing implicit cast, raise error when source data is wrong length.
|
|
|
|
* If doing explicit cast, silently truncate or zero-pad to specified length.
|
2000-04-08 04:13:11 +02:00
|
|
|
*/
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
2001-05-22 18:37:17 +02:00
|
|
|
bit(PG_FUNCTION_ARGS)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg = PG_GETARG_VARBIT_P(0);
|
|
|
|
int32 len = PG_GETARG_INT32(1);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
bool isExplicit = PG_GETARG_BOOL(2);
|
|
|
|
VarBit *result;
|
|
|
|
int rlen;
|
|
|
|
int ipad;
|
|
|
|
bits8 mask;
|
2000-08-21 06:48:57 +02:00
|
|
|
|
|
|
|
/* No work if typmod is invalid or supplied data matches it already */
|
|
|
|
if (len <= 0 || len == VARBITLEN(arg))
|
|
|
|
PG_RETURN_VARBIT_P(arg);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
|
|
|
|
if (!isExplicit)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("bit string length %d does not match type bit(%d)",
|
|
|
|
VARBITLEN(arg), len)));
|
2000-04-08 04:13:11 +02:00
|
|
|
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
rlen = VARBITTOTALLEN(len);
|
|
|
|
/* set to 0 so that string is zero-padded */
|
2002-11-13 01:39:48 +01:00
|
|
|
result = (VarBit *) palloc0(rlen);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, rlen);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
VARBITLEN(result) = len;
|
|
|
|
|
|
|
|
memcpy(VARBITS(result), VARBITS(arg),
|
|
|
|
Min(VARBITBYTES(result), VARBITBYTES(arg)));
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Make sure last byte is zero-padded if needed. This is useless but safe
|
|
|
|
* if source data was shorter than target length (we assume the last byte
|
|
|
|
* of the source data was itself correctly zero-padded).
|
2000-08-21 06:48:57 +02:00
|
|
|
*/
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
ipad = VARBITPAD(result);
|
|
|
|
if (ipad > 0)
|
|
|
|
{
|
|
|
|
mask = BITMASK << ipad;
|
|
|
|
*(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
|
|
|
|
}
|
2000-08-21 06:48:57 +02:00
|
|
|
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
PG_RETURN_VARBIT_P(result);
|
2000-08-21 06:48:57 +02:00
|
|
|
}
|
2000-04-08 04:13:11 +02:00
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
Datum
|
|
|
|
bittypmodin(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
PG_RETURN_INT32(anybit_typmodin(ta, "bit"));
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
bittypmodout(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
int32 typmod = PG_GETARG_INT32(0);
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
PG_RETURN_CSTRING(anybit_typmodout(typmod));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-04-08 04:13:11 +02:00
|
|
|
/*
|
|
|
|
* varbit_in -
|
|
|
|
* converts a string to the internal representation of a bitstring.
|
2001-05-22 18:37:17 +02:00
|
|
|
* This is the same as bit_in except that atttypmod is taken as
|
2000-08-21 06:48:57 +02:00
|
|
|
* the maximum length, not the exact length to force the bitstring to.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
varbit_in(PG_FUNCTION_ARGS)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2000-11-18 17:18:41 +01:00
|
|
|
char *input_string = PG_GETARG_CSTRING(0);
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
#ifdef NOT_USED
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
#endif
|
|
|
|
int32 atttypmod = PG_GETARG_INT32(2);
|
|
|
|
VarBit *result; /* The resulting bit string */
|
2000-04-12 19:17:23 +02:00
|
|
|
char *sp; /* pointer into the character string */
|
2000-08-21 06:48:57 +02:00
|
|
|
bits8 *r; /* pointer into the result */
|
2000-04-12 19:17:23 +02:00
|
|
|
int len, /* Length of the whole data structure */
|
|
|
|
bitlen, /* Number of bits in the bit string */
|
|
|
|
slen; /* Length of the input string */
|
2000-08-21 06:48:57 +02:00
|
|
|
bool bit_not_hex; /* false = hex string true = bit string */
|
2001-05-22 18:37:17 +02:00
|
|
|
int bc;
|
2000-04-12 19:17:23 +02:00
|
|
|
bits8 x = 0;
|
|
|
|
|
|
|
|
/* Check that the first character is a b or an x */
|
2000-11-18 17:18:41 +01:00
|
|
|
if (input_string[0] == 'b' || input_string[0] == 'B')
|
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
bit_not_hex = true;
|
2000-11-18 17:18:41 +01:00
|
|
|
sp = input_string + 1;
|
|
|
|
}
|
|
|
|
else if (input_string[0] == 'x' || input_string[0] == 'X')
|
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
bit_not_hex = false;
|
2000-11-18 17:18:41 +01:00
|
|
|
sp = input_string + 1;
|
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
else
|
2000-08-21 06:48:57 +02:00
|
|
|
{
|
2000-11-18 17:18:41 +01:00
|
|
|
bit_not_hex = true;
|
|
|
|
sp = input_string;
|
2000-08-21 06:48:57 +02:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-11-18 17:18:41 +01:00
|
|
|
slen = strlen(sp);
|
2000-04-12 19:17:23 +02:00
|
|
|
/* Determine bitlength from input string */
|
2000-08-21 06:48:57 +02:00
|
|
|
if (bit_not_hex)
|
|
|
|
bitlen = slen;
|
|
|
|
else
|
|
|
|
bitlen = slen * 4;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Sometimes atttypmod is not supplied. If it is supplied we need to make
|
|
|
|
* sure that the bitstring fits.
|
2000-04-12 19:17:23 +02:00
|
|
|
*/
|
2000-08-21 06:48:57 +02:00
|
|
|
if (atttypmod <= 0)
|
|
|
|
atttypmod = bitlen;
|
2001-05-22 18:37:17 +02:00
|
|
|
else if (bitlen > atttypmod)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
2004-08-02 18:51:10 +02:00
|
|
|
(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
|
2003-07-27 06:53:12 +02:00
|
|
|
errmsg("bit string too long for type bit varying(%d)",
|
2003-08-04 02:43:34 +02:00
|
|
|
atttypmod)));
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
len = VARBITTOTALLEN(bitlen);
|
|
|
|
/* set to 0 so that *r is always initialised and string is zero-padded */
|
2002-11-13 01:39:48 +01:00
|
|
|
result = (VarBit *) palloc0(len);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, len);
|
2000-08-21 06:48:57 +02:00
|
|
|
VARBITLEN(result) = Min(bitlen, atttypmod);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
|
|
|
r = VARBITS(result);
|
|
|
|
if (bit_not_hex)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
/* Parse the bit representation of the string */
|
2000-08-21 06:48:57 +02:00
|
|
|
/* We know it fits, as bitlen was compared to atttypmod */
|
2005-12-25 03:14:19 +01:00
|
|
|
x = HIGHBIT;
|
2000-08-21 06:48:57 +02:00
|
|
|
for (; *sp; sp++)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
|
|
|
if (*sp == '1')
|
|
|
|
*r |= x;
|
2000-08-21 06:48:57 +02:00
|
|
|
else if (*sp != '0')
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("\"%c\" is not a valid binary digit",
|
|
|
|
*sp)));
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
x >>= 1;
|
|
|
|
if (x == 0)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2005-12-25 03:14:19 +01:00
|
|
|
x = HIGHBIT;
|
2000-04-12 19:17:23 +02:00
|
|
|
r++;
|
|
|
|
}
|
|
|
|
}
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
else
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
/* Parse the hex representation of the string */
|
|
|
|
for (bc = 0; *sp; sp++)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
|
|
|
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
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("\"%c\" is not a valid hexadecimal digit",
|
2003-07-27 06:53:12 +02:00
|
|
|
*sp)));
|
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
if (bc)
|
|
|
|
{
|
|
|
|
*r++ |= x;
|
2000-08-21 06:48:57 +02:00
|
|
|
bc = 0;
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*r = x << 4;
|
2000-08-21 06:48:57 +02:00
|
|
|
bc = 1;
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
|
|
|
}
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_VARBIT_P(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
/* varbit_out -
|
|
|
|
* Prints the string as bits to preserve length accurately
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
varbit_out(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
VarBit *s = PG_GETARG_VARBIT_P(0);
|
|
|
|
char *result,
|
|
|
|
*r;
|
|
|
|
bits8 *sp;
|
|
|
|
bits8 x;
|
|
|
|
int i,
|
|
|
|
k,
|
|
|
|
len;
|
|
|
|
|
|
|
|
len = VARBITLEN(s);
|
2000-11-18 17:18:41 +01:00
|
|
|
result = (char *) palloc(len + 1);
|
2000-08-21 06:48:57 +02:00
|
|
|
sp = VARBITS(s);
|
|
|
|
r = result;
|
2007-08-21 04:40:06 +02:00
|
|
|
for (i = 0; i <= len - BITS_PER_BYTE; i += BITS_PER_BYTE, sp++)
|
2000-08-21 06:48:57 +02:00
|
|
|
{
|
2007-08-21 04:40:06 +02:00
|
|
|
/* print full bytes */
|
2000-08-21 06:48:57 +02:00
|
|
|
x = *sp;
|
2000-08-26 23:53:44 +02:00
|
|
|
for (k = 0; k < BITS_PER_BYTE; k++)
|
2000-08-21 06:48:57 +02:00
|
|
|
{
|
2005-12-25 03:14:19 +01:00
|
|
|
*r++ = IS_HIGHBIT_SET(x) ? '1' : '0';
|
2000-08-21 06:48:57 +02:00
|
|
|
x <<= 1;
|
|
|
|
}
|
|
|
|
}
|
2007-08-21 04:40:06 +02:00
|
|
|
if (i < len)
|
2000-08-21 06:48:57 +02:00
|
|
|
{
|
2007-08-21 04:40:06 +02:00
|
|
|
/* print the last partial byte */
|
|
|
|
x = *sp;
|
|
|
|
for (k = i; k < len; k++)
|
|
|
|
{
|
|
|
|
*r++ = IS_HIGHBIT_SET(x) ? '1' : '0';
|
|
|
|
x <<= 1;
|
|
|
|
}
|
2000-08-21 06:48:57 +02:00
|
|
|
}
|
|
|
|
*r = '\0';
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
/*
|
|
|
|
* varbit_recv - converts external binary format to varbit
|
|
|
|
*
|
|
|
|
* External format is the bitlen as an int32, then the byte array.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
varbit_recv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-07-10 23:14:00 +02:00
|
|
|
#ifdef NOT_USED
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
#endif
|
|
|
|
int32 atttypmod = PG_GETARG_INT32(2);
|
2003-05-13 01:08:52 +02:00
|
|
|
VarBit *result;
|
|
|
|
int len,
|
|
|
|
bitlen;
|
|
|
|
int ipad;
|
|
|
|
bits8 mask;
|
|
|
|
|
|
|
|
bitlen = pq_getmsgint(buf, sizeof(int32));
|
|
|
|
if (bitlen < 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
|
|
|
|
errmsg("invalid length in external bit string")));
|
2003-05-13 01:08:52 +02:00
|
|
|
|
2005-07-10 23:14:00 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Sometimes atttypmod is not supplied. If it is supplied we need to make
|
|
|
|
* sure that the bitstring fits.
|
2005-07-10 23:14:00 +02:00
|
|
|
*/
|
|
|
|
if (atttypmod > 0 && bitlen > atttypmod)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
|
|
|
|
errmsg("bit string too long for type bit varying(%d)",
|
|
|
|
atttypmod)));
|
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
len = VARBITTOTALLEN(bitlen);
|
|
|
|
result = (VarBit *) palloc(len);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, len);
|
2003-05-13 01:08:52 +02:00
|
|
|
VARBITLEN(result) = bitlen;
|
|
|
|
|
|
|
|
pq_copymsgbytes(buf, (char *) VARBITS(result), VARBITBYTES(result));
|
|
|
|
|
|
|
|
/* Make sure last byte is zero-padded if needed */
|
|
|
|
ipad = VARBITPAD(result);
|
|
|
|
if (ipad > 0)
|
|
|
|
{
|
|
|
|
mask = BITMASK << ipad;
|
|
|
|
*(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_VARBIT_P(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* varbit_send - converts varbit to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
varbit_send(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
VarBit *s = PG_GETARG_VARBIT_P(0);
|
|
|
|
StringInfoData buf;
|
|
|
|
|
|
|
|
pq_begintypsend(&buf);
|
|
|
|
pq_sendint(&buf, VARBITLEN(s), sizeof(int32));
|
2005-09-24 19:53:28 +02:00
|
|
|
pq_sendbytes(&buf, (char *) VARBITS(s), VARBITBYTES(s));
|
2003-05-13 01:08:52 +02:00
|
|
|
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
|
|
|
}
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
/* varbit()
|
|
|
|
* Converts a varbit() type to a specific internal length.
|
|
|
|
* len is the maximum bitlength specified in the column definition.
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
*
|
|
|
|
* If doing implicit cast, raise error when source data is too long.
|
|
|
|
* If doing explicit cast, silently truncate to max length.
|
2000-08-21 06:48:57 +02:00
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
varbit(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
VarBit *arg = PG_GETARG_VARBIT_P(0);
|
|
|
|
int32 len = PG_GETARG_INT32(1);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
bool isExplicit = PG_GETARG_BOOL(2);
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *result;
|
|
|
|
int rlen;
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
int ipad;
|
|
|
|
bits8 mask;
|
2000-08-21 06:48:57 +02:00
|
|
|
|
|
|
|
/* No work if typmod is invalid or supplied data matches it already */
|
|
|
|
if (len <= 0 || len >= VARBITLEN(arg))
|
|
|
|
PG_RETURN_VARBIT_P(arg);
|
|
|
|
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
if (!isExplicit)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
2004-08-02 18:51:10 +02:00
|
|
|
(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
|
2003-07-27 06:53:12 +02:00
|
|
|
errmsg("bit string too long for type bit varying(%d)",
|
2003-08-04 02:43:34 +02:00
|
|
|
len)));
|
2001-05-22 18:37:17 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
rlen = VARBITTOTALLEN(len);
|
|
|
|
result = (VarBit *) palloc(rlen);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, rlen);
|
2000-08-21 06:48:57 +02:00
|
|
|
VARBITLEN(result) = len;
|
|
|
|
|
|
|
|
memcpy(VARBITS(result), VARBITS(arg), VARBITBYTES(result));
|
|
|
|
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
/* Make sure last byte is zero-padded if needed */
|
|
|
|
ipad = VARBITPAD(result);
|
|
|
|
if (ipad > 0)
|
|
|
|
{
|
|
|
|
mask = BITMASK << ipad;
|
|
|
|
*(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
|
|
|
|
}
|
2000-08-21 06:48:57 +02:00
|
|
|
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
PG_RETURN_VARBIT_P(result);
|
2000-08-21 06:48:57 +02:00
|
|
|
}
|
2000-04-08 04:13:11 +02:00
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
Datum
|
|
|
|
varbittypmodin(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
PG_RETURN_INT32(anybit_typmodin(ta, "varbit"));
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
varbittypmodout(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
int32 typmod = PG_GETARG_INT32(0);
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
PG_RETURN_CSTRING(anybit_typmodout(typmod));
|
|
|
|
}
|
|
|
|
|
2000-04-08 04:13:11 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Comparison operators
|
|
|
|
*
|
|
|
|
* We only need one set of comparison operators for bitstrings, as the lengths
|
2000-04-12 19:17:23 +02:00
|
|
|
* are stored in the same way for zero-padded and varying bit strings.
|
2000-04-08 04:13:11 +02:00
|
|
|
*
|
2000-04-12 19:17:23 +02:00
|
|
|
* Note that the standard is not unambiguous about the comparison between
|
2000-04-08 04:13:11 +02:00
|
|
|
* zero-padded bit strings and varying bitstrings. If the same value is written
|
2000-04-12 19:17:23 +02:00
|
|
|
* into a zero padded bitstring as into a varying bitstring, but the zero
|
|
|
|
* padded bitstring has greater length, it will be bigger.
|
2000-04-08 04:13:11 +02:00
|
|
|
*
|
|
|
|
* Zeros from the beginning of a bitstring cannot simply be ignored, as they
|
|
|
|
* may be part of a bit string and may be significant.
|
2000-08-21 06:48:57 +02:00
|
|
|
*
|
|
|
|
* Note: btree indexes need these routines not to leak memory; therefore,
|
|
|
|
* be careful to free working copies of toasted datums. Most places don't
|
|
|
|
* need to be so careful.
|
2000-04-08 04:13:11 +02:00
|
|
|
*/
|
|
|
|
|
2001-05-03 21:00:37 +02:00
|
|
|
/* bit_cmp
|
|
|
|
*
|
|
|
|
* Compares two bitstrings and returns <0, 0, >0 depending on whether the first
|
|
|
|
* string is smaller, equal, or bigger than the second. All bits are considered
|
|
|
|
* and additional zero bits may make one string smaller/larger than the other,
|
|
|
|
* even if their zero-padded values would be the same.
|
|
|
|
*/
|
|
|
|
static int32
|
|
|
|
bit_cmp(VarBit *arg1, VarBit *arg2)
|
|
|
|
{
|
|
|
|
int bitlen1,
|
|
|
|
bytelen1,
|
|
|
|
bitlen2,
|
|
|
|
bytelen2;
|
|
|
|
int32 cmp;
|
|
|
|
|
|
|
|
bytelen1 = VARBITBYTES(arg1);
|
|
|
|
bytelen2 = VARBITBYTES(arg2);
|
|
|
|
|
|
|
|
cmp = memcmp(VARBITS(arg1), VARBITS(arg2), Min(bytelen1, bytelen2));
|
|
|
|
if (cmp == 0)
|
|
|
|
{
|
|
|
|
bitlen1 = VARBITLEN(arg1);
|
|
|
|
bitlen2 = VARBITLEN(arg2);
|
|
|
|
if (bitlen1 != bitlen2)
|
|
|
|
cmp = (bitlen1 < bitlen2) ? -1 : 1;
|
|
|
|
}
|
|
|
|
return cmp;
|
|
|
|
}
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
biteq(PG_FUNCTION_ARGS)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
|
|
|
bool result;
|
2000-04-12 19:17:23 +02:00
|
|
|
int bitlen1,
|
|
|
|
bitlen2;
|
|
|
|
|
|
|
|
bitlen1 = VARBITLEN(arg1);
|
|
|
|
bitlen2 = VARBITLEN(arg2);
|
2001-05-03 21:00:37 +02:00
|
|
|
|
|
|
|
/* fast path for different-length inputs */
|
2000-04-12 19:17:23 +02:00
|
|
|
if (bitlen1 != bitlen2)
|
2000-08-21 06:48:57 +02:00
|
|
|
result = false;
|
|
|
|
else
|
2001-05-03 21:00:37 +02:00
|
|
|
result = (bit_cmp(arg1, arg2) == 0);
|
2000-08-21 06:48:57 +02:00
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
2000-04-08 04:13:11 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_BOOL(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
bitne(PG_FUNCTION_ARGS)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
|
|
|
bool result;
|
2000-04-12 19:17:23 +02:00
|
|
|
int bitlen1,
|
|
|
|
bitlen2;
|
2000-04-08 04:13:11 +02:00
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
bitlen1 = VARBITLEN(arg1);
|
|
|
|
bitlen2 = VARBITLEN(arg2);
|
2001-05-03 21:00:37 +02:00
|
|
|
|
|
|
|
/* fast path for different-length inputs */
|
2000-04-12 19:17:23 +02:00
|
|
|
if (bitlen1 != bitlen2)
|
2000-08-21 06:48:57 +02:00
|
|
|
result = true;
|
|
|
|
else
|
2001-05-03 21:00:37 +02:00
|
|
|
result = (bit_cmp(arg1, arg2) != 0);
|
2000-08-21 06:48:57 +02:00
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_BOOL(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
bitlt(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
|
|
|
bool result;
|
|
|
|
|
|
|
|
result = (bit_cmp(arg1, arg2) < 0);
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
bitle(PG_FUNCTION_ARGS)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
|
|
|
bool result;
|
|
|
|
|
|
|
|
result = (bit_cmp(arg1, arg2) <= 0);
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
bitgt(PG_FUNCTION_ARGS)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
|
|
|
bool result;
|
|
|
|
|
|
|
|
result = (bit_cmp(arg1, arg2) > 0);
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
bitge(PG_FUNCTION_ARGS)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
|
|
|
bool result;
|
|
|
|
|
|
|
|
result = (bit_cmp(arg1, arg2) >= 0);
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
bitcmp(PG_FUNCTION_ARGS)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
|
|
|
int32 result;
|
|
|
|
|
|
|
|
result = bit_cmp(arg1, arg2);
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
PG_RETURN_INT32(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* bitcat
|
|
|
|
* Concatenation of bit strings
|
|
|
|
*/
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
bitcat(PG_FUNCTION_ARGS)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
2010-01-25 21:55:32 +01:00
|
|
|
|
|
|
|
PG_RETURN_VARBIT_P(bit_catenate(arg1, arg2));
|
|
|
|
}
|
|
|
|
|
|
|
|
static VarBit *
|
|
|
|
bit_catenate(VarBit *arg1, VarBit *arg2)
|
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *result;
|
2000-04-12 19:17:23 +02:00
|
|
|
int bitlen1,
|
|
|
|
bitlen2,
|
|
|
|
bytelen,
|
|
|
|
bit1pad,
|
|
|
|
bit2shift;
|
|
|
|
bits8 *pr,
|
|
|
|
*pa;
|
|
|
|
|
|
|
|
bitlen1 = VARBITLEN(arg1);
|
|
|
|
bitlen2 = VARBITLEN(arg2);
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
bytelen = VARBITTOTALLEN(bitlen1 + bitlen2);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
result = (VarBit *) palloc(bytelen);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, bytelen);
|
2000-04-12 19:17:23 +02:00
|
|
|
VARBITLEN(result) = bitlen1 + bitlen2;
|
2000-08-21 06:48:57 +02:00
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
/* Copy the first bitstring in */
|
|
|
|
memcpy(VARBITS(result), VARBITS(arg1), VARBITBYTES(arg1));
|
2000-08-21 06:48:57 +02:00
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
/* Copy the second bit string */
|
|
|
|
bit1pad = VARBITPAD(arg1);
|
|
|
|
if (bit1pad == 0)
|
|
|
|
{
|
|
|
|
memcpy(VARBITS(result) + VARBITBYTES(arg1), VARBITS(arg2),
|
|
|
|
VARBITBYTES(arg2));
|
|
|
|
}
|
|
|
|
else if (bitlen2 > 0)
|
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
/* We need to shift all the bits to fit */
|
2000-08-26 23:53:44 +02:00
|
|
|
bit2shift = BITS_PER_BYTE - bit1pad;
|
2000-04-12 19:17:23 +02:00
|
|
|
pr = VARBITS(result) + VARBITBYTES(arg1) - 1;
|
2000-08-21 06:48:57 +02:00
|
|
|
for (pa = VARBITS(arg2); pa < VARBITEND(arg2); pa++)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
|
|
|
*pr |= ((*pa >> bit2shift) & BITMASK);
|
|
|
|
pr++;
|
|
|
|
if (pr < VARBITEND(result))
|
|
|
|
*pr = (*pa << bit1pad) & BITMASK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-25 21:55:32 +01:00
|
|
|
return result;
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* bitsubstr
|
2000-04-12 19:17:23 +02:00
|
|
|
* retrieve a substring from the bit string.
|
2000-04-08 04:13:11 +02:00
|
|
|
* Note, s is 1-based.
|
|
|
|
* SQL draft 6.10 9)
|
|
|
|
*/
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
bitsubstr(PG_FUNCTION_ARGS)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2010-01-07 21:17:44 +01:00
|
|
|
PG_RETURN_VARBIT_P(bitsubstring(PG_GETARG_VARBIT_P(0),
|
|
|
|
PG_GETARG_INT32(1),
|
|
|
|
PG_GETARG_INT32(2),
|
|
|
|
false));
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
bitsubstr_no_len(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_VARBIT_P(bitsubstring(PG_GETARG_VARBIT_P(0),
|
|
|
|
PG_GETARG_INT32(1),
|
|
|
|
-1, true));
|
|
|
|
}
|
|
|
|
|
|
|
|
static VarBit *
|
|
|
|
bitsubstring(VarBit *arg, int32 s, int32 l, bool length_not_specified)
|
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *result;
|
2000-04-12 19:17:23 +02:00
|
|
|
int bitlen,
|
|
|
|
rbitlen,
|
|
|
|
len,
|
|
|
|
ipad = 0,
|
|
|
|
ishift,
|
|
|
|
i;
|
|
|
|
int e,
|
|
|
|
s1,
|
|
|
|
e1;
|
|
|
|
bits8 mask,
|
|
|
|
*r,
|
|
|
|
*ps;
|
|
|
|
|
|
|
|
bitlen = VARBITLEN(arg);
|
|
|
|
s1 = Max(s, 1);
|
2010-01-07 20:53:11 +01:00
|
|
|
/* If we do not have an upper bound, use end of string */
|
2010-01-07 21:17:44 +01:00
|
|
|
if (length_not_specified)
|
2010-01-07 20:53:11 +01:00
|
|
|
{
|
|
|
|
e1 = bitlen + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
e = s + l;
|
2010-02-26 03:01:40 +01:00
|
|
|
|
2010-01-07 21:17:44 +01:00
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* A negative value for L is the only way for the end position to be
|
|
|
|
* before the start. SQL99 says to throw an error.
|
2010-01-07 21:17:44 +01:00
|
|
|
*/
|
2010-01-07 20:53:11 +01:00
|
|
|
if (e < s)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SUBSTRING_ERROR),
|
|
|
|
errmsg("negative substring length not allowed")));
|
|
|
|
e1 = Min(e, bitlen + 1);
|
|
|
|
}
|
|
|
|
if (s1 > bitlen || e1 <= s1)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
/* Need to return a zero-length bitstring */
|
|
|
|
len = VARBITTOTALLEN(0);
|
|
|
|
result = (VarBit *) palloc(len);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, len);
|
2000-08-21 06:48:57 +02:00
|
|
|
VARBITLEN(result) = 0;
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
else
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* OK, we've got a true substring starting at position s1-1 and ending
|
|
|
|
* at position e1-1
|
2000-04-12 19:17:23 +02:00
|
|
|
*/
|
|
|
|
rbitlen = e1 - s1;
|
2000-08-21 06:48:57 +02:00
|
|
|
len = VARBITTOTALLEN(rbitlen);
|
|
|
|
result = (VarBit *) palloc(len);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, len);
|
2000-08-21 06:48:57 +02:00
|
|
|
VARBITLEN(result) = rbitlen;
|
2000-04-12 19:17:23 +02:00
|
|
|
len -= VARHDRSZ + VARBITHDRSZ;
|
|
|
|
/* Are we copying from a byte boundary? */
|
2000-08-26 23:53:44 +02:00
|
|
|
if ((s1 - 1) % BITS_PER_BYTE == 0)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
|
|
|
/* Yep, we are copying bytes */
|
2000-08-26 23:53:44 +02:00
|
|
|
memcpy(VARBITS(result), VARBITS(arg) + (s1 - 1) / BITS_PER_BYTE,
|
2000-08-21 06:48:57 +02:00
|
|
|
len);
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Figure out how much we need to shift the sequence by */
|
2000-08-26 23:53:44 +02:00
|
|
|
ishift = (s1 - 1) % BITS_PER_BYTE;
|
2000-04-12 19:17:23 +02:00
|
|
|
r = VARBITS(result);
|
2000-08-26 23:53:44 +02:00
|
|
|
ps = VARBITS(arg) + (s1 - 1) / BITS_PER_BYTE;
|
2000-04-12 19:17:23 +02:00
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
{
|
|
|
|
*r = (*ps << ishift) & BITMASK;
|
|
|
|
if ((++ps) < VARBITEND(arg))
|
2000-08-26 23:53:44 +02:00
|
|
|
*r |= *ps >> (BITS_PER_BYTE - ishift);
|
2000-04-12 19:17:23 +02:00
|
|
|
r++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Do we need to pad at the end? */
|
|
|
|
ipad = VARBITPAD(result);
|
|
|
|
if (ipad > 0)
|
|
|
|
{
|
|
|
|
mask = BITMASK << ipad;
|
|
|
|
*(VARBITS(result) + len - 1) &= mask;
|
|
|
|
}
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
2010-01-07 21:17:44 +01:00
|
|
|
return result;
|
2000-08-21 06:48:57 +02:00
|
|
|
}
|
|
|
|
|
2010-01-25 21:55:32 +01:00
|
|
|
/*
|
|
|
|
* bitoverlay
|
|
|
|
* Replace specified substring of first string with second
|
|
|
|
*
|
|
|
|
* The SQL standard defines OVERLAY() in terms of substring and concatenation.
|
|
|
|
* This code is a direct implementation of what the standard says.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
bitoverlay(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
VarBit *t1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
VarBit *t2 = PG_GETARG_VARBIT_P(1);
|
2010-02-26 03:01:40 +01:00
|
|
|
int sp = PG_GETARG_INT32(2); /* substring start position */
|
|
|
|
int sl = PG_GETARG_INT32(3); /* substring length */
|
2010-01-25 21:55:32 +01:00
|
|
|
|
|
|
|
PG_RETURN_VARBIT_P(bit_overlay(t1, t2, sp, sl));
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
bitoverlay_no_len(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
VarBit *t1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
VarBit *t2 = PG_GETARG_VARBIT_P(1);
|
2010-02-26 03:01:40 +01:00
|
|
|
int sp = PG_GETARG_INT32(2); /* substring start position */
|
2010-01-25 21:55:32 +01:00
|
|
|
int sl;
|
|
|
|
|
2010-02-26 03:01:40 +01:00
|
|
|
sl = VARBITLEN(t2); /* defaults to length(t2) */
|
2010-01-25 21:55:32 +01:00
|
|
|
PG_RETURN_VARBIT_P(bit_overlay(t1, t2, sp, sl));
|
|
|
|
}
|
|
|
|
|
|
|
|
static VarBit *
|
|
|
|
bit_overlay(VarBit *t1, VarBit *t2, int sp, int sl)
|
|
|
|
{
|
|
|
|
VarBit *result;
|
|
|
|
VarBit *s1;
|
|
|
|
VarBit *s2;
|
|
|
|
int sp_pl_sl;
|
|
|
|
|
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* Check for possible integer-overflow cases. For negative sp, throw a
|
|
|
|
* "substring length" error because that's what should be expected
|
|
|
|
* according to the spec's definition of OVERLAY().
|
2010-01-25 21:55:32 +01:00
|
|
|
*/
|
|
|
|
if (sp <= 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SUBSTRING_ERROR),
|
|
|
|
errmsg("negative substring length not allowed")));
|
|
|
|
sp_pl_sl = sp + sl;
|
|
|
|
if (sp_pl_sl <= sl)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("integer out of range")));
|
|
|
|
|
2010-02-26 03:01:40 +01:00
|
|
|
s1 = bitsubstring(t1, 1, sp - 1, false);
|
2010-01-25 21:55:32 +01:00
|
|
|
s2 = bitsubstring(t1, sp_pl_sl, -1, true);
|
|
|
|
result = bit_catenate(s1, t2);
|
|
|
|
result = bit_catenate(result, s2);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2001-03-22 05:01:46 +01:00
|
|
|
/* bitlength, bitoctetlength
|
2000-08-21 06:48:57 +02:00
|
|
|
* Return the length of a bit string
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
bitlength(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
VarBit *arg = PG_GETARG_VARBIT_P(0);
|
|
|
|
|
|
|
|
PG_RETURN_INT32(VARBITLEN(arg));
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
bitoctetlength(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
VarBit *arg = PG_GETARG_VARBIT_P(0);
|
|
|
|
|
|
|
|
PG_RETURN_INT32(VARBITBYTES(arg));
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* bitand
|
2000-08-21 06:48:57 +02:00
|
|
|
* perform a logical AND on two bit strings.
|
2000-04-08 04:13:11 +02:00
|
|
|
*/
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
bitand(PG_FUNCTION_ARGS)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
|
|
|
VarBit *result;
|
2000-04-12 19:17:23 +02:00
|
|
|
int len,
|
2000-08-21 06:48:57 +02:00
|
|
|
bitlen1,
|
|
|
|
bitlen2,
|
2000-04-12 19:17:23 +02:00
|
|
|
i;
|
|
|
|
bits8 *p1,
|
|
|
|
*p2,
|
|
|
|
*r;
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
bitlen1 = VARBITLEN(arg1);
|
|
|
|
bitlen2 = VARBITLEN(arg2);
|
|
|
|
if (bitlen1 != bitlen2)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
2003-09-15 22:03:37 +02:00
|
|
|
(errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
|
2003-07-27 06:53:12 +02:00
|
|
|
errmsg("cannot AND bit strings of different sizes")));
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
len = VARSIZE(arg1);
|
|
|
|
result = (VarBit *) palloc(len);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, len);
|
2000-08-21 06:48:57 +02:00
|
|
|
VARBITLEN(result) = bitlen1;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
p1 = VARBITS(arg1);
|
|
|
|
p2 = VARBITS(arg2);
|
|
|
|
r = VARBITS(result);
|
|
|
|
for (i = 0; i < VARBITBYTES(arg1); i++)
|
2000-04-12 19:17:23 +02:00
|
|
|
*r++ = *p1++ & *p2++;
|
|
|
|
|
|
|
|
/* Padding is not needed as & of 0 pad is 0 */
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_VARBIT_P(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* bitor
|
2000-08-21 06:48:57 +02:00
|
|
|
* perform a logical OR on two bit strings.
|
2000-04-08 04:13:11 +02:00
|
|
|
*/
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
bitor(PG_FUNCTION_ARGS)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
|
|
|
VarBit *result;
|
2000-04-12 19:17:23 +02:00
|
|
|
int len,
|
2000-08-21 06:48:57 +02:00
|
|
|
bitlen1,
|
|
|
|
bitlen2,
|
2000-04-12 19:17:23 +02:00
|
|
|
i;
|
|
|
|
bits8 *p1,
|
|
|
|
*p2,
|
|
|
|
*r;
|
|
|
|
bits8 mask;
|
2000-04-08 04:13:11 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
bitlen1 = VARBITLEN(arg1);
|
|
|
|
bitlen2 = VARBITLEN(arg2);
|
|
|
|
if (bitlen1 != bitlen2)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
2003-09-15 22:03:37 +02:00
|
|
|
(errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
|
2003-07-27 06:53:12 +02:00
|
|
|
errmsg("cannot OR bit strings of different sizes")));
|
2000-08-21 06:48:57 +02:00
|
|
|
len = VARSIZE(arg1);
|
|
|
|
result = (VarBit *) palloc(len);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, len);
|
2000-08-21 06:48:57 +02:00
|
|
|
VARBITLEN(result) = bitlen1;
|
2000-04-08 04:13:11 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
p1 = VARBITS(arg1);
|
|
|
|
p2 = VARBITS(arg2);
|
|
|
|
r = VARBITS(result);
|
|
|
|
for (i = 0; i < VARBITBYTES(arg1); i++)
|
2000-04-12 19:17:23 +02:00
|
|
|
*r++ = *p1++ | *p2++;
|
2000-04-08 04:13:11 +02:00
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
/* Pad the result */
|
|
|
|
mask = BITMASK << VARBITPAD(result);
|
2000-08-21 06:48:57 +02:00
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
r--;
|
|
|
|
*r &= mask;
|
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_VARBIT_P(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* bitxor
|
2000-08-21 06:48:57 +02:00
|
|
|
* perform a logical XOR on two bit strings.
|
2000-04-08 04:13:11 +02:00
|
|
|
*/
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
bitxor(PG_FUNCTION_ARGS)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
|
|
|
VarBit *result;
|
2000-04-12 19:17:23 +02:00
|
|
|
int len,
|
2000-08-21 06:48:57 +02:00
|
|
|
bitlen1,
|
|
|
|
bitlen2,
|
2000-04-12 19:17:23 +02:00
|
|
|
i;
|
|
|
|
bits8 *p1,
|
|
|
|
*p2,
|
|
|
|
*r;
|
|
|
|
bits8 mask;
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
bitlen1 = VARBITLEN(arg1);
|
|
|
|
bitlen2 = VARBITLEN(arg2);
|
|
|
|
if (bitlen1 != bitlen2)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
2003-09-15 22:03:37 +02:00
|
|
|
(errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
|
2003-07-27 06:53:12 +02:00
|
|
|
errmsg("cannot XOR bit strings of different sizes")));
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
len = VARSIZE(arg1);
|
|
|
|
result = (VarBit *) palloc(len);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, len);
|
2000-08-21 06:48:57 +02:00
|
|
|
VARBITLEN(result) = bitlen1;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
p1 = VARBITS(arg1);
|
|
|
|
p2 = VARBITS(arg2);
|
|
|
|
r = VARBITS(result);
|
|
|
|
for (i = 0; i < VARBITBYTES(arg1); i++)
|
2000-04-12 19:17:23 +02:00
|
|
|
*r++ = *p1++ ^ *p2++;
|
|
|
|
|
|
|
|
/* Pad the result */
|
|
|
|
mask = BITMASK << VARBITPAD(result);
|
2000-08-21 06:48:57 +02:00
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
r--;
|
|
|
|
*r &= mask;
|
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_VARBIT_P(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* bitnot
|
2000-08-21 06:48:57 +02:00
|
|
|
* perform a logical NOT on a bit string.
|
2000-04-08 04:13:11 +02:00
|
|
|
*/
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
bitnot(PG_FUNCTION_ARGS)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg = PG_GETARG_VARBIT_P(0);
|
|
|
|
VarBit *result;
|
2000-04-12 19:17:23 +02:00
|
|
|
bits8 *p,
|
|
|
|
*r;
|
|
|
|
bits8 mask;
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
result = (VarBit *) palloc(VARSIZE(arg));
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, VARSIZE(arg));
|
2000-04-12 19:17:23 +02:00
|
|
|
VARBITLEN(result) = VARBITLEN(arg);
|
2000-04-08 04:13:11 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
p = VARBITS(arg);
|
|
|
|
r = VARBITS(result);
|
|
|
|
for (; p < VARBITEND(arg); p++)
|
2001-03-22 05:01:46 +01:00
|
|
|
*r++ = ~*p;
|
2000-04-08 04:13:11 +02:00
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
/* Pad the result */
|
|
|
|
mask = BITMASK << VARBITPAD(result);
|
2000-08-21 06:48:57 +02:00
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
r--;
|
|
|
|
*r &= mask;
|
|
|
|
}
|
2000-04-08 04:13:11 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_VARBIT_P(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* bitshiftleft
|
2000-08-21 06:48:57 +02:00
|
|
|
* do a left shift (i.e. towards the beginning of the string)
|
2000-04-08 04:13:11 +02:00
|
|
|
*/
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
bitshiftleft(PG_FUNCTION_ARGS)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg = PG_GETARG_VARBIT_P(0);
|
|
|
|
int32 shft = PG_GETARG_INT32(1);
|
|
|
|
VarBit *result;
|
2000-04-12 19:17:23 +02:00
|
|
|
int byte_shift,
|
|
|
|
ishift,
|
|
|
|
len;
|
|
|
|
bits8 *p,
|
|
|
|
*r;
|
|
|
|
|
|
|
|
/* Negative shift is a shift to the right */
|
|
|
|
if (shft < 0)
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_DATUM(DirectFunctionCall2(bitshiftright,
|
|
|
|
VarBitPGetDatum(arg),
|
|
|
|
Int32GetDatum(-shft)));
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
result = (VarBit *) palloc(VARSIZE(arg));
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, VARSIZE(arg));
|
2000-04-12 19:17:23 +02:00
|
|
|
VARBITLEN(result) = VARBITLEN(arg);
|
2000-08-21 06:48:57 +02:00
|
|
|
r = VARBITS(result);
|
|
|
|
|
|
|
|
/* If we shifted all the bits out, return an all-zero string */
|
|
|
|
if (shft >= VARBITLEN(arg))
|
|
|
|
{
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
MemSet(r, 0, VARBITBYTES(arg));
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_VARBIT_P(result);
|
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-08-26 23:53:44 +02:00
|
|
|
byte_shift = shft / BITS_PER_BYTE;
|
|
|
|
ishift = shft % BITS_PER_BYTE;
|
2000-08-21 06:48:57 +02:00
|
|
|
p = VARBITS(arg) + byte_shift;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
|
|
|
if (ishift == 0)
|
|
|
|
{
|
|
|
|
/* Special case: we can do a memcpy */
|
|
|
|
len = VARBITBYTES(arg) - byte_shift;
|
|
|
|
memcpy(r, p, len);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
MemSet(r + len, 0, byte_shift);
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (; p < VARBITEND(arg); r++)
|
|
|
|
{
|
|
|
|
*r = *p << ishift;
|
|
|
|
if ((++p) < VARBITEND(arg))
|
2000-08-26 23:53:44 +02:00
|
|
|
*r |= *p >> (BITS_PER_BYTE - ishift);
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
|
|
|
for (; r < VARBITEND(result); r++)
|
2000-08-21 06:48:57 +02:00
|
|
|
*r = 0;
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_VARBIT_P(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* bitshiftright
|
2000-08-21 06:48:57 +02:00
|
|
|
* do a right shift (i.e. towards the end of the string)
|
2000-04-08 04:13:11 +02:00
|
|
|
*/
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
bitshiftright(PG_FUNCTION_ARGS)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg = PG_GETARG_VARBIT_P(0);
|
|
|
|
int32 shft = PG_GETARG_INT32(1);
|
|
|
|
VarBit *result;
|
2000-04-12 19:17:23 +02:00
|
|
|
int byte_shift,
|
|
|
|
ishift,
|
|
|
|
len;
|
|
|
|
bits8 *p,
|
|
|
|
*r;
|
|
|
|
|
|
|
|
/* Negative shift is a shift to the left */
|
|
|
|
if (shft < 0)
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_DATUM(DirectFunctionCall2(bitshiftleft,
|
2001-03-22 05:01:46 +01:00
|
|
|
VarBitPGetDatum(arg),
|
|
|
|
Int32GetDatum(-shft)));
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
result = (VarBit *) palloc(VARSIZE(arg));
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, VARSIZE(arg));
|
2000-04-12 19:17:23 +02:00
|
|
|
VARBITLEN(result) = VARBITLEN(arg);
|
2000-08-21 06:48:57 +02:00
|
|
|
r = VARBITS(result);
|
|
|
|
|
|
|
|
/* If we shifted all the bits out, return an all-zero string */
|
|
|
|
if (shft >= VARBITLEN(arg))
|
|
|
|
{
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
MemSet(r, 0, VARBITBYTES(arg));
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_VARBIT_P(result);
|
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-08-26 23:53:44 +02:00
|
|
|
byte_shift = shft / BITS_PER_BYTE;
|
|
|
|
ishift = shft % BITS_PER_BYTE;
|
2000-08-21 06:48:57 +02:00
|
|
|
p = VARBITS(arg);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
|
|
|
/* Set the first part of the result to 0 */
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
MemSet(r, 0, byte_shift);
|
2000-08-21 06:48:57 +02:00
|
|
|
r += byte_shift;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
|
|
|
if (ishift == 0)
|
|
|
|
{
|
|
|
|
/* Special case: we can do a memcpy */
|
|
|
|
len = VARBITBYTES(arg) - byte_shift;
|
2000-08-21 06:48:57 +02:00
|
|
|
memcpy(r, p, len);
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
if (r < VARBITEND(result))
|
|
|
|
*r = 0; /* initialize first byte */
|
2000-04-12 19:17:23 +02:00
|
|
|
for (; r < VARBITEND(result); p++)
|
|
|
|
{
|
|
|
|
*r |= *p >> ishift;
|
|
|
|
if ((++r) < VARBITEND(result))
|
2000-08-26 23:53:44 +02:00
|
|
|
*r = (*p << (BITS_PER_BYTE - ishift)) & BITMASK;
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_VARBIT_P(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
2004-06-16 03:27:00 +02:00
|
|
|
/*
|
|
|
|
* This is not defined in any standard. We retain the natural ordering of
|
2001-03-22 05:01:46 +01:00
|
|
|
* bits here, as it just seems more intuitive.
|
2000-08-21 06:48:57 +02:00
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
bitfromint4(PG_FUNCTION_ARGS)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
int32 a = PG_GETARG_INT32(0);
|
2004-06-16 03:27:00 +02:00
|
|
|
int32 typmod = PG_GETARG_INT32(1);
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *result;
|
|
|
|
bits8 *r;
|
2004-06-16 03:27:00 +02:00
|
|
|
int rlen;
|
|
|
|
int destbitsleft,
|
|
|
|
srcbitsleft;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2004-06-16 03:27:00 +02:00
|
|
|
if (typmod <= 0)
|
|
|
|
typmod = 1; /* default bit length */
|
|
|
|
|
|
|
|
rlen = VARBITTOTALLEN(typmod);
|
|
|
|
result = (VarBit *) palloc(rlen);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, rlen);
|
2004-06-16 03:27:00 +02:00
|
|
|
VARBITLEN(result) = typmod;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
r = VARBITS(result);
|
2004-06-16 03:27:00 +02:00
|
|
|
destbitsleft = typmod;
|
|
|
|
srcbitsleft = 32;
|
|
|
|
/* drop any input bits that don't fit */
|
|
|
|
srcbitsleft = Min(srcbitsleft, destbitsleft);
|
|
|
|
/* sign-fill any excess bytes in output */
|
|
|
|
while (destbitsleft >= srcbitsleft + 8)
|
|
|
|
{
|
|
|
|
*r++ = (bits8) ((a < 0) ? BITMASK : 0);
|
|
|
|
destbitsleft -= 8;
|
|
|
|
}
|
|
|
|
/* store first fractional byte */
|
|
|
|
if (destbitsleft > srcbitsleft)
|
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
int val = (int) (a >> (destbitsleft - 8));
|
2009-12-12 20:24:35 +01:00
|
|
|
|
|
|
|
/* Force sign-fill in case the compiler implements >> as zero-fill */
|
|
|
|
if (a < 0)
|
|
|
|
val |= (-1) << (srcbitsleft + 8 - destbitsleft);
|
|
|
|
*r++ = (bits8) (val & BITMASK);
|
2004-06-16 03:27:00 +02:00
|
|
|
destbitsleft -= 8;
|
|
|
|
}
|
|
|
|
/* Now srcbitsleft and destbitsleft are the same, need not track both */
|
|
|
|
/* store whole bytes */
|
|
|
|
while (destbitsleft >= 8)
|
|
|
|
{
|
|
|
|
*r++ = (bits8) ((a >> (destbitsleft - 8)) & BITMASK);
|
|
|
|
destbitsleft -= 8;
|
|
|
|
}
|
|
|
|
/* store last fractional byte */
|
|
|
|
if (destbitsleft > 0)
|
|
|
|
*r = (bits8) ((a << (8 - destbitsleft)) & BITMASK);
|
2000-04-08 04:13:11 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_VARBIT_P(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
Datum
|
|
|
|
bittoint4(PG_FUNCTION_ARGS)
|
2000-04-08 04:13:11 +02:00
|
|
|
{
|
2000-08-21 06:48:57 +02:00
|
|
|
VarBit *arg = PG_GETARG_VARBIT_P(0);
|
|
|
|
uint32 result;
|
|
|
|
bits8 *r;
|
2000-04-08 04:13:11 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
/* Check that the bit string is not too long */
|
2004-06-16 03:27:00 +02:00
|
|
|
if (VARBITLEN(arg) > sizeof(result) * BITS_PER_BYTE)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("integer out of range")));
|
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
result = 0;
|
|
|
|
for (r = VARBITS(arg); r < VARBITEND(arg); r++)
|
|
|
|
{
|
2000-08-26 23:53:44 +02:00
|
|
|
result <<= BITS_PER_BYTE;
|
2000-08-21 06:48:57 +02:00
|
|
|
result |= *r;
|
|
|
|
}
|
|
|
|
/* Now shift the result to take account of the padding at the end */
|
|
|
|
result >>= VARBITPAD(arg);
|
2000-04-08 04:13:11 +02:00
|
|
|
|
2000-08-21 06:48:57 +02:00
|
|
|
PG_RETURN_INT32(result);
|
2000-04-08 04:13:11 +02:00
|
|
|
}
|
2000-10-31 11:22:13 +01:00
|
|
|
|
2002-08-04 08:33:59 +02:00
|
|
|
Datum
|
|
|
|
bitfromint8(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int64 a = PG_GETARG_INT64(0);
|
2004-06-16 03:27:00 +02:00
|
|
|
int32 typmod = PG_GETARG_INT32(1);
|
2002-08-04 08:33:59 +02:00
|
|
|
VarBit *result;
|
|
|
|
bits8 *r;
|
2004-06-16 03:27:00 +02:00
|
|
|
int rlen;
|
|
|
|
int destbitsleft,
|
|
|
|
srcbitsleft;
|
2002-08-04 08:33:59 +02:00
|
|
|
|
2004-06-16 03:27:00 +02:00
|
|
|
if (typmod <= 0)
|
|
|
|
typmod = 1; /* default bit length */
|
2002-08-04 08:33:59 +02:00
|
|
|
|
2004-06-16 03:27:00 +02:00
|
|
|
rlen = VARBITTOTALLEN(typmod);
|
|
|
|
result = (VarBit *) palloc(rlen);
|
2007-02-28 00:48:10 +01:00
|
|
|
SET_VARSIZE(result, rlen);
|
2004-06-16 03:27:00 +02:00
|
|
|
VARBITLEN(result) = typmod;
|
2002-08-04 08:33:59 +02:00
|
|
|
|
2004-06-16 03:27:00 +02:00
|
|
|
r = VARBITS(result);
|
|
|
|
destbitsleft = typmod;
|
|
|
|
srcbitsleft = 64;
|
|
|
|
/* drop any input bits that don't fit */
|
|
|
|
srcbitsleft = Min(srcbitsleft, destbitsleft);
|
|
|
|
/* sign-fill any excess bytes in output */
|
|
|
|
while (destbitsleft >= srcbitsleft + 8)
|
|
|
|
{
|
|
|
|
*r++ = (bits8) ((a < 0) ? BITMASK : 0);
|
|
|
|
destbitsleft -= 8;
|
|
|
|
}
|
|
|
|
/* store first fractional byte */
|
|
|
|
if (destbitsleft > srcbitsleft)
|
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
int val = (int) (a >> (destbitsleft - 8));
|
2009-12-12 20:24:35 +01:00
|
|
|
|
|
|
|
/* Force sign-fill in case the compiler implements >> as zero-fill */
|
|
|
|
if (a < 0)
|
|
|
|
val |= (-1) << (srcbitsleft + 8 - destbitsleft);
|
|
|
|
*r++ = (bits8) (val & BITMASK);
|
2004-06-16 03:27:00 +02:00
|
|
|
destbitsleft -= 8;
|
|
|
|
}
|
|
|
|
/* Now srcbitsleft and destbitsleft are the same, need not track both */
|
|
|
|
/* store whole bytes */
|
|
|
|
while (destbitsleft >= 8)
|
|
|
|
{
|
|
|
|
*r++ = (bits8) ((a >> (destbitsleft - 8)) & BITMASK);
|
|
|
|
destbitsleft -= 8;
|
|
|
|
}
|
|
|
|
/* store last fractional byte */
|
|
|
|
if (destbitsleft > 0)
|
|
|
|
*r = (bits8) ((a << (8 - destbitsleft)) & BITMASK);
|
|
|
|
|
|
|
|
PG_RETURN_VARBIT_P(result);
|
2002-08-04 08:33:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
bittoint8(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
VarBit *arg = PG_GETARG_VARBIT_P(0);
|
|
|
|
uint64 result;
|
|
|
|
bits8 *r;
|
|
|
|
|
|
|
|
/* Check that the bit string is not too long */
|
|
|
|
if (VARBITLEN(arg) > sizeof(result) * BITS_PER_BYTE)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
2004-10-04 16:42:48 +02:00
|
|
|
errmsg("bigint out of range")));
|
2003-07-27 06:53:12 +02:00
|
|
|
|
2002-08-04 08:33:59 +02:00
|
|
|
result = 0;
|
|
|
|
for (r = VARBITS(arg); r < VARBITEND(arg); r++)
|
|
|
|
{
|
|
|
|
result <<= BITS_PER_BYTE;
|
|
|
|
result |= *r;
|
|
|
|
}
|
|
|
|
/* Now shift the result to take account of the padding at the end */
|
|
|
|
result >>= VARBITPAD(arg);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
2000-10-31 11:22:13 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* Determines the position of S2 in the bitstring S1 (1-based string).
|
|
|
|
* If S2 does not appear in S1 this function returns 0.
|
|
|
|
* If S2 is of length 0 this function returns 1.
|
2002-08-04 08:33:59 +02:00
|
|
|
* Compatible in usage with POSITION() functions for other data types.
|
2000-10-31 11:22:13 +01:00
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
bitposition(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2002-08-04 08:33:59 +02:00
|
|
|
VarBit *str = PG_GETARG_VARBIT_P(0);
|
2001-03-22 05:01:46 +01:00
|
|
|
VarBit *substr = PG_GETARG_VARBIT_P(1);
|
|
|
|
int substr_length,
|
2002-08-04 08:33:59 +02:00
|
|
|
str_length,
|
2000-10-31 11:22:13 +01:00
|
|
|
i,
|
|
|
|
is;
|
2001-03-22 05:01:46 +01:00
|
|
|
bits8 *s, /* pointer into substring */
|
2002-08-04 08:33:59 +02:00
|
|
|
*p; /* pointer into str */
|
2001-03-22 05:01:46 +01:00
|
|
|
bits8 cmp, /* shifted substring byte to compare */
|
|
|
|
mask1, /* mask for substring byte shifted right */
|
|
|
|
mask2, /* mask for substring byte shifted left */
|
|
|
|
end_mask, /* pad mask for last substring byte */
|
2002-08-04 08:33:59 +02:00
|
|
|
str_mask; /* pad mask for last string byte */
|
2000-10-31 11:22:13 +01:00
|
|
|
bool is_match;
|
|
|
|
|
|
|
|
/* Get the substring length */
|
|
|
|
substr_length = VARBITLEN(substr);
|
2002-08-04 08:33:59 +02:00
|
|
|
str_length = VARBITLEN(str);
|
2000-10-31 11:22:13 +01:00
|
|
|
|
2002-08-04 08:33:59 +02:00
|
|
|
/* String has zero length or substring longer than string, return 0 */
|
|
|
|
if ((str_length == 0) || (substr_length > str_length))
|
2001-03-22 05:01:46 +01:00
|
|
|
PG_RETURN_INT32(0);
|
|
|
|
|
2002-08-04 08:33:59 +02:00
|
|
|
/* zero-length substring means return 1 */
|
2000-10-31 11:22:13 +01:00
|
|
|
if (substr_length == 0)
|
|
|
|
PG_RETURN_INT32(1);
|
|
|
|
|
|
|
|
/* Initialise the padding masks */
|
|
|
|
end_mask = BITMASK << VARBITPAD(substr);
|
2002-08-04 08:33:59 +02:00
|
|
|
str_mask = BITMASK << VARBITPAD(str);
|
|
|
|
for (i = 0; i < VARBITBYTES(str) - VARBITBYTES(substr) + 1; i++)
|
2000-10-31 11:22:13 +01:00
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
for (is = 0; is < BITS_PER_BYTE; is++)
|
|
|
|
{
|
2000-10-31 11:22:13 +01:00
|
|
|
is_match = true;
|
2002-08-04 08:33:59 +02:00
|
|
|
p = VARBITS(str) + i;
|
2000-10-31 11:22:13 +01:00
|
|
|
mask1 = BITMASK >> is;
|
|
|
|
mask2 = ~mask1;
|
2001-03-22 05:01:46 +01:00
|
|
|
for (s = VARBITS(substr);
|
|
|
|
is_match && s < VARBITEND(substr); s++)
|
2000-10-31 11:22:13 +01:00
|
|
|
{
|
|
|
|
cmp = *s >> is;
|
2001-03-22 05:01:46 +01:00
|
|
|
if (s == VARBITEND(substr) - 1)
|
2000-10-31 11:22:13 +01:00
|
|
|
{
|
|
|
|
mask1 &= end_mask >> is;
|
2002-08-04 08:33:59 +02:00
|
|
|
if (p == VARBITEND(str) - 1)
|
2001-03-22 05:01:46 +01:00
|
|
|
{
|
2002-08-04 08:33:59 +02:00
|
|
|
/* Check that there is enough of str left */
|
|
|
|
if (mask1 & ~str_mask)
|
2001-03-22 05:01:46 +01:00
|
|
|
{
|
2000-10-31 11:22:13 +01:00
|
|
|
is_match = false;
|
|
|
|
break;
|
|
|
|
}
|
2002-08-04 08:33:59 +02:00
|
|
|
mask1 &= str_mask;
|
2000-10-31 11:22:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
is_match = ((cmp ^ *p) & mask1) == 0;
|
|
|
|
if (!is_match)
|
|
|
|
break;
|
2000-11-07 12:35:16 +01:00
|
|
|
/* Move on to the next byte */
|
2000-10-31 11:22:13 +01:00
|
|
|
p++;
|
2002-08-04 08:33:59 +02:00
|
|
|
if (p == VARBITEND(str))
|
2001-03-22 05:01:46 +01:00
|
|
|
{
|
2000-10-31 11:22:13 +01:00
|
|
|
mask2 = end_mask << (BITS_PER_BYTE - is);
|
|
|
|
is_match = mask2 == 0;
|
2000-11-18 17:18:41 +01:00
|
|
|
#if 0
|
2003-05-27 19:49:47 +02:00
|
|
|
elog(DEBUG4, "S. %d %d em=%2x sm=%2x r=%d",
|
2001-03-22 05:01:46 +01:00
|
|
|
i, is, end_mask, mask2, is_match);
|
2000-11-18 17:18:41 +01:00
|
|
|
#endif
|
2000-10-31 11:22:13 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
cmp = *s << (BITS_PER_BYTE - is);
|
2001-03-22 05:01:46 +01:00
|
|
|
if (s == VARBITEND(substr) - 1)
|
2000-10-31 11:22:13 +01:00
|
|
|
{
|
|
|
|
mask2 &= end_mask << (BITS_PER_BYTE - is);
|
2002-08-04 08:33:59 +02:00
|
|
|
if (p == VARBITEND(str) - 1)
|
2001-03-22 05:01:46 +01:00
|
|
|
{
|
2002-08-04 08:33:59 +02:00
|
|
|
if (mask2 & ~str_mask)
|
2001-03-22 05:01:46 +01:00
|
|
|
{
|
2000-10-31 11:22:13 +01:00
|
|
|
is_match = false;
|
|
|
|
break;
|
|
|
|
}
|
2002-08-04 08:33:59 +02:00
|
|
|
mask2 &= str_mask;
|
2000-10-31 11:22:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
is_match = ((cmp ^ *p) & mask2) == 0;
|
|
|
|
}
|
2002-08-04 08:33:59 +02:00
|
|
|
/* Have we found a match? */
|
2000-10-31 11:22:13 +01:00
|
|
|
if (is_match)
|
2001-03-22 05:01:46 +01:00
|
|
|
PG_RETURN_INT32(i * BITS_PER_BYTE + is + 1);
|
2000-10-31 11:22:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
PG_RETURN_INT32(0);
|
|
|
|
}
|
2010-01-25 21:55:32 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bitsetbit
|
|
|
|
*
|
|
|
|
* Given an instance of type 'bit' creates a new one with
|
|
|
|
* the Nth bit set to the given value.
|
|
|
|
*
|
|
|
|
* The bit location is specified left-to-right in a zero-based fashion
|
|
|
|
* consistent with the other get_bit and set_bit functions, but
|
|
|
|
* inconsistent with the standard substring, position, overlay functions
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
bitsetbit(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
int32 n = PG_GETARG_INT32(1);
|
|
|
|
int32 newBit = PG_GETARG_INT32(2);
|
|
|
|
VarBit *result;
|
|
|
|
int len,
|
|
|
|
bitlen;
|
|
|
|
bits8 *r,
|
|
|
|
*p;
|
|
|
|
int byteNo,
|
|
|
|
bitNo;
|
|
|
|
|
|
|
|
bitlen = VARBITLEN(arg1);
|
|
|
|
if (n < 0 || n >= bitlen)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
|
|
|
errmsg("bit index %d out of valid range (0..%d)",
|
|
|
|
n, bitlen - 1)));
|
2010-02-26 03:01:40 +01:00
|
|
|
|
2010-01-25 21:55:32 +01:00
|
|
|
/*
|
|
|
|
* sanity check!
|
|
|
|
*/
|
|
|
|
if (newBit != 0 && newBit != 1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("new bit must be 0 or 1")));
|
|
|
|
|
|
|
|
len = VARSIZE(arg1);
|
|
|
|
result = (VarBit *) palloc(len);
|
|
|
|
SET_VARSIZE(result, len);
|
|
|
|
VARBITLEN(result) = bitlen;
|
|
|
|
|
|
|
|
p = VARBITS(arg1);
|
|
|
|
r = VARBITS(result);
|
|
|
|
|
|
|
|
memcpy(r, p, VARBITBYTES(arg1));
|
|
|
|
|
|
|
|
byteNo = n / BITS_PER_BYTE;
|
|
|
|
bitNo = BITS_PER_BYTE - 1 - (n % BITS_PER_BYTE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Update the byte.
|
|
|
|
*/
|
|
|
|
if (newBit == 0)
|
|
|
|
r[byteNo] &= (~(1 << bitNo));
|
|
|
|
else
|
|
|
|
r[byteNo] |= (1 << bitNo);
|
|
|
|
|
|
|
|
PG_RETURN_VARBIT_P(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bitgetbit
|
|
|
|
*
|
|
|
|
* returns the value of the Nth bit of a bit array (0 or 1).
|
|
|
|
*
|
|
|
|
* The bit location is specified left-to-right in a zero-based fashion
|
|
|
|
* consistent with the other get_bit and set_bit functions, but
|
|
|
|
* inconsistent with the standard substring, position, overlay functions
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
bitgetbit(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
|
|
int32 n = PG_GETARG_INT32(1);
|
|
|
|
int bitlen;
|
|
|
|
bits8 *p;
|
|
|
|
int byteNo,
|
|
|
|
bitNo;
|
|
|
|
|
|
|
|
bitlen = VARBITLEN(arg1);
|
|
|
|
if (n < 0 || n >= bitlen)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
|
|
|
errmsg("bit index %d out of valid range (0..%d)",
|
|
|
|
n, bitlen - 1)));
|
|
|
|
|
|
|
|
p = VARBITS(arg1);
|
|
|
|
|
|
|
|
byteNo = n / BITS_PER_BYTE;
|
|
|
|
bitNo = BITS_PER_BYTE - 1 - (n % BITS_PER_BYTE);
|
|
|
|
|
|
|
|
if (p[byteNo] & (1 << bitNo))
|
|
|
|
PG_RETURN_INT32(1);
|
|
|
|
else
|
|
|
|
PG_RETURN_INT32(0);
|
|
|
|
}
|