From abc2c61d0159203079e511bd6b67f65108b1869a Mon Sep 17 00:00:00 2001
From: Andrey Borodin <amborodin@acm.org>
Date: Sat, 3 Oct 2020 21:08:54 +0500
Subject: [PATCH] Sortsupport for sorting GiST build for gist_btree types

---
 contrib/btree_gist/Makefile                 |   2 +-
 contrib/btree_gist/btree_bit.c              |  53 ++++++
 contrib/btree_gist/btree_bytea.c            |  54 +++++-
 contrib/btree_gist/btree_cash.c             |  75 +++++++++
 contrib/btree_gist/btree_date.c             |  63 +++++++
 contrib/btree_gist/btree_enum.c             |  70 ++++++++
 contrib/btree_gist/btree_float4.c           |  71 ++++++++
 contrib/btree_gist/btree_float8.c           |  79 +++++++++
 contrib/btree_gist/btree_gist--1.6--1.7.sql | 176 ++++++++++++++++++++
 contrib/btree_gist/btree_gist.control       |   2 +-
 contrib/btree_gist/btree_gist.h             |   1 +
 contrib/btree_gist/btree_inet.c             |  80 +++++++++
 contrib/btree_gist/btree_int2.c             |  70 ++++++++
 contrib/btree_gist/btree_int4.c             |  70 ++++++++
 contrib/btree_gist/btree_int8.c             |  75 ++++++++-
 contrib/btree_gist/btree_macaddr.c          |  63 +++++++
 contrib/btree_gist/btree_macaddr8.c         |  62 +++++++
 contrib/btree_gist/btree_numeric.c          |  52 ++++++
 contrib/btree_gist/btree_oid.c              |  71 ++++++++
 contrib/btree_gist/btree_text.c             |  54 ++++++
 contrib/btree_gist/btree_time.c             |  60 +++++++
 contrib/btree_gist/btree_ts.c               |  59 +++++++
 contrib/btree_gist/btree_uuid.c             |  54 ++++++
 src/backend/access/gist/gistvalidate.c      |   1 +
 24 files changed, 1413 insertions(+), 4 deletions(-)
 create mode 100644 contrib/btree_gist/btree_gist--1.6--1.7.sql

diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile
index e92d974a1a..a1f818f71e 100644
--- a/contrib/btree_gist/Makefile
+++ b/contrib/btree_gist/Makefile
@@ -32,7 +32,7 @@ EXTENSION = btree_gist
 DATA = btree_gist--1.0--1.1.sql \
        btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql \
        btree_gist--1.3--1.4.sql btree_gist--1.4--1.5.sql \
-       btree_gist--1.5--1.6.sql
+       btree_gist--1.5--1.6.sql btree_gist--1.6--1.7.sql
 PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes"
 
 REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \
diff --git a/contrib/btree_gist/btree_bit.c b/contrib/btree_gist/btree_bit.c
index 2225244ded..752a320ede 100644
--- a/contrib/btree_gist/btree_bit.c
+++ b/contrib/btree_gist/btree_bit.c
@@ -19,6 +19,7 @@ PG_FUNCTION_INFO_V1(gbt_bit_picksplit);
 PG_FUNCTION_INFO_V1(gbt_bit_consistent);
 PG_FUNCTION_INFO_V1(gbt_bit_penalty);
 PG_FUNCTION_INFO_V1(gbt_bit_same);
+PG_FUNCTION_INFO_V1(gbt_bit_sortsupport);
 
 
 /* define for comparison */
@@ -209,3 +210,55 @@ gbt_bit_penalty(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_var_penalty(result, o, n, PG_GET_COLLATION(),
 									  &tinfo, fcinfo->flinfo));
 }
+
+static int
+gbt_bit_cmp_sort(Datum a, Datum b, SortSupport ssup)
+{
+	return DatumGetInt32(DirectFunctionCall2(byteacmp,
+											 PointerGetDatum(a),
+											 PointerGetDatum(b)));
+}
+
+static Datum
+gbt_bit_abbrev_convert(Datum original, SortSupport ssup)
+{
+	return (Datum) 0;
+}
+
+static int
+gbt_bit_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	return 0;
+}
+
+/*
+ * We are always aborting the abbreviation.
+ */
+static bool
+gbt_bit_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return true;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_bit_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_bit_cmp_abbrev;
+		ssup->abbrev_converter = gbt_bit_abbrev_convert;
+		ssup->abbrev_abort = gbt_bit_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_bit_cmp_sort;
+	}
+	else
+	{
+		ssup->comparator = gbt_bit_cmp_sort;
+	}
+	PG_RETURN_VOID();
+}
+
diff --git a/contrib/btree_gist/btree_bytea.c b/contrib/btree_gist/btree_bytea.c
index 6b005f0157..67e4a42f60 100644
--- a/contrib/btree_gist/btree_bytea.c
+++ b/contrib/btree_gist/btree_bytea.c
@@ -18,6 +18,7 @@ PG_FUNCTION_INFO_V1(gbt_bytea_picksplit);
 PG_FUNCTION_INFO_V1(gbt_bytea_consistent);
 PG_FUNCTION_INFO_V1(gbt_bytea_penalty);
 PG_FUNCTION_INFO_V1(gbt_bytea_same);
+PG_FUNCTION_INFO_V1(gbt_bytea_sortsupport);
 
 
 /* define for comparison */
@@ -87,7 +88,7 @@ static const gbtree_vinfo tinfo =
 
 
 /**************************************************
- * Text ops
+ * Bytea ops
  **************************************************/
 
 
@@ -168,3 +169,54 @@ gbt_bytea_penalty(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_var_penalty(result, o, n, PG_GET_COLLATION(),
 									  &tinfo, fcinfo->flinfo));
 }
