diff --git a/src/backend/access/gin/ginbulk.c b/src/backend/access/gin/ginbulk.c
index 3af0271..02d8600 100644
--- a/src/backend/access/gin/ginbulk.c
+++ b/src/backend/access/gin/ginbulk.c
@@ -22,6 +22,13 @@
 #define DEF_NENTRY	2048		/* GinEntryAccumulator allocation quantum */
 #define DEF_NPTR	5			/* ItemPointer initial allocation quantum */
 
+static int fastCompareEntries(GinState *ginstate, OffsetNumber attnum,
+				  Datum a, GinNullCategory categorya,
+				  Datum b, GinNullCategory categoryb);
+static int fastCompareAttEntries(GinState *ginstate,
+					 OffsetNumber attnuma, Datum a, GinNullCategory categorya,
+					 OffsetNumber attnumb, Datum b, GinNullCategory categoryb);
+static int fastCmpDatums(int16 attlen, bool attbyval, Datum a, Datum b);
 
 /* Combiner function for rbtree.c */
 static void
@@ -67,9 +74,104 @@ cmpEntryAccumulator(const RBNode *a, const RBNode *b, void *arg)
 	const GinEntryAccumulator *eb = (const GinEntryAccumulator *) b;
 	BuildAccumulator *accum = (BuildAccumulator *) arg;
 
-	return ginCompareAttEntries(accum->ginstate,
-								ea->attnum, ea->key, ea->category,
-								eb->attnum, eb->key, eb->category);
+	return fastCompareAttEntries(accum->ginstate,
+								 ea->attnum, ea->key, ea->category,
+								 eb->attnum, eb->key, eb->category);
+}
+
+
+/*
+ * Compare two keys of the same index column.
+ *
+ * This is like ginCompareEntries, but uses memcmp() for the comparison instead
+ * of the real compare function.
+ */
+static int
+fastCompareEntries(GinState *ginstate, OffsetNumber attnum,
+				  Datum a, GinNullCategory categorya,
+				  Datum b, GinNullCategory categoryb)
+{
+	/* if not of same null category, sort by that first */
+	if (categorya != categoryb)
+		return (categorya < categoryb) ? -1 : 1;
+
+	/* all null items in same category are equal */
+	if (categorya != GIN_CAT_NORM_KEY)
+		return 0;
+
+	/* both not null, so compare the Datums */
+	return fastCmpDatums(ginstate->origTupdesc->attrs[attnum - 1]->attlen,
+						 ginstate->origTupdesc->attrs[attnum - 1]->attbyval,
+						 a, b);
+}
+
+
+/*
+ * Compare two keys of possibly different index columns.
+ *
+ * This is like ginCompareAttEntries, but uses memcmp() for the comparison
+ * instead of the real compare function.
+ */
+static int
+fastCompareAttEntries(GinState *ginstate,
+					 OffsetNumber attnuma, Datum a, GinNullCategory categorya,
+					 OffsetNumber attnumb, Datum b, GinNullCategory categoryb)
+{
+	/* attribute number is the first sort key */
+	if (attnuma != attnumb)
+		return (attnuma < attnumb) ? -1 : 1;
+
+	return fastCompareEntries(ginstate, attnuma, a, categorya, b, categoryb);
+}
+
+/*
+ * Compare two Datums. This is like datumIsEqual, but returns -1, 0, or 1,
+ * rather than just a boolean.
+ *
+ * XXX: This assumes that the arguments are not toasted. Is that safe?
+ */
+static int
+fastCmpDatums(int16 typLen, bool typByVal, Datum value1, Datum value2)
+{
+	int			res;
+
+	if (typByVal)
+	{
+		/*
+		 * just compare the two datums. NOTE: just comparing "len" bytes will
+		 * not do the work, because we do not know how these bytes are aligned
+		 * inside the "Datum".  We assume instead that any given datatype is
+		 * consistent about how it fills extraneous bits in the Datum.
+		 */
+		if (value1 > value2)
+			return 1;
+		else if (value1 < value2)
+			return -1;
+		else
+			return 0;
+	}
+	else
+	{
+		Size		size1,
+					size2;
+		char	   *s1,
+				   *s2;
+
+		/*
+		 * Compare the bytes pointed by the pointers stored in the datums.
+		 */
+		size1 = datumGetSize(value1, typByVal, typLen);
+		size2 = datumGetSize(value2, typByVal, typLen);
+		if (size1 > size2)
+			return 1;
+		else if (size1 < size2)
+			return -1;
+
+		s1 = (char *) DatumGetPointer(value1);
+		s2 = (char *) DatumGetPointer(value2);
+		res = memcmp(s1, s2, size1);
+	}
+	return res;
 }
 
 /* Allocator function for rbtree.c */
