Index: src/backend/utils/adt/varbit.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/varbit.c,v retrieving revision 1.63 diff -c -r1.63 varbit.c *** src/backend/utils/adt/varbit.c 7 Jan 2010 20:17:43 -0000 1.63 --- src/backend/utils/adt/varbit.c 20 Jan 2010 10:23:15 -0000 *************** *** 1606,1608 **** --- 1606,1703 ---- } PG_RETURN_INT32(0); } + + + /* bitsetbit + * Given an instance of type 'bit' creates a new one with + * the Nth bit set to the given value. + * The 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("index %d out of valid range, 0..%d", + n, bitlen - 1))); + /* + * 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 (0 or 1). + * The 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; + int byteNo, + bitNo; + + bitlen = VARBITLEN(arg1); + + if (n < 0 || n >= bitlen) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("index %d out of valid range, 0..%d", + n, bitlen - 1))); + + byteNo = n / BITS_PER_BYTE; + bitNo = BITS_PER_BYTE - 1 - n % BITS_PER_BYTE; + + if (VARBITS(arg1)[byteNo] &(1 << bitNo)) + PG_RETURN_INT32(1); + else + PG_RETURN_INT32(0); + } + Index: src/include/catalog/pg_proc.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_proc.h,v retrieving revision 1.564 diff -c -r1.564 pg_proc.h *** src/include/catalog/pg_proc.h 19 Jan 2010 14:11:32 -0000 1.564 --- src/include/catalog/pg_proc.h 20 Jan 2010 10:23:19 -0000 *************** *** 957,962 **** --- 957,966 ---- DESCR("get bit"); DATA(insert OID = 724 ( set_bit PGNSP PGUID 12 1 0 0 f f f t f i 3 0 17 "17 23 23" _null_ _null_ _null_ _null_ byteaSetBit _null_ _null_ _null_ )); DESCR("set bit"); + DATA(insert OID = 749 ( overlay PGNSP PGUID 14 1 0 0 f f f t f i 4 0 17 "17 17 23 23" _null_ _null_ _null_ _null_ "select pg_catalog.substring($1, 1, ($3 - 1)) || $2 || pg_catalog.substring($1, ($3 + $4))" _null_ _null_ _null_ )); + DESCR("substitute portion of binary string"); + DATA(insert OID = 752 ( overlay PGNSP PGUID 14 1 0 0 f f f t f i 3 0 17 "17 17 23" _null_ _null_ _null_ _null_ "select pg_catalog.substring($1, 1, ($3 - 1)) || $2 || pg_catalog.substring($1, ($3 + pg_catalog.octet_length($2)))" _null_ _null_ _null_ )); + DESCR("substitute portion of binary string"); DATA(insert OID = 725 ( dist_pl PGNSP PGUID 12 1 0 0 f f f t f i 2 0 701 "600 628" _null_ _null_ _null_ _null_ dist_pl _null_ _null_ _null_ )); DESCR("distance between point and line"); *************** *** 2405,2410 **** --- 2409,2422 ---- DATA(insert OID = 1699 ( substring PGNSP PGUID 12 1 0 0 f f f t f i 2 0 1560 "1560 23" _null_ _null_ _null_ _null_ bitsubstr_no_len _null_ _null_ _null_ )); DESCR("return portion of bitstring"); + DATA(insert OID = 3030 ( overlay PGNSP PGUID 14 1 0 0 f f f t f i 4 0 1560 "1560 1560 23 23" _null_ _null_ _null_ _null_ "select pg_catalog.substring($1, 1, ($3 - 1)) || $2 || pg_catalog.substring($1, ($3 + $4))" _null_ _null_ _null_ )); + DESCR("substitute portion of bit string"); + DATA(insert OID = 3031 ( overlay PGNSP PGUID 14 1 0 0 f f f t f i 3 0 1560 "1560 1560 23" _null_ _null_ _null_ _null_ "select pg_catalog.substring($1, 1, ($3 - 1)) || $2 || pg_catalog.substring($1, ($3 + pg_catalog.length($2)))" _null_ _null_ _null_ )); + DESCR("substitute portion of bit string"); + DATA(insert OID = 3032 ( get_bit PGNSP PGUID 12 1 0 0 f f f t f i 2 0 23 "1560 23" _null_ _null_ _null_ _null_ bitgetbit _null_ _null_ _null_ )); + DESCR("get bit"); + DATA(insert OID = 3033 ( set_bit PGNSP PGUID 12 1 0 0 f f f t f i 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ )); + DESCR("set bit"); /* for mac type support */ DATA(insert OID = 436 ( macaddr_in PGNSP PGUID 12 1 0 0 f f f t f i 1 0 829 "2275" _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ )); Index: src/test/regress/expected/bit.out =================================================================== RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/bit.out,v retrieving revision 1.4 diff -c -r1.4 bit.out *** src/test/regress/expected/bit.out 27 Jul 2003 04:53:11 -0000 1.4 --- src/test/regress/expected/bit.out 20 Jan 2010 10:23:19 -0000 *************** *** 509,511 **** --- 509,585 ---- DROP TABLE BIT_SHIFT_TABLE; DROP TABLE VARBIT_SHIFT_TABLE; + SELECT get_bit(B'0101011000100', 10); + get_bit + --------- + 1 + (1 row) + + SELECT get_bit(B'0101011', 3); + get_bit + --------- + 1 + (1 row) + + SELECT get_bit(B'0101011000100100', 15); + get_bit + --------- + 0 + (1 row) + + SELECT get_bit(B'010101100010010', 8); + get_bit + --------- + 0 + (1 row) + + SELECT set_bit(B'0101011', 0, 1); + set_bit + --------- + 1101011 + (1 row) + + SELECT set_bit(B'010101100010010', 14, 1); + set_bit + ----------------- + 010101100010011 + (1 row) + + SELECT set_bit(B'010101100010010', 8, 1); + set_bit + ----------------- + 010101101010010 + (1 row) + + SELECT set_bit(B'0101011000100100', 15, 1); + set_bit + ------------------ + 0101011000100101 + (1 row) + + SELECT set_bit(B'0101011000100100', 16, 1); + ERROR: index 16 out of valid range, 0..15 + SELECT overlay(B'0101011100' placing '001' from 2 for 3); + overlay + ------------ + 0001011100 + (1 row) + + SELECT overlay(B'0101011100' placing '101' from 6); + overlay + ------------ + 0101010100 + (1 row) + + SELECT overlay(B'0101011100' placing '001' from 11); + overlay + --------------- + 0101011100001 + (1 row) + + SELECT overlay(B'0101011100' placing '001' from 20); + overlay + --------------- + 0101011100001 + (1 row) + Index: src/test/regress/expected/strings.out =================================================================== RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/strings.out,v retrieving revision 1.39 diff -c -r1.39 strings.out *** src/test/regress/expected/strings.out 4 Aug 2009 16:08:36 -0000 1.39 --- src/test/regress/expected/strings.out 20 Jan 2010 10:23:20 -0000 *************** *** 1579,1581 **** --- 1579,1599 ---- \000trim\000 (1 row) + SELECT encode(overlay(E'Th\\000omas'::bytea placing E'Th\\001omas'::bytea from 2),'escape'); + encode + ------------- + TTh\x01omas + (1 row) + + SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 8),'escape'); + encode + -------------------- + Th\000omas\x02\x03 + (1 row) + + SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 5 for 3),'escape'); + encode + ----------------- + Th\000o\x02\x03 + (1 row) + Index: src/test/regress/sql/strings.sql =================================================================== RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/strings.sql,v retrieving revision 1.27 diff -c -r1.27 strings.sql *** src/test/regress/sql/strings.sql 4 Aug 2009 16:08:37 -0000 1.27 --- src/test/regress/sql/strings.sql 20 Jan 2010 10:23:20 -0000 *************** *** 547,549 **** --- 547,552 ---- SELECT btrim(E'\\000trim\\000'::bytea, E'\\000'::bytea); SELECT btrim(''::bytea, E'\\000'::bytea); SELECT btrim(E'\\000trim\\000'::bytea, ''::bytea); + SELECT encode(overlay(E'Th\\000omas'::bytea placing E'Th\\001omas'::bytea from 2),'escape'); + SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 8),'escape'); + SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 5 for 3),'escape'); \ No newline at end of file Index: src/test/regress/sql/bit.sql =================================================================== RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/bit.sql,v retrieving revision 1.2 diff -c -r1.2 bit.sql *** src/test/regress/sql/bit.sql 22 May 2001 16:37:17 -0000 1.2 --- src/test/regress/sql/bit.sql 20 Jan 2010 10:23:20 -0000 *************** *** 184,186 **** --- 184,200 ---- DROP TABLE BIT_SHIFT_TABLE; DROP TABLE VARBIT_SHIFT_TABLE; + + SELECT get_bit(B'0101011000100', 10); + SELECT get_bit(B'0101011', 3); + SELECT get_bit(B'0101011000100100', 15); + SELECT get_bit(B'010101100010010', 8); + SELECT set_bit(B'0101011', 0, 1); + SELECT set_bit(B'010101100010010', 14, 1); + SELECT set_bit(B'010101100010010', 8, 1); + SELECT set_bit(B'0101011000100100', 15, 1); + SELECT set_bit(B'0101011000100100', 16, 1); + SELECT overlay(B'0101011100' placing '001' from 2 for 3); + SELECT overlay(B'0101011100' placing '101' from 6); + SELECT overlay(B'0101011100' placing '001' from 11); + SELECT overlay(B'0101011100' placing '001' from 20); \ No newline at end of file Index: src/include/utils/varbit.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/utils/varbit.h,v retrieving revision 1.30 diff -c -r1.30 varbit.h *** src/include/utils/varbit.h 7 Jan 2010 20:17:44 -0000 1.30 --- src/include/utils/varbit.h 20 Jan 2010 10:23:19 -0000 *************** *** 96,100 **** --- 96,102 ---- extern Datum bitfromint8(PG_FUNCTION_ARGS); extern Datum bittoint8(PG_FUNCTION_ARGS); extern Datum bitposition(PG_FUNCTION_ARGS); + extern Datum bitsetbit(PG_FUNCTION_ARGS); + extern Datum bitgetbit(PG_FUNCTION_ARGS); #endif Index: doc/src/sgml/func.sgml =================================================================== RCS file: /projects/cvsroot/pgsql/doc/src/sgml/func.sgml,v retrieving revision 1.497 diff -c -r1.497 func.sgml *** doc/src/sgml/func.sgml 19 Jan 2010 05:50:18 -0000 1.497 --- doc/src/sgml/func.sgml 20 Jan 2010 10:23:14 -0000 *************** *** 2673,2678 **** --- 2673,2688 ---- octet_length(E'jo\\000se'::bytea) 5 + + + overlay(string placing string from int for int) + bytea + + Replace substring + + overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 2 for 3) + T\\002\\003mas + position(substring in string) *************** *** 2934,2940 **** bit_length, octet_length, position, ! substring. --- 2944,2958 ---- bit_length, octet_length, position, ! substring, ! overlay. ! ! ! ! The following functions work on bit strings as well as binary ! strings: ! get_bit, ! set_bit.