+
+static int
+gbt_bytea_cmp_sort(Datum a, Datum b, SortSupport ssup)
+{
+	return DatumGetInt32(DirectFunctionCall2(byteacmp,
+											 PointerGetDatum(a),
+											 PointerGetDatum(b)));
+}
+
+static Datum
+gbt_bytea_abbrev_convert(Datum original, SortSupport ssup)
+{
+	return (Datum) 0;
+}
+
+static int
+gbt_bytea_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	return 0;
+}
+
+/*
+ * We are always aborting the abbreviation.
+ */
+static bool
+gbt_bytea_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return true;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_bytea_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_bytea_cmp_abbrev;
+		ssup->abbrev_converter = gbt_bytea_abbrev_convert;
+		ssup->abbrev_abort = gbt_bytea_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_bytea_cmp_sort;
+	}
+	else
+	{
+		ssup->comparator = gbt_bytea_cmp_sort;
+	}
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_cash.c b/contrib/btree_gist/btree_cash.c
index dfa23224b6..558c5eb325 100644
--- a/contrib/btree_gist/btree_cash.c
+++ b/contrib/btree_gist/btree_cash.c
@@ -25,6 +25,7 @@ PG_FUNCTION_INFO_V1(gbt_cash_consistent);
 PG_FUNCTION_INFO_V1(gbt_cash_distance);
 PG_FUNCTION_INFO_V1(gbt_cash_penalty);
 PG_FUNCTION_INFO_V1(gbt_cash_same);
+PG_FUNCTION_INFO_V1(gbt_cash_sortsupport);
 
 static bool
 gbt_cashgt(const void *a, const void *b, FmgrInfo *flinfo)
@@ -216,3 +217,77 @@ gbt_cash_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+static int
+gbt_cash_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	cashKEY   *ia = (cashKEY *) DatumGetPointer(a);
+	cashKEY   *ib = (cashKEY *) DatumGetPointer(b);
+
+	/* for leaf items we expect lower == upper */
+	Assert(ia->lower == ia->upper);
+	Assert(ib->lower == ib->upper);
+
+	if (ia->lower == ib->lower)
+	{
+		return 0;
+	}
+
+	return (ia->lower > ib->lower) ? 1 : -1;
+}
+
+static Datum
+gbt_cash_abbrev_convert(Datum original, SortSupport ssup)
+{
+	cashKEY   *b1 = (cashKEY *) DatumGetPointer(original);
+	int64		z = b1->lower;
+
+#if SIZEOF_DATUM == 8
+	return (Datum) z;
+#else
+	return (Datum) (z >> 32);
+#endif
+}
+
+static int
+gbt_cash_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	if (z1 > z2)
+		return 1;
+	else if (z1 < z2)
+		return -1;
+	else
+		return 0;
+}
+
+/*
+ * We never consider aborting the abbreviation.
+ */
+static bool
+gbt_cash_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return false;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_cash_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_cash_cmp_abbrev;
+		ssup->abbrev_converter = gbt_cash_abbrev_convert;
+		ssup->abbrev_abort = gbt_cash_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_cash_cmp;
+	}
+	else
+	{
+		ssup->comparator = gbt_cash_cmp;
+	}
+	PG_RETURN_VOID();
+}
+
diff --git a/contrib/btree_gist/btree_date.c b/contrib/btree_gist/btree_date.c
index 455a265a49..bfed3a6220 100644
--- a/contrib/btree_gist/btree_date.c
+++ b/contrib/btree_gist/btree_date.c
@@ -25,6 +25,7 @@ PG_FUNCTION_INFO_V1(gbt_date_consistent);
 PG_FUNCTION_INFO_V1(gbt_date_distance);
 PG_FUNCTION_INFO_V1(gbt_date_penalty);
 PG_FUNCTION_INFO_V1(gbt_date_same);
+PG_FUNCTION_INFO_V1(gbt_date_sortsupport);
 
 static bool
 gbt_dategt(const void *a, const void *b, FmgrInfo *flinfo)
@@ -257,3 +258,65 @@ gbt_date_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+static int
+gbt_date_cmp_sort(Datum a, Datum b, SortSupport ssup)
+{
+	dateKEY    *ia = (dateKEY *) PointerGetDatum(a);
+	dateKEY    *ib = (dateKEY *) PointerGetDatum(b);
+	int			res;
+
+	res = DatumGetInt32(DirectFunctionCall2(date_cmp,
+											DateADTGetDatum(ia->lower),
+											DateADTGetDatum(ib->lower)));
+	if (res == 0)
+		return DatumGetInt32(DirectFunctionCall2(date_cmp,
+												 DateADTGetDatum(ia->upper),
+												 DateADTGetDatum(ib->upper)));
+
+	return res;
+}
+
+static Datum
+gbt_date_abbrev_convert(Datum original, SortSupport ssup)
+{
+	return (Datum) 0;
+}
+
+static int
+gbt_date_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	return 0;
+}
+
+/*
+ * We are always aborting the abbreviation.
+ */
+static bool
+gbt_date_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return true;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_date_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_date_cmp_abbrev;
+		ssup->abbrev_converter = gbt_date_abbrev_convert;
+		ssup->abbrev_abort = gbt_date_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_date_cmp_sort;
+	}
+	else
+	{
+		ssup->comparator = gbt_date_cmp_sort;
+	}
+	PG_RETURN_VOID();
+}
+
diff --git a/contrib/btree_gist/btree_enum.c b/contrib/btree_gist/btree_enum.c
index d4dc38a38e..404117a201 100644
--- a/contrib/btree_gist/btree_enum.c
+++ b/contrib/btree_gist/btree_enum.c
@@ -26,6 +26,7 @@ PG_FUNCTION_INFO_V1(gbt_enum_picksplit);
 PG_FUNCTION_INFO_V1(gbt_enum_consistent);
 PG_FUNCTION_INFO_V1(gbt_enum_penalty);
 PG_FUNCTION_INFO_V1(gbt_enum_same);
+PG_FUNCTION_INFO_V1(gbt_enum_sortsupport);
 
 
 static bool
