From e2668636ca5e306c213eef52082a6e2ed1246608 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat, 12 Dec 2009 19:24:44 +0000
Subject: [PATCH] Fix integer-to-bit-string conversions to handle the first
 fractional byte correctly when the output bit width is wider than the given
 integer by something other than a multiple of 8 bits.

This has been wrong since I first wrote that code for 8.0 :-(.  Kudos to
Roman Kononov for being the first to notice, though I didn't use his
patch.  Per bug #5237.
---
 src/backend/utils/adt/varbit.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c
index ec5a5bebd0..35a79a0b14 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
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.58 2009/01/01 17:23:50 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.58.2.1 2009/12/12 19:24:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1346,7 +1346,12 @@ bitfromint4(PG_FUNCTION_ARGS)
 	/* store first fractional byte */
 	if (destbitsleft > srcbitsleft)
 	{
-		*r++ = (bits8) ((a >> (srcbitsleft - 8)) & BITMASK);
+		int		val = (int) (a >> (destbitsleft - 8));
+
+		/* Force sign-fill in case the compiler implements >> as zero-fill */
+		if (a < 0)
+			val |= (-1) << (srcbitsleft + 8 - destbitsleft);
+		*r++ = (bits8) (val & BITMASK);
 		destbitsleft -= 8;
 	}
 	/* Now srcbitsleft and destbitsleft are the same, need not track both */
@@ -1425,7 +1430,12 @@ bitfromint8(PG_FUNCTION_ARGS)
 	/* store first fractional byte */
 	if (destbitsleft > srcbitsleft)
 	{
-		*r++ = (bits8) ((a >> (srcbitsleft - 8)) & BITMASK);
+		int		val = (int) (a >> (destbitsleft - 8));
+
+		/* Force sign-fill in case the compiler implements >> as zero-fill */
+		if (a < 0)
+			val |= (-1) << (srcbitsleft + 8 - destbitsleft);
+		*r++ = (bits8) (val & BITMASK);
 		destbitsleft -= 8;
 	}
 	/* Now srcbitsleft and destbitsleft are the same, need not track both */