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 ----
         <entry><literal>octet_length(E'jo\\000se'::bytea)</literal></entry>
         <entry><literal>5</literal></entry>
        </row>
+       
+       <row>
+        <entry><literal><function>overlay</function>(<parameter>string</parameter> placing <parameter>string</parameter> from <type>int</type> <optional>for <type>int</type></optional>)</literal></entry>
+        <entry><type>bytea</type></entry>
+        <entry>
+         Replace substring
+        </entry>
+        <entry><literal>overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 2 for 3)</literal></entry>
+        <entry><literal>T\\002\\003mas</literal></entry>
+       </row>
  
        <row>
         <entry><literal><function>position</function>(<parameter>substring</parameter> in <parameter>string</parameter>)</literal></entry>
***************
*** 2934,2940 ****
      <literal><function>bit_length</function></literal>,
      <literal><function>octet_length</function></literal>,
      <literal><function>position</function></literal>,
!     <literal><function>substring</function></literal>.
     </para>
  
     <para>
--- 2944,2958 ----
      <literal><function>bit_length</function></literal>,
      <literal><function>octet_length</function></literal>,
      <literal><function>position</function></literal>,
!     <literal><function>substring</function></literal>,
!     <literal><function>overlay</function></literal>.
!    </para>
! 
!    <para>
!     The following functions work on bit strings as well as binary
!     strings:
!     <literal><function>get_bit</function></literal>,
!     <literal><function>set_bit</function></literal>.
     </para>
  
     <para>