@@ -183,3 +184,72 @@ gbt_enum_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+static int
+gbt_enum_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	oidKEY   *ia = (oidKEY *) DatumGetPointer(a);
+	oidKEY   *ib = (oidKEY *) DatumGetPointer(b);
+
+	/* for leaf items we expect lower == upper */
+	Assert(ia->lower == ia->upper);
+	Assert(ib->lower == ib->upper);
+
+	if (ia->lower == ib->lower)
+	{
+		return 0;
+	}
+
+	return (ia->lower > ib->lower) ? 1 : -1;
+}
+
+static Datum
+gbt_enum_abbrev_convert(Datum original, SortSupport ssup)
+{
+	oidKEY   *b1 = (oidKEY *) DatumGetPointer(original);
+	Oid		z = b1->lower;
+
+	return (Datum) z;
+}
+
+static int
+gbt_enum_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	if (z1 > z2)
+		return 1;
+	else if (z1 < z2)
+		return -1;
+	else
+		return 0;
+}
+
+/*
+ * We never consider aborting the abbreviation.
+ */
+static bool
+gbt_enum_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return false;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_enum_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_enum_cmp_abbrev;
+		ssup->abbrev_converter = gbt_enum_abbrev_convert;
+		ssup->abbrev_abort = gbt_enum_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_enum_cmp;
+	}
+	else
+	{
+		ssup->comparator = gbt_enum_cmp;
+	}
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_float4.c b/contrib/btree_gist/btree_float4.c
index 3604c73313..d836d62bb1 100644
--- a/contrib/btree_gist/btree_float4.c
+++ b/contrib/btree_gist/btree_float4.c
@@ -23,6 +23,7 @@ PG_FUNCTION_INFO_V1(gbt_float4_consistent);
 PG_FUNCTION_INFO_V1(gbt_float4_distance);
 PG_FUNCTION_INFO_V1(gbt_float4_penalty);
 PG_FUNCTION_INFO_V1(gbt_float4_same);
+PG_FUNCTION_INFO_V1(gbt_float4_sortsupport);
 
 static bool
 gbt_float4gt(const void *a, const void *b, FmgrInfo *flinfo)
@@ -209,3 +210,73 @@ gbt_float4_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+
+static int
+gbt_float4_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	float4KEY   *ia = (float4KEY *) DatumGetPointer(a);
+	float4KEY   *ib = (float4KEY *) DatumGetPointer(b);
+
+	/* for leaf items we expect lower == upper */
+	Assert(ia->lower == ia->upper);
+	Assert(ib->lower == ib->upper);
+
+	if (ia->lower == ib->lower)
+	{
+		return 0;
+	}
+
+	return (ia->lower > ib->lower) ? 1 : -1;
+}
+
+static Datum
+gbt_float4_abbrev_convert(Datum original, SortSupport ssup)
+{
+	float4KEY   *b1 = (float4KEY *) DatumGetPointer(original);
+	float4		z = b1->lower;
+
+	return (Datum) Float4GetDatum(z);
+}
+
+static int
+gbt_float4_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	if (DatumGetFloat4(z1) > DatumGetFloat4(z2))
+		return 1;
+	else if (DatumGetFloat4(z1) < DatumGetFloat4(z2))
+		return -1;
+	else
+		return 0;
+}
+
+/*
+ * We never consider aborting the abbreviation.
+ */
+static bool
+gbt_float4_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return false;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_float4_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_float4_cmp_abbrev;
+		ssup->abbrev_converter = gbt_float4_abbrev_convert;
+		ssup->abbrev_abort = gbt_float4_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_float4_cmp;
+	}
+	else
+	{
+		ssup->comparator = gbt_float4_cmp;
+	}
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_float8.c b/contrib/btree_gist/btree_float8.c
index 10a5262aaa..8eb8a93710 100644
--- a/contrib/btree_gist/btree_float8.c
+++ b/contrib/btree_gist/btree_float8.c
@@ -23,6 +23,7 @@ PG_FUNCTION_INFO_V1(gbt_float8_consistent);
 PG_FUNCTION_INFO_V1(gbt_float8_distance);
 PG_FUNCTION_INFO_V1(gbt_float8_penalty);
 PG_FUNCTION_INFO_V1(gbt_float8_same);
+PG_FUNCTION_INFO_V1(gbt_float8_sortsupport);
 
 
 static bool
