diff --git a/src/backend/utils/adt/datum.c b/src/backend/utils/adt/datum.c
index 8832785540f..ef202c83f40 100644
--- a/src/backend/utils/adt/datum.c
+++ b/src/backend/utils/adt/datum.c
@@ -271,6 +271,27 @@ datum_image_eq(Datum value1, Datum value2, bool typByVal, int typLen)
 
 	if (typByVal)
 	{
+		/*
+		 * XXX hack to fix issue with functions such as hash_numeric() not
+		 * returning the correct type.  Force sign-extended representation.
+		 */
+		switch (typLen)
+		{
+			case sizeof(char):
+				value1 = CharGetDatum(DatumGetChar(value1));
+				value2 = CharGetDatum(DatumGetChar(value2));
+				break;
+			case sizeof(int16):
+				value1 = Int16GetDatum(DatumGetInt16(value1));
+				value2 = Int16GetDatum(DatumGetInt16(value2));
+				break;
+			case sizeof(int32):
+				value1 = Int32GetDatum(DatumGetInt32(value1));
+				value2 = Int32GetDatum(DatumGetInt32(value2));
+				break;
+			/* Nothing needs done for 64-bit types */
+		}
+
 		result = (value1 == value2);
 	}
 	else if (typLen > 0)
@@ -341,7 +362,27 @@ datum_image_hash(Datum value, bool typByVal, int typLen)
 	uint32		result;
 
 	if (typByVal)
-		result = hash_bytes((unsigned char *) &value, sizeof(Datum));
+	{
+		/*
+		 * XXX hack to fix issue with functions such as hash_numeric() not
+		 * returning the correct type.  Force sign-extended representation.
+		 */
+		switch (typLen)
+		{
+			case sizeof(char):
+				value = CharGetDatum(DatumGetChar(value));
+				break;
+			case sizeof(int16):
+				value = Int16GetDatum(DatumGetInt16(value));
+				break;
+			case sizeof(int32):
+				value = Int32GetDatum(DatumGetInt32(value));
+				break;
+			/* Nothing needs done for 64-bit types */
+		}
+
+		result = hash_bytes((unsigned char*) &value, sizeof(Datum));
+	}
 	else if (typLen > 0)
 		result = hash_bytes((unsigned char *) DatumGetPointer(value), typLen);
 	else if (typLen == -1)
