diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index 2fad9aba04..8779acddb4 100644 --- a/src/backend/utils/adt/varbit.c +++ b/src/backend/utils/adt/varbit.c @@ -9,7 +9,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.22 2002/06/20 20:29:38 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.23 2002/08/04 06:33:48 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -98,8 +98,8 @@ bit_in(PG_FUNCTION_ARGS) if (atttypmod <= 0) atttypmod = bitlen; else if (bitlen != atttypmod) - elog(ERROR, "bit string length does not match type bit(%d)", - atttypmod); + elog(ERROR, "Bit string length %d does not match type BIT(%d)", + bitlen, atttypmod); len = VARBITTOTALLEN(atttypmod); result = (VarBit *) palloc(len); @@ -119,7 +119,7 @@ bit_in(PG_FUNCTION_ARGS) if (*sp == '1') *r |= x; else if (*sp != '0') - elog(ERROR, "cannot parse %c as a binary digit", *sp); + elog(ERROR, "Cannot parse '%c' as a binary digit", *sp); x >>= 1; if (x == 0) { @@ -140,7 +140,7 @@ bit_in(PG_FUNCTION_ARGS) else if (*sp >= 'a' && *sp <= 'f') x = (bits8) (*sp - 'a') + 10; else - elog(ERROR, "cannot parse %c as a hex digit", *sp); + elog(ERROR, "Cannot parse '%c' as a hex digit", *sp); if (bc) { *r++ |= x; @@ -214,8 +214,8 @@ bit(PG_FUNCTION_ARGS) if (len <= 0 || len == VARBITLEN(arg)) PG_RETURN_VARBIT_P(arg); else - elog(ERROR, "bit string length does not match type bit(%d)", - len); + elog(ERROR, "Bit string length %d does not match type BIT(%d)", + VARBITLEN(arg), len); return 0; /* quiet compiler */ } @@ -305,7 +305,7 @@ varbit_in(PG_FUNCTION_ARGS) if (atttypmod <= 0) atttypmod = bitlen; else if (bitlen > atttypmod) - elog(ERROR, "bit string too long for type bit varying(%d)", + elog(ERROR, "Bit string too long for type BIT VARYING(%d)", atttypmod); len = VARBITTOTALLEN(bitlen); @@ -326,7 +326,7 @@ varbit_in(PG_FUNCTION_ARGS) if (*sp == '1') *r |= x; else if (*sp != '0') - elog(ERROR, "cannot parse %c as a binary digit", *sp); + elog(ERROR, "Cannot parse '%c' as a binary digit", *sp); x >>= 1; if (x == 0) { @@ -347,7 +347,7 @@ varbit_in(PG_FUNCTION_ARGS) else if (*sp >= 'a' && *sp <= 'f') x = (bits8) (*sp - 'a') + 10; else - elog(ERROR, "cannot parse %c as a hex digit", *sp); + elog(ERROR, "Cannot parse '%c' as a hex digit", *sp); if (bc) { *r++ |= x; @@ -420,7 +420,7 @@ varbit(PG_FUNCTION_ARGS) PG_RETURN_VARBIT_P(arg); if (len < VARBITLEN(arg)) - elog(ERROR, "bit string too long for type bit varying(%d)", len); + elog(ERROR, "Bit string too long for type BIT VARYING(%d)", len); rlen = VARBITTOTALLEN(len); result = (VarBit *) palloc(rlen); @@ -812,7 +812,7 @@ bitand(PG_FUNCTION_ARGS) bitlen1 = VARBITLEN(arg1); bitlen2 = VARBITLEN(arg2); if (bitlen1 != bitlen2) - elog(ERROR, "cannot AND bit strings of different sizes"); + elog(ERROR, "Cannot AND bit strings of different sizes"); len = VARSIZE(arg1); result = (VarBit *) palloc(len); VARATT_SIZEP(result) = len; @@ -850,7 +850,7 @@ bitor(PG_FUNCTION_ARGS) bitlen1 = VARBITLEN(arg1); bitlen2 = VARBITLEN(arg2); if (bitlen1 != bitlen2) - elog(ERROR, "cannot OR bit strings of different sizes"); + elog(ERROR, "Cannot OR bit strings of different sizes"); len = VARSIZE(arg1); result = (VarBit *) palloc(len); VARATT_SIZEP(result) = len; @@ -894,7 +894,7 @@ bitxor(PG_FUNCTION_ARGS) bitlen1 = VARBITLEN(arg1); bitlen2 = VARBITLEN(arg2); if (bitlen1 != bitlen2) - elog(ERROR, "cannot XOR bit strings of different sizes"); + elog(ERROR, "Cannot XOR bit strings of different sizes"); len = VARSIZE(arg1); result = (VarBit *) palloc(len); VARATT_SIZEP(result) = len; @@ -1109,7 +1109,7 @@ bittoint4(PG_FUNCTION_ARGS) /* Check that the bit string is not too long */ if (VARBITLEN(arg) > sizeof(int4) * BITS_PER_BYTE) - elog(ERROR, "bit string is too large to fit in type integer"); + elog(ERROR, "Bit string is too large to fit in type integer"); result = 0; for (r = VARBITS(arg); r < VARBITEND(arg); r++) { @@ -1122,51 +1122,114 @@ bittoint4(PG_FUNCTION_ARGS) PG_RETURN_INT32(result); } +Datum +bitfromint8(PG_FUNCTION_ARGS) +{ +#ifndef INT64_IS_BUSTED + int64 a = PG_GETARG_INT64(0); + VarBit *result; + bits8 *r; + int len; + + /* allocate enough space for the bits in an int64 */ + len = VARBITTOTALLEN(sizeof(a) * BITS_PER_BYTE); + result = (VarBit *) palloc(len); + VARATT_SIZEP(result) = len; + VARBITLEN(result) = sizeof(a) * BITS_PER_BYTE; + + /* + * masks and shifts here are just too painful and we know that an int64 + * has got 8 bytes + */ + r = VARBITS(result); + r[0] = (bits8) ((a >> (7 * BITS_PER_BYTE)) & BITMASK); + r[1] = (bits8) ((a >> (6 * BITS_PER_BYTE)) & BITMASK); + r[2] = (bits8) ((a >> (5 * BITS_PER_BYTE)) & BITMASK); + r[3] = (bits8) ((a >> (4 * BITS_PER_BYTE)) & BITMASK); + r[4] = (bits8) ((a >> (3 * BITS_PER_BYTE)) & BITMASK); + r[5] = (bits8) ((a >> (2 * BITS_PER_BYTE)) & BITMASK); + r[6] = (bits8) ((a >> (1 * BITS_PER_BYTE)) & BITMASK); + r[7] = (bits8) (a & BITMASK); + + PG_RETURN_VARBIT_P(result); +#else + elog(ERROR, "INT64 is not supported on this platform"); + PG_RETURN_NULL(); +#endif +} + +Datum +bittoint8(PG_FUNCTION_ARGS) +{ +#ifndef INT64_IS_BUSTED + 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) + elog(ERROR, "Bit string is too large to fit in type int64"); + 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); +#else + elog(ERROR, "INT64 is not supported on this platform"); + PG_RETURN_NULL(); +#endif +} /* 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. + * Compatible in usage with POSITION() functions for other data types. */ Datum bitposition(PG_FUNCTION_ARGS) { + VarBit *str = PG_GETARG_VARBIT_P(0); VarBit *substr = PG_GETARG_VARBIT_P(1); - VarBit *arg = PG_GETARG_VARBIT_P(0); int substr_length, - arg_length, + str_length, i, is; bits8 *s, /* pointer into substring */ - *p; /* pointer into arg */ + *p; /* pointer into str */ 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 */ - arg_mask; /* pad mask for last argument byte */ + str_mask; /* pad mask for last string byte */ bool is_match; /* Get the substring length */ substr_length = VARBITLEN(substr); - arg_length = VARBITLEN(arg); + str_length = VARBITLEN(str); - /* Argument has 0 length or substring longer than argument, return 0 */ - if (arg_length == 0 || substr_length > arg_length) + /* String has zero length or substring longer than string, return 0 */ + if ((str_length == 0) || (substr_length > str_length)) PG_RETURN_INT32(0); - /* 0-length means return 1 */ + /* zero-length substring means return 1 */ if (substr_length == 0) PG_RETURN_INT32(1); /* Initialise the padding masks */ end_mask = BITMASK << VARBITPAD(substr); - arg_mask = BITMASK << VARBITPAD(arg); - for (i = 0; i < VARBITBYTES(arg) - VARBITBYTES(substr) + 1; i++) + str_mask = BITMASK << VARBITPAD(str); + for (i = 0; i < VARBITBYTES(str) - VARBITBYTES(substr) + 1; i++) { for (is = 0; is < BITS_PER_BYTE; is++) { is_match = true; - p = VARBITS(arg) + i; + p = VARBITS(str) + i; mask1 = BITMASK >> is; mask2 = ~mask1; for (s = VARBITS(substr); @@ -1176,15 +1239,15 @@ bitposition(PG_FUNCTION_ARGS) if (s == VARBITEND(substr) - 1) { mask1 &= end_mask >> is; - if (p == VARBITEND(arg) - 1) + if (p == VARBITEND(str) - 1) { - /* Check that there is enough of arg left */ - if (mask1 & ~arg_mask) + /* Check that there is enough of str left */ + if (mask1 & ~str_mask) { is_match = false; break; } - mask1 &= arg_mask; + mask1 &= str_mask; } } is_match = ((cmp ^ *p) & mask1) == 0; @@ -1192,7 +1255,7 @@ bitposition(PG_FUNCTION_ARGS) break; /* Move on to the next byte */ p++; - if (p == VARBITEND(arg)) + if (p == VARBITEND(str)) { mask2 = end_mask << (BITS_PER_BYTE - is); is_match = mask2 == 0; @@ -1206,19 +1269,19 @@ bitposition(PG_FUNCTION_ARGS) if (s == VARBITEND(substr) - 1) { mask2 &= end_mask << (BITS_PER_BYTE - is); - if (p == VARBITEND(arg) - 1) + if (p == VARBITEND(str) - 1) { - if (mask2 & ~arg_mask) + if (mask2 & ~str_mask) { is_match = false; break; } - mask2 &= arg_mask; + mask2 &= str_mask; } } is_match = ((cmp ^ *p) & mask2) == 0; } - /* Have we found a match */ + /* Have we found a match? */ if (is_match) PG_RETURN_INT32(i * BITS_PER_BYTE + is + 1); } diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 2c5979f9a4..143d45a18a 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_proc.h,v 1.248 2002/07/31 01:49:13 momjian Exp $ + * $Id: pg_proc.h,v 1.249 2002/08/04 06:33:54 thomas Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -2236,9 +2236,9 @@ DATA(insert OID = 1681 ( length PGNSP PGUID 12 f f t f i 1 23 "1560" bitlengt DESCR("bitstring length"); DATA(insert OID = 1682 ( octet_length PGNSP PGUID 12 f f t f i 1 23 "1560" bitoctetlength - _null_ )); DESCR("octet length"); -DATA(insert OID = 1683 ( bitfromint4 PGNSP PGUID 12 f f t f i 1 1560 "23" bitfromint4 - _null_ )); +DATA(insert OID = 1683 ( bit PGNSP PGUID 12 f f t f i 1 1560 "23" bitfromint4 - _null_ )); DESCR("int4 to bitstring"); -DATA(insert OID = 1684 ( bittoint4 PGNSP PGUID 12 f f t f i 1 23 "1560" bittoint4 - _null_ )); +DATA(insert OID = 1684 ( int4 PGNSP PGUID 12 f f t f i 1 23 "1560" bittoint4 - _null_ )); DESCR("bitstring to int4"); DATA(insert OID = 1685 ( bit PGNSP PGUID 12 f f t f i 2 1560 "1560 23" bit - _null_ )); @@ -2873,6 +2873,11 @@ DESCR("substitutes regular expression"); DATA(insert OID = 2074 ( substring PGNSP PGUID 14 f f t f i 3 25 "25 25 25" "select substring($1, like_escape($2, $3))" - _null_ )); DESCR("substitutes regular expression with escape argument"); +DATA(insert OID = 2075 ( bit PGNSP PGUID 12 f f t f i 1 1560 "20" bitfromint8 - _null_ )); +DESCR("int8 to bitstring"); +DATA(insert OID = 2076 ( int8 PGNSP PGUID 12 f f t f i 1 20 "1560" bittoint8 - _null_ )); +DESCR("bitstring to int8"); + DATA(insert OID = 2090 ( current_setting PGNSP PGUID 12 f f t f s 1 25 "25" show_config_by_name - _null_ )); DESCR("SHOW X as a function"); DATA(insert OID = 2091 ( set_config PGNSP PGUID 12 f f f f v 3 25 "25 25 16" set_config_by_name - _null_ )); diff --git a/src/include/utils/varbit.h b/src/include/utils/varbit.h index 42ea863151..8dff3166d5 100644 --- a/src/include/utils/varbit.h +++ b/src/include/utils/varbit.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: varbit.h,v 1.14 2002/06/20 20:29:53 momjian Exp $ + * $Id: varbit.h,v 1.15 2002/08/04 06:33:56 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -88,6 +88,8 @@ extern Datum bitlength(PG_FUNCTION_ARGS); extern Datum bitoctetlength(PG_FUNCTION_ARGS); extern Datum bitfromint4(PG_FUNCTION_ARGS); extern Datum bittoint4(PG_FUNCTION_ARGS); +extern Datum bitfromint8(PG_FUNCTION_ARGS); +extern Datum bittoint8(PG_FUNCTION_ARGS); extern Datum bitposition(PG_FUNCTION_ARGS); #endif diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out index 4821a1d3da..310edf3bc3 100644 --- a/src/test/regress/expected/bit.out +++ b/src/test/regress/expected/bit.out @@ -6,12 +6,12 @@ -- CREATE TABLE BIT_TABLE(b BIT(11)); INSERT INTO BIT_TABLE VALUES (B'10'); -- too short -ERROR: bit string length does not match type bit(11) +ERROR: Bit string length 2 does not match type BIT(11) INSERT INTO BIT_TABLE VALUES (B'00000000000'); INSERT INTO BIT_TABLE VALUES (B'11011000000'); INSERT INTO BIT_TABLE VALUES (B'01010101010'); INSERT INTO BIT_TABLE VALUES (B'101011111010'); -- too long -ERROR: bit string length does not match type bit(11) +ERROR: Bit string length 12 does not match type BIT(11) --INSERT INTO BIT_TABLE VALUES ('X554'); --INSERT INTO BIT_TABLE VALUES ('X555'); SELECT * FROM BIT_TABLE; @@ -28,7 +28,7 @@ INSERT INTO VARBIT_TABLE VALUES (B'0'); INSERT INTO VARBIT_TABLE VALUES (B'010101'); INSERT INTO VARBIT_TABLE VALUES (B'01010101010'); INSERT INTO VARBIT_TABLE VALUES (B'101011111010'); -- too long -ERROR: bit string too long for type bit varying(11) +ERROR: Bit string too long for type BIT VARYING(11) --INSERT INTO VARBIT_TABLE VALUES ('X554'); --INSERT INTO VARBIT_TABLE VALUES ('X555'); SELECT * FROM VARBIT_TABLE; @@ -212,11 +212,11 @@ SELECT a,a<<4 AS "a<<4",b,b>>2 AS "b>>2" FROM bit_table; DROP TABLE bit_table; -- The following should fail select B'001' & B'10'; -ERROR: cannot AND bit strings of different sizes +ERROR: Cannot AND bit strings of different sizes select B'0111' | B'011'; -ERROR: cannot OR bit strings of different sizes +ERROR: Cannot OR bit strings of different sizes select B'0010' # B'011101'; -ERROR: cannot XOR bit strings of different sizes +ERROR: Cannot XOR bit strings of different sizes -- More position tests, checking all the boundary cases SELECT POSITION(B'1010' IN B'0000101'); -- 0 position