@@ -216,3 +217,81 @@ gbt_float8_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+static int
+gbt_float8_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	float8KEY   *ia = (float8KEY *) DatumGetPointer(a);
+	float8KEY   *ib = (float8KEY *) DatumGetPointer(b);
+
+	/* for leaf items we expect lower == upper */
+	Assert(ia->lower == ia->upper);
+	Assert(ib->lower == ib->upper);
+
+	if (ia->lower == ib->lower)
+	{
+		return 0;
+	}
+
+	return (ia->lower > ib->lower) ? 1 : -1;
+}
+
+static Datum
+gbt_float8_abbrev_convert(Datum original, SortSupport ssup)
+{
+	float8KEY   *b1 = (float8KEY *) DatumGetPointer(original);
+	float8		z = b1->lower;
+
+#if SIZEOF_DATUM == 8
+	return (Datum) Float8GetDatum(z);
+#else
+	return (Datum) 0;
+#endif
+}
+
+static int
+gbt_float8_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+#if SIZEOF_DATUM == 8
+	if (DatumGetFloat8(z1) > DatumGetFloat8(z2))
+		return 1;
+	else if (DatumGetFloat8(z1) < DatumGetFloat8(z2))
+		return -1;
+	else
+		return 0;
+#else
+	return 0;
+#endif
+}
+
+static bool
+gbt_float8_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+#if SIZEOF_DATUM == 8
+	return false;
+#else
+	return true;
+#endif
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_float8_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_float8_cmp_abbrev;
+		ssup->abbrev_converter = gbt_float8_abbrev_convert;
+		ssup->abbrev_abort = gbt_float8_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_float8_cmp;
+	}
+	else
+	{
+		ssup->comparator = gbt_float8_cmp;
+	}
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_gist--1.6--1.7.sql b/contrib/btree_gist/btree_gist--1.6--1.7.sql
new file mode 100644
index 0000000000..bd98a4758e
--- /dev/null
+++ b/contrib/btree_gist/btree_gist--1.6--1.7.sql
@@ -0,0 +1,176 @@
+/* contrib/btree_gist/btree_gist--1.6--1.7.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.7'" to load this file. \quit
+
+
+CREATE FUNCTION gbt_int8_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_int8_ops USING gist ADD
+	FUNCTION	11	(int8, int8) gbt_int8_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_int4_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_int4_ops USING gist ADD
+	FUNCTION	11	(int4, int4) gbt_int4_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_int2_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_int2_ops USING gist ADD
+	FUNCTION	11	(int2, int2) gbt_int2_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_float8_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_float8_ops USING gist ADD
+	FUNCTION	11	(float8, float8) gbt_float8_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_float4_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_float4_ops USING gist ADD
+	FUNCTION	11	(float4, float4) gbt_float4_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_enum_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_enum_ops USING gist ADD
+	FUNCTION	11	(anyenum, anyenum) gbt_enum_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_oid_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_oid_ops USING gist ADD
+	FUNCTION	11	(oid, oid) gbt_oid_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_cash_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_cash_ops USING gist ADD
+	FUNCTION	11	(money, money) gbt_cash_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_inet_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_inet_ops USING gist ADD
+	FUNCTION	11	(inet, inet) gbt_inet_sortsupport (internal) ;
+
+
+CREATE FUNCTION gbt_macad_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_macaddr_ops USING gist ADD
+	FUNCTION	11	(macaddr, macaddr) gbt_macad_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_macad8_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_macaddr8_ops USING gist ADD
+	FUNCTION	11	(macaddr8, macaddr8) gbt_macad8_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_numeric_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_numeric_ops USING gist ADD
+	FUNCTION	11	(numeric, numeric) gbt_numeric_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_uuid_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_uuid_ops USING gist ADD
+	FUNCTION	11	(uuid, uuid) gbt_uuid_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_ts_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_timestamp_ops USING gist ADD
+	FUNCTION	11	(timestamp, timestamp) gbt_ts_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_timestamptz_ops USING gist ADD
+	FUNCTION	11	(timestamptz, timestamptz) gbt_ts_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_text_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_text_ops USING gist ADD
+	FUNCTION	11	(text, text) gbt_text_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_timestamptz_ops USING gist ADD
+	FUNCTION	11	(text, text) gbt_text_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_time_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_time_ops USING gist ADD
+	FUNCTION	11	(time, time) gbt_time_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_timestamptz_ops USING gist ADD
+	FUNCTION	11	(time, time) gbt_time_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_bytea_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_bytea_ops USING gist ADD
+	FUNCTION	11	(bytea, bytea) gbt_bytea_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_timestamptz_ops USING gist ADD
+	FUNCTION	11	(bytea, bytea) gbt_bytea_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_date_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_date_ops USING gist ADD
+	FUNCTION	11	(date, date) gbt_date_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_timestamptz_ops USING gist ADD
+	FUNCTION	11	(date, date) gbt_date_sortsupport (internal) ;
+
+CREATE FUNCTION gbt_bit_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_date_ops USING gist ADD
+	FUNCTION	11	(bit, bit) gbt_bit_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_timestamptz_ops USING gist ADD
+	FUNCTION	11	(bit, bit) gbt_bit_sortsupport (internal) ;
diff --git a/contrib/btree_gist/btree_gist.control b/contrib/btree_gist/btree_gist.control
index e5c41fe8f3..fa9171a80a 100644
--- a/contrib/btree_gist/btree_gist.control
+++ b/contrib/btree_gist/btree_gist.control
@@ -1,6 +1,6 @@
 # btree_gist extension
 comment = 'support for indexing common datatypes in GiST'
-default_version = '1.6'
+default_version = '1.7'
 module_pathname = '$libdir/btree_gist'
 relocatable = true
 trusted = true
diff --git a/contrib/btree_gist/btree_gist.h b/contrib/btree_gist/btree_gist.h
index 14c7c8ee19..35ad287ed3 100644
--- a/contrib/btree_gist/btree_gist.h
+++ b/contrib/btree_gist/btree_gist.h
@@ -6,6 +6,7 @@
 
 #include "access/nbtree.h"
 #include "fmgr.h"
+#include "utils/sortsupport.h"
 
 #define BtreeGistNotEqualStrategyNumber 6
 
diff --git a/contrib/btree_gist/btree_inet.c b/contrib/btree_gist/btree_inet.c
index e4b3a946b2..61cac1df00 100644
--- a/contrib/btree_gist/btree_inet.c
+++ b/contrib/btree_gist/btree_inet.c
@@ -24,6 +24,7 @@ PG_FUNCTION_INFO_V1(gbt_inet_picksplit);
 PG_FUNCTION_INFO_V1(gbt_inet_consistent);
 PG_FUNCTION_INFO_V1(gbt_inet_penalty);
 PG_FUNCTION_INFO_V1(gbt_inet_same);
+PG_FUNCTION_INFO_V1(gbt_inet_sortsupport);
 
 
 static bool
@@ -186,3 +187,82 @@ gbt_inet_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+static int
+gbt_inet_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	inetKEY   *ia = (inetKEY *) DatumGetPointer(a);
+	inetKEY   *ib = (inetKEY *) DatumGetPointer(b);
+
+	/* for leaf items we expect lower == upper */
+	Assert(ia->lower == ia->upper);
+	Assert(ib->lower == ib->upper);
+
+	if (ia->lower == ib->lower)
+	{
+		return 0;
+	}
+
+	return (ia->lower > ib->lower) ? 1 : -1;
+}
+
+static Datum
+gbt_inet_abbrev_convert(Datum original, SortSupport ssup)
+{
+	inetKEY   *b1 = (inetKEY *) DatumGetPointer(original);
+	double		z = b1->lower;
+
+#if SIZEOF_DATUM == 8
+	return (Datum) Float8GetDatum(z);
+#else
+	return (Datum) 0;
+#endif
+}
+
+static int
+gbt_inet_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+#if SIZEOF_DATUM == 8
+	if (DatumGetFloat8(z1) > DatumGetFloat8(z2))
+		return 1;
+	else if (DatumGetFloat8(z1) < DatumGetFloat8(z2))
+		return -1;
+	else
+		return 0;
+#else
+	return 0;
+#endif
+}
+
+static bool
+gbt_inet_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+#if SIZEOF_DATUM == 8
+	return false;
+#else
+	return true;
+#endif
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_inet_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_inet_cmp_abbrev;
+		ssup->abbrev_converter = gbt_inet_abbrev_convert;
+		ssup->abbrev_abort = gbt_inet_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_inet_cmp;
+	}
+	else
+	{
+		ssup->comparator = gbt_inet_cmp;
+	}
+	PG_RETURN_VOID();
+}
+
diff --git a/contrib/btree_gist/btree_int2.c b/contrib/btree_gist/btree_int2.c
index a91b95ff39..abcff85a93 100644
--- a/contrib/btree_gist/btree_int2.c
+++ b/contrib/btree_gist/btree_int2.c
@@ -24,6 +24,7 @@ PG_FUNCTION_INFO_V1(gbt_int2_consistent);
 PG_FUNCTION_INFO_V1(gbt_int2_distance);
 PG_FUNCTION_INFO_V1(gbt_int2_penalty);
 PG_FUNCTION_INFO_V1(gbt_int2_same);
+PG_FUNCTION_INFO_V1(gbt_int2_sortsupport);
 
 static bool
 gbt_int2gt(const void *a, const void *b, FmgrInfo *flinfo)
@@ -214,3 +215,72 @@ gbt_int2_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+static int
+gbt_int2_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	int16KEY   *ia = (int16KEY *) DatumGetPointer(a);
+	int16KEY   *ib = (int16KEY *) DatumGetPointer(b);
+
+	/* for leaf items we expect lower == upper */
+	Assert(ia->lower == ia->upper);
+	Assert(ib->lower == ib->upper);
+
+	if (ia->lower == ib->lower)
+	{
+		return 0;
+	}
+
+	return (ia->lower > ib->lower) ? 1 : -1;
+}
+
+static Datum
+gbt_int2_abbrev_convert(Datum original, SortSupport ssup)
+{
+	int16KEY   *b1 = (int16KEY *) DatumGetPointer(original);
+	int16		z = b1->lower;
+
+	return (Datum) z;
+}
+
+static int
+gbt_int2_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	if (z1 > z2)
+		return 1;
+	else if (z1 < z2)
+		return -1;
+	else
+		return 0;
+}
+
+/*
+ * We never consider aborting the abbreviation.
+ */
+static bool
+gbt_int2_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return false;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_int2_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_int2_cmp_abbrev;
+		ssup->abbrev_converter = gbt_int2_abbrev_convert;
+		ssup->abbrev_abort = gbt_int2_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_int2_cmp;
+	}
+	else
+	{
+		ssup->comparator = gbt_int2_cmp;
+	}
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_int4.c b/contrib/btree_gist/btree_int4.c
index 7ea98c478c..327d771230 100644
--- a/contrib/btree_gist/btree_int4.c
+++ b/contrib/btree_gist/btree_int4.c
@@ -24,6 +24,7 @@ PG_FUNCTION_INFO_V1(gbt_int4_consistent);
 PG_FUNCTION_INFO_V1(gbt_int4_distance);
 PG_FUNCTION_INFO_V1(gbt_int4_penalty);
 PG_FUNCTION_INFO_V1(gbt_int4_same);
+PG_FUNCTION_INFO_V1(gbt_int4_sortsupport);
 
 
 static bool
@@ -215,3 +216,72 @@ gbt_int4_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+static int
+gbt_int4_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	int32KEY   *ia = (int32KEY *) DatumGetPointer(a);
+	int32KEY   *ib = (int32KEY *) DatumGetPointer(b);
+
+	/* for leaf items we expect lower == upper */
+	Assert(ia->lower == ia->upper);
+	Assert(ib->lower == ib->upper);
+
+	if (ia->lower == ib->lower)
+	{
+		return 0;
+	}
+
+	return (ia->lower > ib->lower) ? 1 : -1;
+}
+
+static Datum
+gbt_int4_abbrev_convert(Datum original, SortSupport ssup)
+{
+	int32KEY   *b1 = (int32KEY *) DatumGetPointer(original);
+	int32		z = b1->lower;
+
+	return (Datum) z;
+}
+
+static int
+gbt_int4_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	if (z1 > z2)
+		return 1;
+	else if (z1 < z2)
+		return -1;
+	else
+		return 0;
+}
+
+/*
+ * We never consider aborting the abbreviation.
+ */
+static bool
+gbt_int4_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return false;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_int4_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_int4_cmp_abbrev;
+		ssup->abbrev_converter = gbt_int4_abbrev_convert;
+		ssup->abbrev_abort = gbt_int4_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_int4_cmp;
+	}
+	else
+	{
+		ssup->comparator = gbt_int4_cmp;
+	}
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_int8.c b/contrib/btree_gist/btree_int8.c
index df2b0d174b..32f8c3b8b4 100644
--- a/contrib/btree_gist/btree_int8.c
+++ b/contrib/btree_gist/btree_int8.c
@@ -24,7 +24,7 @@ PG_FUNCTION_INFO_V1(gbt_int8_consistent);
 PG_FUNCTION_INFO_V1(gbt_int8_distance);
 PG_FUNCTION_INFO_V1(gbt_int8_penalty);
 PG_FUNCTION_INFO_V1(gbt_int8_same);
-
+PG_FUNCTION_INFO_V1(gbt_int8_sortsupport);
 
 static bool
 gbt_int8gt(const void *a, const void *b, FmgrInfo *flinfo)
@@ -215,3 +215,76 @@ gbt_int8_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+static int
+gbt_int8_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	int64KEY   *ia = (int64KEY *) DatumGetPointer(a);
+	int64KEY   *ib = (int64KEY *) DatumGetPointer(b);
+
+	/* for leaf items we expect lower == upper */
+	Assert(ia->lower == ia->upper);
+	Assert(ib->lower == ib->upper);
+
+	if (ia->lower == ib->lower)
+	{
+		return 0;
+	}
+
+	return (ia->lower > ib->lower) ? 1 : -1;
+}
+
+static Datum
+gbt_int8_abbrev_convert(Datum original, SortSupport ssup)
+{
+	int64KEY   *b1 = (int64KEY *) DatumGetPointer(original);
+	int64		z = b1->lower;
+
+#if SIZEOF_DATUM == 8
+	return (Datum) z;
+#else
+	return (Datum) (z >> 32);
+#endif
+}
+
+static int
+gbt_int8_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	if (z1 > z2)
+		return 1;
+	else if (z1 < z2)
+		return -1;
+	else
+		return 0;
+}
+
+/*
+ * We never consider aborting the abbreviation.
+ */
+static bool
+gbt_int8_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return false;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_int8_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_int8_cmp_abbrev;
+		ssup->abbrev_converter = gbt_int8_abbrev_convert;
+		ssup->abbrev_abort = gbt_int8_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_int8_cmp;
+	}
+	else
+	{
+		ssup->comparator = gbt_int8_cmp;
+	}
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_macaddr.c b/contrib/btree_gist/btree_macaddr.c
index 7f0e9e9c91..bda5de3cfc 100644
--- a/contrib/btree_gist/btree_macaddr.c
+++ b/contrib/btree_gist/btree_macaddr.c
@@ -25,6 +25,7 @@ PG_FUNCTION_INFO_V1(gbt_macad_picksplit);
 PG_FUNCTION_INFO_V1(gbt_macad_consistent);
 PG_FUNCTION_INFO_V1(gbt_macad_penalty);
 PG_FUNCTION_INFO_V1(gbt_macad_same);
+PG_FUNCTION_INFO_V1(gbt_macad_sortsupport);
 
 
 static bool
@@ -195,3 +196,65 @@ gbt_macad_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+static int
+gbt_macad_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	macKEY   *ma = (macKEY *) DatumGetPointer(a);
+	macKEY   *mb = (macKEY *) DatumGetPointer(b);
+	uint64    ia  = mac_2_uint64(&ma->lower);
+	uint64    ib  = mac_2_uint64(&mb->lower);
+
+	/* for leaf items we expect lower == upper */
+
+	if (ia == ib)
+	{
+		return 0;
+	}
+
+	return (ia > ib) ? 1 : -1;
+}
+
+static Datum
+gbt_macad_abbrev_convert(Datum original, SortSupport ssup)
+{
+	return (Datum) 0;
+}
+
+static int
+gbt_macad_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	return 0;
+}
+
+/*
+ * We are always aborting the abbreviation.
+ */
+static bool
+gbt_macad_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return true;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_macad_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_macad_cmp_abbrev;
+		ssup->abbrev_converter = gbt_macad_abbrev_convert;
+		ssup->abbrev_abort = gbt_macad_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_macad_cmp;
+	}
+	else
+	{
+		ssup->comparator = gbt_macad_cmp;
+	}
+	PG_RETURN_VOID();
+}
+
diff --git a/contrib/btree_gist/btree_macaddr8.c b/contrib/btree_gist/btree_macaddr8.c
index ab4bca5d50..4980b5df6e 100644
--- a/contrib/btree_gist/btree_macaddr8.c
+++ b/contrib/btree_gist/btree_macaddr8.c
@@ -25,6 +25,7 @@ PG_FUNCTION_INFO_V1(gbt_macad8_picksplit);
 PG_FUNCTION_INFO_V1(gbt_macad8_consistent);
 PG_FUNCTION_INFO_V1(gbt_macad8_penalty);
 PG_FUNCTION_INFO_V1(gbt_macad8_same);
+PG_FUNCTION_INFO_V1(gbt_macad8_sortsupport);
 
 
 static bool
@@ -195,3 +196,64 @@ gbt_macad8_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+static int
+gbt_macad8_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	mac8KEY   *ma = (mac8KEY *) DatumGetPointer(a);
+	mac8KEY   *mb = (mac8KEY *) DatumGetPointer(b);
+	uint64    ia  = mac8_2_uint64(&ma->lower);
+	uint64    ib  = mac8_2_uint64(&mb->lower);
+
+	/* for leaf items we expect lower == upper */
+
+	if (ia == ib)
+	{
+		return 0;
+	}
+
+	return (ia > ib) ? 1 : -1;
+}
+
+static Datum
+gbt_macad8_abbrev_convert(Datum original, SortSupport ssup)
+{
+	return (Datum) 0;
+}
+
+static int
+gbt_macad8_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	return 0;
+}
+
+/*
+ * We are always aborting the abbreviation.
+ */
+static bool
+gbt_macad8_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return true;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_macad8_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_macad8_cmp_abbrev;
+		ssup->abbrev_converter = gbt_macad8_abbrev_convert;
+		ssup->abbrev_abort = gbt_macad8_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_macad8_cmp;
+	}
+	else
+	{
+		ssup->comparator = gbt_macad8_cmp;
+	}
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_numeric.c b/contrib/btree_gist/btree_numeric.c
index 35e466cdd9..e1a29402f3 100644
--- a/contrib/btree_gist/btree_numeric.c
+++ b/contrib/btree_gist/btree_numeric.c
@@ -21,6 +21,7 @@ PG_FUNCTION_INFO_V1(gbt_numeric_picksplit);
 PG_FUNCTION_INFO_V1(gbt_numeric_consistent);
 PG_FUNCTION_INFO_V1(gbt_numeric_penalty);
 PG_FUNCTION_INFO_V1(gbt_numeric_same);
+PG_FUNCTION_INFO_V1(gbt_numeric_sortsupport);
 
 
 /* define for comparison */
@@ -227,3 +228,54 @@ gbt_numeric_picksplit(PG_FUNCTION_ARGS)
 					  &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(v);
 }
+
+static int
+gbt_numeric_cmp_sort(Datum a, Datum b, SortSupport ssup)
+{
+	return DatumGetInt32(DirectFunctionCall2(numeric_cmp,
+											 PointerGetDatum(a),
+											 PointerGetDatum(b)));
+}
+
+static Datum
+gbt_numeric_abbrev_convert(Datum original, SortSupport ssup)
+{
+	return (Datum) 0;
+}
+
+static int
+gbt_numeric_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	return 0;
+}
+
+/*
+ * We are always aborting the abbreviation.
+ */
+static bool
+gbt_numeric_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return true;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_numeric_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_numeric_cmp_abbrev;
+		ssup->abbrev_converter = gbt_numeric_abbrev_convert;
+		ssup->abbrev_abort = gbt_numeric_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_numeric_cmp_sort;
+	}
+	else
+	{
+		ssup->comparator = gbt_numeric_cmp_sort;
+	}
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_oid.c b/contrib/btree_gist/btree_oid.c
index 3cc7d4245d..5dcfc2ec48 100644
--- a/contrib/btree_gist/btree_oid.c
+++ b/contrib/btree_gist/btree_oid.c
@@ -23,6 +23,7 @@ PG_FUNCTION_INFO_V1(gbt_oid_consistent);
 PG_FUNCTION_INFO_V1(gbt_oid_distance);
 PG_FUNCTION_INFO_V1(gbt_oid_penalty);
 PG_FUNCTION_INFO_V1(gbt_oid_same);
+PG_FUNCTION_INFO_V1(gbt_oid_sortsupport);
 
 
 static bool
@@ -215,3 +216,73 @@ gbt_oid_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+static int
+gbt_oid_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	oidKEY   *ia = (oidKEY *) DatumGetPointer(a);
+	oidKEY   *ib = (oidKEY *) DatumGetPointer(b);
+
+	/* for leaf items we expect lower == upper */
+	Assert(ia->lower == ia->upper);
+	Assert(ib->lower == ib->upper);
+
+	if (ia->lower == ib->lower)
+	{
+		return 0;
+	}
+
+	return (ia->lower > ib->lower) ? 1 : -1;
+}
+
+static Datum
+gbt_oid_abbrev_convert(Datum original, SortSupport ssup)
+{
+	oidKEY   *b1 = (oidKEY *) DatumGetPointer(original);
+	Oid		z = b1->lower;
+
+	return (Datum) z;
+}
+
+static int
+gbt_oid_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	if (z1 > z2)
+		return 1;
+	else if (z1 < z2)
+		return -1;
+	else
+		return 0;
+}
+
+/*
+ * We never consider aborting the abbreviation.
+ */
+static bool
+gbt_oid_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return false;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_oid_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_oid_cmp_abbrev;
+		ssup->abbrev_converter = gbt_oid_abbrev_convert;
+		ssup->abbrev_abort = gbt_oid_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_oid_cmp;
+	}
+	else
+	{
+		ssup->comparator = gbt_oid_cmp;
+	}
+	PG_RETURN_VOID();
+}
+
diff --git a/contrib/btree_gist/btree_text.c b/contrib/btree_gist/btree_text.c
index 8019d11281..8ee866ee80 100644
--- a/contrib/btree_gist/btree_text.c
+++ b/contrib/btree_gist/btree_text.c
@@ -18,6 +18,7 @@ PG_FUNCTION_INFO_V1(gbt_text_consistent);
 PG_FUNCTION_INFO_V1(gbt_bpchar_consistent);
 PG_FUNCTION_INFO_V1(gbt_text_penalty);
 PG_FUNCTION_INFO_V1(gbt_text_same);
+PG_FUNCTION_INFO_V1(gbt_text_sortsupport);
 
 
 /* define for comparison */
@@ -239,3 +240,56 @@ gbt_text_penalty(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_var_penalty(result, o, n, PG_GET_COLLATION(),
 									  &tinfo, fcinfo->flinfo));
 }
+
+static int
+gbt_text_cmp_sort(Datum a, Datum b, SortSupport ssup)
+{
+	return DatumGetInt32(DirectFunctionCall2Coll(bttextcmp,
+											 ssup->ssup_collation,
+											 PointerGetDatum(a),
+											 PointerGetDatum(b)));
+}
+
+static Datum
+gbt_text_abbrev_convert(Datum original, SortSupport ssup)
+{
+	return (Datum) 0;
+}
+
+static int
+gbt_text_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	return 0;
+}
+
+/*
+ * We are always aborting the abbreviation.
+ */
+static bool
+gbt_text_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return true;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_text_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_text_cmp_abbrev;
+		ssup->abbrev_converter = gbt_text_abbrev_convert;
+		ssup->abbrev_abort = gbt_text_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_text_cmp_sort;
+	}
+	else
+	{
+		ssup->comparator = gbt_text_cmp_sort;
+	}
+	PG_RETURN_VOID();
+}
+
diff --git a/contrib/btree_gist/btree_time.c b/contrib/btree_gist/btree_time.c
index fd8774a2f0..b2d05bdc56 100644
--- a/contrib/btree_gist/btree_time.c
+++ b/contrib/btree_gist/btree_time.c
@@ -28,6 +28,7 @@ PG_FUNCTION_INFO_V1(gbt_time_distance);
 PG_FUNCTION_INFO_V1(gbt_timetz_consistent);
 PG_FUNCTION_INFO_V1(gbt_time_penalty);
 PG_FUNCTION_INFO_V1(gbt_time_same);
+PG_FUNCTION_INFO_V1(gbt_time_sortsupport);
 
 
 #ifdef USE_FLOAT8_BYVAL
@@ -332,3 +333,62 @@ gbt_time_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+static int
+gbt_time_cmp_sort(Datum a, Datum b, SortSupport ssup)
+{
+	timeKEY    *ia = (timeKEY *) DatumGetPointer(a);
+	timeKEY    *ib = (timeKEY *) DatumGetPointer(b);
+	int			res;
+
+	res = DatumGetInt32(DirectFunctionCall2(time_cmp, TimeADTGetDatumFast(ia->lower), TimeADTGetDatumFast(ib->lower)));
+	if (res == 0)
+		return DatumGetInt32(DirectFunctionCall2(time_cmp, TimeADTGetDatumFast(ia->upper), TimeADTGetDatumFast(ib->upper)));
+
+	return res;
+}
+
+static Datum
+gbt_time_abbrev_convert(Datum original, SortSupport ssup)
+{
+	return (Datum) 0;
+}
+
+static int
+gbt_time_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	return 0;
+}
+
+/*
+ * We are always aborting the abbreviation.
+ */
+static bool
+gbt_time_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return true;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_time_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_time_cmp_abbrev;
+		ssup->abbrev_converter = gbt_time_abbrev_convert;
+		ssup->abbrev_abort = gbt_time_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_time_cmp_sort;
+	}
+	else
+	{
+		ssup->comparator = gbt_time_cmp_sort;
+	}
+	PG_RETURN_VOID();
+}
+
+
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 2671ba961c..35548fc49c 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -31,6 +31,7 @@ PG_FUNCTION_INFO_V1(gbt_tstz_consistent);
 PG_FUNCTION_INFO_V1(gbt_tstz_distance);
 PG_FUNCTION_INFO_V1(gbt_ts_penalty);
 PG_FUNCTION_INFO_V1(gbt_ts_same);
+PG_FUNCTION_INFO_V1(gbt_ts_sortsupport);
 
 
 #ifdef USE_FLOAT8_BYVAL
@@ -399,3 +400,61 @@ gbt_ts_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+static int
+gbt_ts_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	tsKEY   *ia = (tsKEY *) DatumGetPointer(a);
+	tsKEY   *ib = (tsKEY *) DatumGetPointer(b);
+	int			res;
+
+	res = DatumGetInt32(DirectFunctionCall2(timestamp_cmp, TimestampGetDatumFast(ia->lower), TimestampGetDatumFast(ib->lower)));
+	if (res == 0)
+		return DatumGetInt32(DirectFunctionCall2(timestamp_cmp, TimestampGetDatumFast(ia->upper), TimestampGetDatumFast(ib->upper)));
+
+	return res;
+}
+
+static Datum
+gbt_ts_abbrev_convert(Datum original, SortSupport ssup)
+{
+	return (Datum) 0;
+}
+
+static int
+gbt_ts_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	return 0;
+}
+
+/*
+ * We are always aborting the abbreviation.
+ */
+static bool
+gbt_ts_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return true;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_ts_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_ts_cmp_abbrev;
+		ssup->abbrev_converter = gbt_ts_abbrev_convert;
+		ssup->abbrev_abort = gbt_ts_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_ts_cmp;
+	}
+	else
+	{
+		ssup->comparator = gbt_ts_cmp;
+	}
+	PG_RETURN_VOID();
+}
+
diff --git a/contrib/btree_gist/btree_uuid.c b/contrib/btree_gist/btree_uuid.c
index b81875979a..2beffcb2e6 100644
--- a/contrib/btree_gist/btree_uuid.c
+++ b/contrib/btree_gist/btree_uuid.c
@@ -25,6 +25,7 @@ PG_FUNCTION_INFO_V1(gbt_uuid_picksplit);
 PG_FUNCTION_INFO_V1(gbt_uuid_consistent);
 PG_FUNCTION_INFO_V1(gbt_uuid_penalty);
 PG_FUNCTION_INFO_V1(gbt_uuid_same);
+PG_FUNCTION_INFO_V1(gbt_uuid_sortsupport);
 
 
 static int
@@ -233,3 +234,56 @@ gbt_uuid_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+static int
+gbt_uuid_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	uuidKEY   *ua = (uuidKEY *) DatumGetPointer(a);
+	uuidKEY   *ub = (uuidKEY *) DatumGetPointer(b);
+
+	return uuid_internal_cmp(&ua->lower, &ub->lower);
+}
+
+static Datum
+gbt_uuid_abbrev_convert(Datum original, SortSupport ssup)
+{
+	return (Datum) 0;
+}
+
+static int
+gbt_uuid_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
+{
+	return 0;
+}
+
+/*
+ * We are always aborting the abbreviation.
+ */
+static bool
+gbt_uuid_abbrev_abort(int memtupcount, SortSupport ssup)
+{
+	return true;
+}
+
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+gbt_uuid_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	if (ssup->abbreviate)
+	{
+		ssup->comparator = gbt_uuid_cmp_abbrev;
+		ssup->abbrev_converter = gbt_uuid_abbrev_convert;
+		ssup->abbrev_abort = gbt_uuid_abbrev_abort;
+		ssup->abbrev_full_comparator = gbt_uuid_cmp;
+	}
+	else
+	{
+		ssup->comparator = gbt_uuid_cmp;
+	}
+	PG_RETURN_VOID();
+}
+
diff --git a/src/backend/access/gist/gistvalidate.c b/src/backend/access/gist/gistvalidate.c
index 8a14620fab..e600015b12 100644
--- a/src/backend/access/gist/gistvalidate.c
+++ b/src/backend/access/gist/gistvalidate.c
@@ -338,6 +338,7 @@ gistadjustmembers(Oid opfamilyoid,
 			case GIST_DISTANCE_PROC:
 			case GIST_FETCH_PROC:
 			case GIST_OPTIONS_PROC:
+			case GIST_SORTSUPPORT_PROC:
 				/* Optional, so force it to be a soft family dependency */
 				op->ref_is_hard = false;
 				op->ref_is_family = true;
-- 
2.24.3 (Apple Git-128)

