Subject: [PATCH] Add sortsupport for range types and btree_gist

From: Christoph Heiss <[email-masked]>
Date: Wed, 15 Jun 2022 12:45:07 +0200

Hi all!

The motivation behind this is that incrementally building up a GiST 
index for certain input data can create a terrible tree structure.
Furthermore, exclusion constraints are commonly implemented using GiST 
indices and for that use case, data is mostly orderable.

By sorting the data before inserting it into the index results in a much 
better index structure, leading to significant performance improvements.

Testing was done using following setup, with about 50 million rows:

    CREATE EXTENSION btree_gist;
    CREATE TABLE t (id uuid, block_range int4range);
    CREATE INDEX ON before USING GIST (id, block_range);
    COPY t FROM '..' DELIMITER ',' CSV HEADER;

using

    SELECT * FROM t WHERE id = '..' AND block_range && '..'

as test query, using a unpatched instance and one with the patch applied.

Some stats for fetching 10,000 random rows using the query above,
100 iterations to get good averages.

The benchmarking was done on a unpatched instance compiled using the 
exact same options as with the patch applied.
[ Results are noted in a unpatched -> patched fashion. ]

First set of results are after the initial CREATE TABLE, CREATE INDEX 
and a COPY to the table, thereby incrementally building the index.

Shared Hit Blocks (average): 110.97 -> 78.58
Shared Read Blocks (average): 58.90 -> 47.42
Execution Time (average): 1.10 -> 0.83 ms
I/O Read Time (average): 0.19 -> 0.15 ms

After a REINDEX on the table, the results improve even more:

Shared Hit Blocks (average): 84.24 -> 8.54
Shared Read Blocks (average): 49.89 -> 0.74
Execution Time (average): 0.84 -> 0.065 ms
I/O Read Time (average): 0.16 -> 0.004 ms

Additionally, the time a REINDEX takes also improves significantly:

     672407.584 ms (11:12.408) -> 130670.232 ms (02:10.670)

Most of the sortsupport for btree_gist was implemented by re-using 
already existing infrastructure. For the few remaining types (bit, bool, 
cash, enum, interval, macaddress8 and time) I manually implemented them 
directly in btree_gist.
It might make sense to move them into the backend for uniformity, but I 
wanted to get other opinions on that first.

`make check-world` reports no regressions.

Attached below, besides the patch, are also two scripts for benchmarking.

`bench-gist.py` to benchmark the actual patch, example usage of this 
would be e.g. `./bench-gist.py -o results.csv public.table`. This 
expects a local instance with no authentication and default `postgres` 
user. The port can be set using the `--port` option.

`plot.py` prints average values (as used above) and creates boxplots for 
each statistic from the result files produced with `bench-gist.py`. 
Depends on matplotlib and pandas.

Additionally, if needed, the sample dataset used to benchmark this is 
available to independently verify the results [1].

Thanks,
Christoph Heiss

---

[1] https://drive.google.com/file/d/1SKRiUYd78_zl7CeD8pLDoggzCCh0wj39

From 22e1b60929c39309e06c2477d8d027e60ad49b9d Mon Sep 17 00:00:00 2001
From: Christoph Heiss <[email-masked]>
Date: Thu, 9 Jun 2022 17:07:46 +0200
Subject: [PATCH 1/1] Add sortsupport for range types and btree_gist

Incrementally building up a GiST index can result in a sub-optimal index
structure for range types.
By sorting the data before inserting it into the index will result in a
much better index.

This can provide sizeable improvements in query execution time, I/O read
time and shared block hits/reads.

Signed-off-by: Christoph Heiss <[email-masked]>
---
 contrib/btree_gist/Makefile                 |   3 +-
 contrib/btree_gist/btree_bit.c              |  19 ++++
 contrib/btree_gist/btree_bool.c             |  22 ++++
 contrib/btree_gist/btree_cash.c             |  22 ++++
 contrib/btree_gist/btree_enum.c             |  19 ++++
 contrib/btree_gist/btree_gist--1.7--1.8.sql | 105 ++++++++++++++++++++
 contrib/btree_gist/btree_gist.control       |   2 +-
 contrib/btree_gist/btree_interval.c         |  19 ++++
 contrib/btree_gist/btree_macaddr8.c         |  19 ++++
 contrib/btree_gist/btree_time.c             |  19 ++++
 src/backend/utils/adt/rangetypes_gist.c     |  70 +++++++++++++
 src/include/catalog/pg_amproc.dat           |   3 +
 src/include/catalog/pg_proc.dat             |   3 +
 13 files changed, 323 insertions(+), 2 deletions(-)
 create mode 100644 contrib/btree_gist/btree_gist--1.7--1.8.sql

diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile
index 48997c75f6..4096de73ea 100644
--- a/contrib/btree_gist/Makefile
+++ b/contrib/btree_gist/Makefile
@@ -33,7 +33,8 @@ 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.6--1.7.sql
+       btree_gist--1.5--1.6.sql btree_gist--1.6--1.7.sql \
+       btree_gist--1.7--1.8.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 5b246bcde4..bf32bfd628 100644
--- a/contrib/btree_gist/btree_bit.c
+++ b/contrib/btree_gist/btree_bit.c
@@ -7,6 +7,7 @@
 #include "btree_utils_var.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
+#include "utils/sortsupport.h"
 #include "utils/varbit.h"

@@ -19,10 +20,17 @@ 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 */
 
+static int
+bit_fast_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	return DatumGetInt32(DirectFunctionCall2(byteacmp, x, y));
+}
+
 static bool
 gbt_bitgt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
 {
@@ -208,3 +216,14 @@ gbt_bit_penalty(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_var_penalty(result, o, n, PG_GET_COLLATION(),
 									  &tinfo, fcinfo->flinfo));
 }
+
+Datum
+gbt_bit_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	ssup->comparator = bit_fast_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_bool.c b/contrib/btree_gist/btree_bool.c
index 8b2af129b5..3a9f230e68 100644
--- a/contrib/btree_gist/btree_bool.c
+++ b/contrib/btree_gist/btree_bool.c
@@ -6,6 +6,7 @@
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "common/int.h"
+#include "utils/sortsupport.h"
 
 typedef struct boolkey
 {
@@ -23,6 +24,16 @@ PG_FUNCTION_INFO_V1(gbt_bool_picksplit);
 PG_FUNCTION_INFO_V1(gbt_bool_consistent);
 PG_FUNCTION_INFO_V1(gbt_bool_penalty);
 PG_FUNCTION_INFO_V1(gbt_bool_same);
+PG_FUNCTION_INFO_V1(gbt_bool_sortsupport);
+
+static int
+bool_fast_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	bool	arg1 = DatumGetBool(x);
+	bool	arg2 = DatumGetBool(y);
+
+	return arg1 - arg2;
+}
 
 static bool
 gbt_boolgt(const void *a, const void *b, FmgrInfo *flinfo)
@@ -167,3 +178,14 @@ gbt_bool_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_bool_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	ssup->comparator = bool_fast_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_cash.c b/contrib/btree_gist/btree_cash.c
index 6ac97e2b12..389b725130 100644
--- a/contrib/btree_gist/btree_cash.c
+++ b/contrib/btree_gist/btree_cash.c
@@ -7,6 +7,7 @@
 #include "btree_utils_num.h"
 #include "common/int.h"
 #include "utils/cash.h"
+#include "utils/sortsupport.h"
 
 typedef struct
 {
@@ -25,6 +26,16 @@ 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 int
+cash_fast_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	bool	arg1 = DatumGetCash(x);
+	bool	arg2 = DatumGetCash(y);
+
+	return arg1 - arg2;
+}
 
 static bool
 gbt_cashgt(const void *a, const void *b, FmgrInfo *flinfo)
@@ -215,3 +226,14 @@ gbt_cash_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_cash_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	ssup->comparator = cash_fast_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_enum.c b/contrib/btree_gist/btree_enum.c
index d4dc38a38e..2ab0ae9bc8 100644
--- a/contrib/btree_gist/btree_enum.c
+++ b/contrib/btree_gist/btree_enum.c
@@ -7,6 +7,7 @@
 #include "btree_utils_num.h"
 #include "fmgr.h"
 #include "utils/builtins.h"
+#include "utils/sortsupport.h"
 
 /* enums are really Oids, so we just use the same structure */
 
@@ -26,8 +27,15 @@ 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 int
+enum_fast_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	return DatumGetInt32(DirectFunctionCall2(enum_cmp, x, y));
+}
+
 static bool
 gbt_enumgt(const void *a, const void *b, FmgrInfo *flinfo)
 {
@@ -183,3 +191,14 @@ gbt_enum_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_enum_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	ssup->comparator = enum_fast_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_gist--1.7--1.8.sql b/contrib/btree_gist/btree_gist--1.7--1.8.sql
new file mode 100644
index 0000000000..01bd8f9f64
--- /dev/null
+++ b/contrib/btree_gist/btree_gist--1.7--1.8.sql
@@ -0,0 +1,105 @@
+/* contrib/btree_gist/btree_gist--1.7--1.8.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.8'" to load this file. \quit
+
+CREATE FUNCTION gbt_bit_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_bool_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_cash_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_enum_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_intv_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_time_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_bit_ops USING gist ADD
+    FUNCTION    11  (bit, bit) gbt_bit_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_bool_ops USING gist ADD
+    FUNCTION    11  (bool, bool) gbt_bool_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_bytea_ops USING gist ADD
+    FUNCTION    11  (bytea, bytea) bytea_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_cash_ops USING gist ADD
+    FUNCTION    11  (money, money) gbt_cash_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_date_ops USING gist ADD
+    FUNCTION    11  (date, date) date_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_enum_ops USING gist ADD
+    FUNCTION    11  (anyenum, anyenum) gbt_enum_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_float4_ops USING gist ADD
+    FUNCTION    11  (float4, float4) btfloat4sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_float8_ops USING gist ADD
+    FUNCTION    11  (float8, float8) btfloat8sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_inet_ops USING gist ADD
+    FUNCTION    11  (inet, inet) network_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_int2_ops USING gist ADD
+    FUNCTION    11  (int2, int2) btint2sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_int4_ops USING gist ADD
+    FUNCTION    11  (int4, int4) btint4sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_int8_ops USING gist ADD
+    FUNCTION    11  (int8, int8) btint8sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_interval_ops USING gist ADD
+    FUNCTION    11  (interval, interval) gbt_intv_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_macaddr_ops USING gist ADD
+    FUNCTION    11  (macaddr, macaddr) macaddr_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_macaddr8_ops USING gist ADD
+    FUNCTION    11  (macaddr8, macaddr8) gbt_macad8_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_numeric_ops USING gist ADD
+    FUNCTION    11  (numeric, numeric) numeric_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_oid_ops USING gist ADD
+    FUNCTION    11  (oid, oid) btoidsortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_text_ops USING gist ADD
+    FUNCTION    11  (text, text) bttextsortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_bpchar_ops USING gist ADD
+    FUNCTION    11  (bpchar, bpchar) bpchar_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_time_ops USING gist ADD
+    FUNCTION    11  (time, time) gbt_time_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_timestamp_ops USING gist ADD
+    FUNCTION    11  (timestamp, timestamp) timestamp_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_uuid_ops USING gist ADD
+    FUNCTION    11  (uuid, uuid) uuid_sortsupport (internal) ;
diff --git a/contrib/btree_gist/btree_gist.control b/contrib/btree_gist/btree_gist.control
index fa9171a80a..abf66538f3 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.7'
+default_version = '1.8'
 module_pathname = '$libdir/btree_gist'
 relocatable = true
 trusted = true
diff --git a/contrib/btree_gist/btree_interval.c b/contrib/btree_gist/btree_interval.c
index c2bf82086d..80179adc99 100644
--- a/contrib/btree_gist/btree_interval.c
+++ b/contrib/btree_gist/btree_interval.c
@@ -6,6 +6,7 @@
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
+#include "utils/sortsupport.h"
 #include "utils/timestamp.h"
 
 typedef struct
@@ -27,8 +28,15 @@ PG_FUNCTION_INFO_V1(gbt_intv_consistent);
 PG_FUNCTION_INFO_V1(gbt_intv_distance);
 PG_FUNCTION_INFO_V1(gbt_intv_penalty);
 PG_FUNCTION_INFO_V1(gbt_intv_same);
+PG_FUNCTION_INFO_V1(gbt_intv_sortsupport);

+static int
+intv_fast_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	return DatumGetInt32(DirectFunctionCall2(interval_cmp, x, y));
+}
+
 static bool
 gbt_intvgt(const void *a, const void *b, FmgrInfo *flinfo)
 {
@@ -295,3 +303,14 @@ gbt_intv_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_intv_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	ssup->comparator = intv_fast_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_macaddr8.c b/contrib/btree_gist/btree_macaddr8.c
index 796cc4efee..034e34bf90 100644
--- a/contrib/btree_gist/btree_macaddr8.c
+++ b/contrib/btree_gist/btree_macaddr8.c
@@ -7,6 +7,7 @@
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
 #include "utils/inet.h"
+#include "utils/sortsupport.h"
 
 typedef struct
 {
@@ -25,8 +26,15 @@ 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 int
+macaddr8_fast_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	return DatumGetInt32(DirectFunctionCall2(macaddr8_cmp, x, y));
+}
+
 static bool
 gbt_macad8gt(const void *a, const void *b, FmgrInfo *flinfo)
 {
@@ -194,3 +202,14 @@ gbt_macad8_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_macad8_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	ssup->comparator = macaddr8_fast_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_time.c b/contrib/btree_gist/btree_time.c
index fd8774a2f0..fb3454987b 100644
--- a/contrib/btree_gist/btree_time.c
+++ b/contrib/btree_gist/btree_time.c
@@ -7,6 +7,7 @@
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
+#include "utils/sortsupport.h"
 #include "utils/timestamp.h"
 
 typedef struct
@@ -28,6 +29,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
@@ -37,6 +39,12 @@ PG_FUNCTION_INFO_V1(gbt_time_same);
 #endif

+static int
+time_fast_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	return DatumGetInt32(DirectFunctionCall2(time_cmp, x, y));
+}
+
 static bool
 gbt_timegt(const void *a, const void *b, FmgrInfo *flinfo)
 {
@@ -332,3 +340,14 @@ gbt_time_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_time_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	ssup->comparator = time_fast_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index fbf39dbf30..2ded365dc2 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -21,6 +21,7 @@
 #include "utils/fmgrprotos.h"
 #include "utils/multirangetypes.h"
 #include "utils/rangetypes.h"
+#include "utils/sortsupport.h"
 
 /*
  * Range class properties used to segregate different classes of ranges in
@@ -177,6 +178,7 @@ static void range_gist_double_sorting_split(TypeCacheEntry *typcache,
 static void range_gist_consider_split(ConsiderSplitContext *context,
 									  RangeBound *right_lower, int min_left_count,
 									  RangeBound *left_upper, int max_left_count);
+static int	range_gist_cmp(Datum a, Datum b, SortSupport ssup);
 static int	get_gist_range_class(RangeType *range);
 static int	single_bound_cmp(const void *a, const void *b, void *arg);
 static int	interval_cmp_lower(const void *a, const void *b, void *arg);
@@ -773,6 +775,20 @@ range_gist_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(v);
 }
 
+/*
+ * Sort support routine for fast GiST index build by sorting.
+ */
+Datum
+range_gist_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport	ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	ssup->comparator = range_gist_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
+
 /* equality comparator for GiST */
 Datum
 range_gist_same(PG_FUNCTION_ARGS)
@@ -1692,6 +1708,60 @@ range_gist_consider_split(ConsiderSplitContext *context,
 	}
 }
 
+/*
+ * GiST sortsupport comparator for ranges.
+ *
+ * Operates solely on the lower bounds of the ranges, comparing them using
+ * range_cmp_bounds().
+ * Empty ranges are sorted before non-empty ones.
+ */
+static int
+range_gist_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	RangeType *range_a = DatumGetRangeTypeP(a);
+	RangeType *range_b = DatumGetRangeTypeP(b);
+	TypeCacheEntry *typcache = ssup->ssup_extra;
+	RangeBound	lower1,
+				lower2;
+	RangeBound	upper1,
+				upper2;
+	bool		empty1,
+				empty2;
+	int			result;
+
+	if (typcache == NULL) {
+		Assert(RangeTypeGetOid(range_a) == RangeTypeGetOid(range_b));
+		typcache = lookup_type_cache(RangeTypeGetOid(range_a), TYPECACHE_RANGE_INFO);
+
+		/*
+		 * Cache the range info between calls to avoid having to call
+		 * lookup_type_cache() for each comparison.
+		 */
+		ssup->ssup_extra = typcache;
+	}
+
+	range_deserialize(typcache, range_a, &lower1, &upper1, &empty1);
+	range_deserialize(typcache, range_b, &lower2, &upper2, &empty2);
+
+	/* For b-tree use, empty ranges sort before all else */
+	if (empty1 && empty2)
+		result = 0;
+	else if (empty1)
+		result = -1;
+	else if (empty2)
+		result = 1;
+	else
+		result = range_cmp_bounds(typcache, &lower1, &lower2);
+
+	if ((Datum) range_a != a)
+		pfree(range_a);
+
+	if ((Datum) range_b != b)
+		pfree(range_b);
+
+	return result;
+}
+
 /*
  * Find class number for range.
  *
diff --git a/src/include/catalog/pg_amproc.dat b/src/include/catalog/pg_amproc.dat
index 4cc129bebd..9318ad5fd8 100644
--- a/src/include/catalog/pg_amproc.dat
+++ b/src/include/catalog/pg_amproc.dat
@@ -600,6 +600,9 @@
 { amprocfamily => 'gist/range_ops', amproclefttype => 'anyrange',
   amprocrighttype => 'anyrange', amprocnum => '7',
   amproc => 'range_gist_same' },
+{ amprocfamily => 'gist/range_ops', amproclefttype => 'anyrange',
+  amprocrighttype => 'anyrange', amprocnum => '11',
+  amproc => 'range_gist_sortsupport' },
 { amprocfamily => 'gist/network_ops', amproclefttype => 'inet',
   amprocrighttype => 'inet', amprocnum => '1',
   amproc => 'inet_gist_consistent' },
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 87aa571a33..47676fb53e 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -10376,6 +10376,9 @@
 { oid => '3881', descr => 'GiST support',
   proname => 'range_gist_same', prorettype => 'internal',
   proargtypes => 'anyrange anyrange internal', prosrc => 'range_gist_same' },
+{ oid => '8849', descr => 'GiST support',
+  proname => 'range_gist_sortsupport', prorettype => 'void',
+  proargtypes => 'internal', prosrc => 'range_gist_sortsupport' },
 { oid => '6154', descr => 'GiST support',
   proname => 'multirange_gist_consistent', prorettype => 'bool',
   proargtypes => 'internal anymultirange int2 oid internal',
-- 
2.36.1

---

From: Andrey Borodin <[email-masked]>
Date: Wed, 15 Jun 2022 19:39:34 +0500

Hi Christoph!

> On 15 Jun 2022, at 15:45, Christoph Heiss <[email-masked]> wrote:
> 
> By sorting the data before inserting it into the index results in a much better index structure, leading to significant performance improvements.

Here's my version of the very similar idea [0]. It lacks range types support.
On a quick glance your version lacks support of abbreviated sort, so I think benchmarks can be pushed event further :)
Let's merge our efforts and create combined patch?

Please, create a new entry for the patch on Commitfest.

Thank you!

Best regards, Andrey Borodin.

[0] https://commitfest.postgresql.org/37/2824/

---

From: Jacob Champion <[email-masked]>
Date: Tue, 5 Jul 2022 11:13:41 -0700

> `make check-world` reports no regressions.

cfbot is reporting a crash in contrib/btree_gist:

    https://cirrus-ci.com/github/postgresql-cfbot/postgresql/commitfest/38/3686

Thanks,
--Jacob

---

From: Jacob Champion <[email-masked]>
Date: Tue, 2 Aug 2022 11:01:00 -0700

This entry has been waiting on author input for a while (our current
threshold is roughly two weeks), so I've marked it Returned with
Feedback.

Once you think the patchset is ready for review again, you (or any
interested party) can resurrect the patch entry by visiting

    https://commitfest.postgresql.org/38/3686/

and changing the status to "Needs Review", and then changing the
status again to "Move to next CF". (Don't forget the second step;
hopefully we will have streamlined this in the near future!)

Thanks,
--Jacob

---

From: Christoph Heiss <[email-masked]>
Date: Wed, 31 Aug 2022 21:15:40 +0200

Hi!

Sorry for the long delay.

This fixes the crashes, now all tests run fine w/ and w/o debug 
configuration. That shouldn't even have slipped through as such.

Notable changes from v1:
- gbt_enum_sortsupport() now passes on fcinfo->flinfo
   enum_cmp_internal() needs a place to cache the typcache entry.
- inet sortsupport now uses network_cmp() directly

Thanks,
Christoph Heiss

From 667779bc0761c1356141722181c5a54ac46d96b9 Mon Sep 17 00:00:00 2001
From: Christoph Heiss <[email-masked]>
Date: Wed, 31 Aug 2022 19:20:43 +0200
Subject: [PATCH v2 1/1] Add sortsupport for range types and btree_gist

Signed-off-by: Christoph Heiss <[email-masked]>
---
 contrib/btree_gist/Makefile                 |   3 +-
 contrib/btree_gist/btree_bit.c              |  19 ++++
 contrib/btree_gist/btree_bool.c             |  22 ++++
 contrib/btree_gist/btree_cash.c             |  22 ++++
 contrib/btree_gist/btree_enum.c             |  26 +++++
 contrib/btree_gist/btree_gist--1.7--1.8.sql | 110 ++++++++++++++++++++
 contrib/btree_gist/btree_gist.control       |   2 +-
 contrib/btree_gist/btree_inet.c             |  19 ++++
 contrib/btree_gist/btree_interval.c         |  19 ++++
 contrib/btree_gist/btree_macaddr8.c         |  19 ++++
 contrib/btree_gist/btree_time.c             |  19 ++++
 src/backend/utils/adt/rangetypes_gist.c     |  70 +++++++++++++
 src/include/catalog/pg_amproc.dat           |   3 +
 src/include/catalog/pg_proc.dat             |   3 +
 14 files changed, 354 insertions(+), 2 deletions(-)
 create mode 100644 contrib/btree_gist/btree_gist--1.7--1.8.sql

 
+static int
 
 typedef struct boolkey
 {
 
 static bool
 
 typedef struct
 {
 
 static bool
index d4dc38a38e..33b9a34235 100644

@@ -26,8 +27,16 @@ PG_FUNCTION_INFO_V1(gbt_enum_picksplit);

+static int
+	return DatumGetInt32(CallerFInfoFunctionCall2(enum_cmp, ssup->ssup_extra,
+												  InvalidOid, x, y));
@@ -183,3 +192,20 @@ gbt_enum_same(PG_FUNCTION_ARGS)
+	 * Since enum_fast_cmp() also uses enum_cmp() like the rest of the
+	 * comparsion functions, it also needs to pass on flinfo when calling
+	 * it. Thus save it in ->ssup_extra and later retrieve it in enum_fast_cmp().
+	ssup->ssup_extra = fcinfo->flinfo;
index 0000000000..a5ac9657cc
@@ -0,0 +1,110 @@
+CREATE FUNCTION gbt_inet_sortsupport(internal)
+    FUNCTION    11  (inet, inet) gbt_inet_sortsupport (internal) ;
diff --git a/contrib/btree_gist/btree_inet.c b/contrib/btree_gist/btree_inet.c
index 2fb952dca8..1f519cfd61 100644
--- a/contrib/btree_gist/btree_inet.c
+++ b/contrib/btree_gist/btree_inet.c
@@ -8,6 +8,7 @@
 #include "catalog/pg_type.h"
 
 typedef struct inetkey
 {
@@ -24,8 +25,15 @@ 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 int
+inet_fast_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	return DatumGetInt32(DirectFunctionCall2(network_cmp, x, y));
+}
+
 static bool
 gbt_inetgt(const void *a, const void *b, FmgrInfo *flinfo)
 {
@@ -185,3 +193,14 @@ gbt_inet_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_inet_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	ssup->comparator = inet_fast_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_interval.c b/contrib/btree_gist/btree_interval.c
index c2bf82086d..80179adc99 100644
--- a/contrib/btree_gist/btree_interval.c
+++ b/contrib/btree_gist/btree_interval.c
@@ -6,6 +6,7 @@
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "utils/builtins.h"
+#include "utils/sortsupport.h"
 #include "utils/timestamp.h"
 
 typedef struct

+static int
 
 typedef struct
 {

+static int
 
 typedef struct

 #ifdef USE_FLOAT8_BYVAL

+static int
index 777fdf0e2e..f77fc213f8 100644
 
 /*
 
+/*
@@ -1693,6 +1709,60 @@ range_gist_consider_split(ConsiderSplitContext *context,
 	}
 }
 
+/*
index be47583122..e0c1169871 100644
@@ -10384,6 +10384,9 @@
2.37.2

---

From: Andres Freund <[email-masked]>
Date: Sun, 2 Oct 2022 00:23:32 -0700

Hi,

> - inet sortsupport now uses network_cmp() directly

Updated the patch to add the minimal change for meson compat.

Greetings,

Andres Freund

---

From: Andres Freund <[email-masked]>
Date: Sun, 2 Oct 2022 00:29:01 -0700

> Updated the patch to add the minimal change for meson compat.

Now I made the same mistake of not adding the change... Clearly I need to stop
for tonight. Either way, here's the hopefully correct change.

---

From: Bernd Helmle <[email-masked]>
Date: Wed, 30 Nov 2022 18:25:25 +0100

Hi,

No deep code review yet, but CF is approaching its end and i didn't
have time to look at this earlier :/ 

Below are some things i've tested so far.

> 100 iterations to get good averages.

Here are my results with repeating this:

HEAD:
-- token index (buffering=auto)
CREATE INDEX Time: 700213,110 ms (11:40,213)

HEAD patched:

-- token index (buffering=auto)
CREATE INDEX Time: 136229,400 ms (02:16,229)

So index creation speed on the test set (table filled with the tokens
and then creating the index afterwards) gets a lot of speedup with this
patch and default buffering strategy.

> > I/O Read Time (average): 0.19 -> 0.15 ms

I've changed this a little and did the following:

So creating the index _after_ having loaded the tokens.
My configuration was:

shared_buffers = 4G
max_wal_size = 6G
effective_cache_size = 4g # (default, index fits)
maintenance_work_mem = 1G

Here are my numbers from the attached benchmark script 

HEAD -> HEAD patched:

Shared Hit Blocks (avg) : 76.81 -> 9.17
Shared Read Blocks (avg): 0.43 -> 0.11
Execution Time (avg)    : 0.40 -> 0.05
IO Read Time (avg)      : 0.001 -> 0.0007

So with these settings i see an improvement with the provided test set.
Since this patches adds sortsupport for all other existing opclasses, i
thought to give it a try with another test set. What i did was to adapt
the benchmark script (see attached) to use the "pgbench_accounts" table
which i changed to instead using the primary key to have a btree_gist
index on column "aid".

I let pgbench fill its tables with scale = 1000, dropped the primary
key, create the btree_gist on "aid" with default buffering strategy:

pgbench -s 1000 -i bernd

ALTER TABLE pgbench_accounts DROP CONSTRAINT pgbench_accounts_pkey ;
CREATE INDEX ON pgbench_accounts USING gist(aid);

Ran the benchmark script bench-gist-pgbench_accounts.py:

The numbers are:

HEAD -> HEAD patched

Shared Hit Blocks (avg) : 4.85 -> 8.75
Shared Read Blocks (avg): 0.14 -> 0.17
Execution Time (avg)    : 0.01 -> 0.05
IO Read Time (avg)      : 0.0003 -> 0.0009

So numbers got worse here. You can uncover this when using pgbench
against that modified table in a much more worse outcome.

Running

pgbench -s 1000 -c 16 -j 16 -S -Mprepared -T 300 

on my workstation at least 3 times gives me the following numbers:

HEAD:

tps = 215338.784398 (without initial connection time)
tps = 212826.513727 (without initial connection time)
tps = 212102.857891 (without initial connection time)

HEAD patched:

tps = 126487.796716 (without initial connection time)
tps = 125076.391528 (without initial connection time)
tps = 124538.946388 (without initial connection time)

So this doesn't look good. While this patch gets a real improvement for
the provided tokens, it makes performance for at least int4 on this
test worse. Though the picture changes again if you build the index
buffered:

tps = 198409.248911 (without initial connection time)
tps = 194431.827394 (without initial connection time)
tps = 195657.532281 (without initial connection time)

which is again close to current HEAD (i have no idea why it is even
*that* slower, since "buffered=on" shouldn't employ sortsupport, no?).
Of course, built time for the index in this case is much slower again:

-- pgbench_accounts index (buffered)
CREATE INDEX Time: 900912,924 ms (15:00,913)

So while providing a huge improvement on index creation speed it's
sometimes still required to carefully check the index quality.

[...]

> wanted to get other opinions on that first.

Hmm i'd say we leave them in the contrib module until they are required
somewhere else, too or make a separate patch for them? Do we have plans
to have such requirement in the backend already?

Attached is a rebased patch against current HEAD.

Thanks

	Bernd

---

From: vignesh C <[email-masked]>
Date: Fri, 26 Jan 2024 18:31:12 +0530

On Wed, 10 Jan 2024 at 19:49, jian he <[email-masked]> wrote:
>
> On Wed, Jan 10, 2024 at 8:00 AM jian he <[email-masked]> wrote:
> >
> > `
> > from the doc, add sortsupport function will only influence index build time?
> >
> > +/*
> > per https://www.postgresql.org/docs/current/gist-extensibility.html
> > QUOTE:
> > All the GiST support methods are normally called in short-lived memory
> > contexts; that is, CurrentMemoryContext will get reset after each
> > tuple is processed. It is therefore not very important to worry about
> > pfree'ing everything you palloc. However, in some cases it's useful
> > for a support method to
> > ENDOF_QUOTE
> >
> > so removing the following part should be OK.
> > comparison solely on the lower bounds looks strange to me.
> > if lower bound is the same, then compare upper bound, so the
> > range_gist_cmp function is consistent with function range_compare.
> > so following change:
> >
> > + else
> > to
> > `
> > else
> > result = range_cmp_bounds(typcache, &lower1, &lower2);
> > if (result == 0)
> > result = range_cmp_bounds(typcache, &upper1, &upper2);
> > }
> > `
> >
> > does contrib/btree_gist/btree_gist--1.7--1.8.sql function be declared
> > as strict ? (I am not sure)
> > other than that, the whole patch looks good.
>
> the original author email address ([email-masked])
> Address not found.
> so I don't include it.
>
> I split the original author's patch into 2.
> 1. Add GiST sortsupport function for all the btree-gist module data
> types except anyrange data type (which actually does not in this
> module)
> 2. Add GiST sortsupport function for anyrange data type.

CFBot shows that the patch does not apply anymore as in [1]:
=== Applying patches on top of PostgreSQL commit ID
7014c9a4bba2d1b67d60687afb5b2091c1d07f73 ===
=== applying patch
./v5-0001-Add-GIST-sortsupport-function-for-all-the-btree-g.patch
patching file contrib/btree_gist/Makefile
Hunk #1 FAILED at 33.
1 out of 1 hunk FAILED -- saving rejects to file contrib/btree_gist/Makefile.rej
...
The next patch would create the file
contrib/btree_gist/btree_gist--1.7--1.8.sql,
which already exists!  Applying it anyway.
patching file contrib/btree_gist/btree_gist--1.7--1.8.sql
Hunk #1 FAILED at 1.
1 out of 1 hunk FAILED -- saving rejects to file
contrib/btree_gist/btree_gist--1.7--1.8.sql.rej
patching file contrib/btree_gist/btree_gist.control
Hunk #1 FAILED at 1.
1 out of 1 hunk FAILED -- saving rejects to file
contrib/btree_gist/btree_gist.control.rej
...
patching file contrib/btree_gist/meson.build
Hunk #1 FAILED at 50.
1 out of 1 hunk FAILED -- saving rejects to file
contrib/btree_gist/meson.build.rej

Please post an updated version for the same.

[1] - http://cfbot.cputube.org/patch_46_3686.log

Regards,
Vignesh

---

From: Bernd Helmle <[email-masked]>
Date: Fri, 26 Jan 2024 19:22:28 +0100

> === Applying patches on top of PostgreSQL commit ID

I've started working on it and planning to submit a polished patch for
the upcoming CF.

---

From: Bernd Helmle <[email-masked]>
Date: Mon, 11 Nov 2024 17:41:25 +0100

Am Samstag, dem 26.10.2024 um 11:40 +0300 schrieb Andrey M. Borodin:
> First patch:
> 0. We have PG_FREE_IF_COPY(), does it suits your needs?
> 1. Tests do not check what actual build method is used. You can add
> INJECTION_POINT("gist-sort-build") and expect a notice there or
> something like that.
> 2. "Per default" -> "By default", "indexe" -> "index", "index
> quality" -> NULL (in 14 quality was bad, since 15 same "quality")
> 

Updated and rebased patches attached. I used the injection point name
"btree-gist-sorted-build".

> Second patch:
> 0. PG_FREE_IF_COPY in range_gist_cmp? :)
> 1. Some test of this new functionality?

I added the same injection point here, too, since the functionalitly is
already employed in btree_gist regression tests "partition" and
"without_overlap".

Except the suggestions for PG_FREE_IF_COPY(), this updated patch set
reflects all the comments from Andrey above.

Playing with these suggested changes also revealed some bugs (i
confused some of the comparator functions for macaddr*), so thanks
again for the review!

Thanks,
	Bernd

diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile
index 7ac2df26c10..736309b6e68 100644
--- a/contrib/btree_gist/Makefile
+++ b/contrib/btree_gist/Makefile
@@ -34,13 +34,20 @@ 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.6--1.7.sql \
-       btree_gist--1.7--1.8.sql
+       btree_gist--1.7--1.8.sql btree_gist--1.8--1.9.sql
 PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes"
 
-REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \
-        time timetz date interval macaddr macaddr8 inet cidr text varchar char \
-        bytea bit varbit numeric uuid not_equal enum bool partitions \
-        stratnum without_overlaps
+REGRESS = init int2 int2_buffering int4 int4_buffering int8 int8_buffering float4 \
+		  float4_buffering float8 float8__buffering cash cash_buffering \
+ 		  oid oid_buffering timestamp timestamp_buffering timestamptz \
+ 		  timestamptz_buffering time time_buffering timetz timetz_buffering date \
+ 		  date_buffering interval interval_buffering macaddr macaddr_buffering \
+ 		  macaddr8 macaddr8_buffering inet inet_buffering cidr cidr_buffering text \
+ 		  text_buffering varchar varchar_buffering char char_buffering \
+          bytea bytea_buffering bit bit_buffering varbit varbit_buffering numeric \
+          numeric_buffering uuid uuid_buffering not_equal not_equal_buffering \
+          enum enum_buffering bool bool_buffering partitions partitions_buffering \
+          stratnum without_overlaps cleanup
 
 SHLIB_LINK += $(filter -lm, $(LIBS))
 
index 9d5e01a1977..e979e0f6b7d 100644

@@ -18,10 +19,33 @@ 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);
+PG_FUNCTION_INFO_V1(gbt_varbit_sortsupport);

+static int
+gbt_bit_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	GBT_VARKEY *key1 = PG_DETOAST_DATUM(x);
+	GBT_VARKEY *key2 = PG_DETOAST_DATUM(y);
+
+	GBT_VARKEY_R arg1 = gbt_var_key_readable(key1);
+	GBT_VARKEY_R arg2 = gbt_var_key_readable(key2);
+	Datum result;
+
+	/* lower is always equal to upper, so just compare those fields */
+	result = DirectFunctionCall2(byteacmp,
+								 PointerGetDatum(arg1.lower),
+								 PointerGetDatum(arg2.lower));
+
+	GBT_FREE_IF_COPY(key1, x);
+	GBT_FREE_IF_COPY(key2, y);
+
+	return DatumGetInt32(result);
+}
+
 static bool
 gbt_bitgt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
 {
@@ -207,3 +231,29 @@ gbt_bit_penalty(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_var_penalty(result, o, n, PG_GET_COLLATION(),
 									  &tinfo, fcinfo->flinfo));
 }
+
+Datum
+gbt_bit_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_bit_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
+
+Datum
+gbt_varbit_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	ssup->comparator = gbt_bit_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
\ No newline at end of file
diff --git a/contrib/btree_gist/btree_bool.c b/contrib/btree_gist/btree_bool.c
index bdc7834bb6a..bba38b10cca 100644
--- a/contrib/btree_gist/btree_bool.c
+++ b/contrib/btree_gist/btree_bool.c
@@ -5,6 +5,7 @@
 
 #include "btree_gist.h"
 
 typedef struct boolkey
 {
@@ -22,6 +23,16 @@ PG_FUNCTION_INFO_V1(gbt_bool_picksplit);
 PG_FUNCTION_INFO_V1(gbt_bool_consistent);
 PG_FUNCTION_INFO_V1(gbt_bool_penalty);
 PG_FUNCTION_INFO_V1(gbt_bool_same);
+PG_FUNCTION_INFO_V1(gbt_bool_sortsupport);
+
+static int
+gbt_bool_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	boolKEY	*arg1 = (boolKEY *) DatumGetPointer(x);
+	boolKEY *arg2 = (boolKEY *) DatumGetPointer(y);
+
+	return arg1->lower - arg2->lower;
+}
 
 static bool
 gbt_boolgt(const void *a, const void *b, FmgrInfo *flinfo)
@@ -166,3 +177,18 @@ gbt_bool_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_bool_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_bool_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_bytea.c b/contrib/btree_gist/btree_bytea.c
index 394e40ed16b..9c22dc7f2a0 100644
--- a/contrib/btree_gist/btree_bytea.c
+++ b/contrib/btree_gist/btree_bytea.c
@@ -6,6 +6,7 @@
 #include "btree_gist.h"
 #include "btree_utils_var.h"
 #include "utils/fmgrprotos.h"
+#include "utils/sortsupport.h"

 /*
@@ -17,7 +18,45 @@ 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);
 
+/* sortsupport support */
+
+static int
+gbt_bytea_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	GBT_VARKEY *key1 = PG_DETOAST_DATUM(x);
+	GBT_VARKEY *key2 = PG_DETOAST_DATUM(y);
+
+	GBT_VARKEY_R xkey = gbt_var_key_readable(key1);
+	GBT_VARKEY_R ykey = gbt_var_key_readable(key2);
+	Datum result;
+
+	/* lower and upper are always the same, so it is enough to compare lower */
+	result = DirectFunctionCall2(byteacmp,
+								 PointerGetDatum(xkey.lower),
+								 PointerGetDatum(ykey.lower));
+
+	GBT_FREE_IF_COPY(key1, x);
+	GBT_FREE_IF_COPY(key2, y);
+
+	return DatumGetInt32(result);
+}
+
+Datum
+gbt_bytea_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_bytea_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}

index 546b948ea40..c215ced3371 100644
 
 typedef struct
 {
@@ -25,6 +26,21 @@ 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);
+
+extern Datum cash_cmp(PG_FUNCTION_ARGS);
+
+static int
+gbt_cash_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	cashKEY	*arg1 = (cashKEY *) DatumGetPointer(x);
+	cashKEY	*arg2 = (cashKEY *) DatumGetPointer(y);
+
+	/* Since lower and upper are always equal, it is enough to compare lower */
+	return DatumGetInt32(DirectFunctionCall2(cash_cmp,
+											 CashGetDatum(arg1->lower),
+											 CashGetDatum(arg2->lower)));
+}
 
 static bool
 gbt_cashgt(const void *a, const void *b, FmgrInfo *flinfo)
@@ -215,3 +231,18 @@ gbt_cash_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_cash_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_cash_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_date.c b/contrib/btree_gist/btree_date.c
index 5efb5ef96f5..f6c03721572 100644
--- a/contrib/btree_gist/btree_date.c
+++ b/contrib/btree_gist/btree_date.c
@@ -7,6 +7,7 @@
 #include "btree_utils_num.h"
 #include "utils/fmgrprotos.h"
 #include "utils/date.h"
+#include "utils/sortsupport.h"
 
 typedef struct
 {
@@ -25,6 +26,34 @@ 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);
+
+/* sortsupport functions */
+
+static int gbt_date_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	dateKEY *akey = (dateKEY *) DatumGetPointer(x);
+	dateKEY *bkey = (dateKEY *) DatumGetPointer(y);
+
+	return DatumGetInt32(DirectFunctionCall2(date_cmp,
+											 DateADTGetDatum(akey->lower),
+											 DateADTGetDatum(bkey->lower)));
+}
+
+Datum
+gbt_date_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_date_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
 
 static bool
 gbt_dategt(const void *a, const void *b, FmgrInfo *flinfo)
diff --git a/contrib/btree_gist/btree_enum.c b/contrib/btree_gist/btree_enum.c
index 26682122f8e..179ed94c6e1 100644
--- a/contrib/btree_gist/btree_enum.c
+++ b/contrib/btree_gist/btree_enum.c
@@ -7,6 +7,7 @@
 #include "btree_utils_num.h"
 #include "fmgr.h"
 #include "utils/fmgrprotos.h"
+#include "utils/sortsupport.h"

@@ -26,8 +27,23 @@ PG_FUNCTION_INFO_V1(gbt_enum_picksplit);

+static int
+gbt_enum_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	oidKEY *arg1 = (oidKEY *) DatumGetPointer(x);
+	oidKEY *arg2 = (oidKEY *) DatumGetPointer(y);
+
+	/* Since lower and upper oidKEY are always the same, just compare lower */
+	return DatumGetInt32(CallerFInfoFunctionCall2(enum_cmp,
+												  ssup->ssup_extra,
+												  InvalidOid,
+												  arg1->lower,
+												  arg2->lower));
+}
+
 static bool
 gbt_enumgt(const void *a, const void *b, FmgrInfo *flinfo)
 {
@@ -183,3 +199,24 @@ gbt_enum_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_enum_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	ssup->comparator = gbt_enum_ssup_cmp;
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	/*
+	 * Since enum_fast_cmp() also uses enum_cmp() like the rest of the
+	 * comparison functions, it also needs to pass flinfo when calling
+	 * it. Thus save it in ssup_extra and retrieve it in enum_fast_cmp() later.
+	 */
+	ssup->ssup_extra = fcinfo->flinfo;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_float4.c b/contrib/btree_gist/btree_float4.c
index 84ca5eee501..a572ac1fcad 100644
--- a/contrib/btree_gist/btree_float4.c
+++ b/contrib/btree_gist/btree_float4.c
@@ -5,6 +5,7 @@
 
 #include "btree_gist.h"
 #include "utils/float.h"
 
 typedef struct float4key
@@ -24,6 +25,37 @@ 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);
+
+extern Datum btfloat4cmp(PG_FUNCTION_ARGS);
+
+/* sortsupport functions */
+static int
+gbt_float4_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	float4KEY *arg1 = (float4KEY *) DatumGetPointer(x);
+	float4KEY *arg2 = (float4KEY *) DatumGetPointer(y);
+
+	/* Since lower and upper for float4KEYs here are always equal it is okay to compare them only */
+	return DatumGetInt32(DirectFunctionCall2(btfloat4cmp,
+											 Float4GetDatum(arg1->lower),
+											 Float4GetDatum(arg2->lower)));
+}
+
+Datum
+gbt_float4_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_float4_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
 
 static bool
 gbt_float4gt(const void *a, const void *b, FmgrInfo *flinfo)
diff --git a/contrib/btree_gist/btree_float8.c b/contrib/btree_gist/btree_float8.c
index 081a719b006..7545884f82e 100644
--- a/contrib/btree_gist/btree_float8.c
+++ b/contrib/btree_gist/btree_float8.c
@@ -5,6 +5,7 @@
 
 #include "btree_gist.h"
 #include "utils/float.h"
 
 typedef struct float8key
@@ -24,7 +25,37 @@ 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);
 
+extern Datum btfloat8cmp(PG_FUNCTION_ARGS);
+
+/* sortsupport functions */
+static int
+gbt_float8_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	float8KEY *arg1 = (float8KEY *) DatumGetPointer(x);
+	float8KEY *arg2 = (float8KEY *) DatumGetPointer(y);
+
+	/* upper and lower for input keys are equal here */
+	return DatumGetInt32(DirectFunctionCall2(btfloat8cmp,
+											 Float8GetDatum(arg1->lower),
+											 Float8GetDatum(arg2->lower)));
+}
+
+Datum
+gbt_float8_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_float8_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
 
 static bool
 gbt_float8gt(const void *a, const void *b, FmgrInfo *flinfo)
diff --git a/contrib/btree_gist/btree_gist--1.8--1.9.sql b/contrib/btree_gist/btree_gist--1.8--1.9.sql
new file mode 100644
index 00000000000..97c6d36ace5
--- /dev/null
+++ b/contrib/btree_gist/btree_gist--1.8--1.9.sql
@@ -0,0 +1,192 @@
+/* contrib/btree_gist/btree_gist--1.7--1.8.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.9'" to load this file. \quit
+
+CREATE FUNCTION gbt_bit_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_varbit_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_bool_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_cash_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_enum_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_inet_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_intv_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_time_sortsupport(internal)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_int2_sortsupport(internal)
+    RETURNS void
+AS 'MODULE_PATHNAME'
+    LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_int4_sortsupport(internal)
+    RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_int8_sortsupport(internal)
+    RETURNS void
+AS 'MODULE_PATHNAME'
+    LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_bytea_sortsupport(internal)
+    RETURNS void
+AS 'MODULE_PATHNAME'
+    LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_date_sortsupport(internal)
+    RETURNS void
+AS 'MODULE_PATHNAME'
+    LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_float4_sortsupport(internal)
+    RETURNS void
+AS 'MODULE_PATHNAME'
+    LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_float8_sortsupport(internal)
+    RETURNS void
+AS 'MODULE_PATHNAME'
+    LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macaddr_sortsupport(internal)
+    RETURNS void
+AS 'MODULE_PATHNAME'
+    LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_numeric_sortsupport(internal)
+    RETURNS void
+AS 'MODULE_PATHNAME'
+    LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_oid_sortsupport(internal)
+    RETURNS void
+AS 'MODULE_PATHNAME'
+    LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_text_sortsupport(internal)
+    RETURNS void
+AS 'MODULE_PATHNAME'
+    LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_ts_sortsupport(internal)
+    RETURNS void
+AS 'MODULE_PATHNAME'
+    LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_uuid_sortsupport(internal)
+    RETURNS void
+AS 'MODULE_PATHNAME'
+    LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_vbit_ops USING gist ADD
+    FUNCTION    11  (varbit, varbit) gbt_varbit_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_bit_ops USING gist ADD
+    FUNCTION    11  (bit, bit) gbt_bit_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_bool_ops USING gist ADD
+    FUNCTION    11  (bool, bool) gbt_bool_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_bytea_ops USING gist ADD
+    FUNCTION    11  (bytea, bytea) gbt_bytea_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_cash_ops USING gist ADD
+    FUNCTION    11  (money, money) gbt_cash_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_date_ops USING gist ADD
+    FUNCTION    11  (date, date) gbt_date_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_enum_ops USING gist ADD
+    FUNCTION    11  (anyenum, anyenum) gbt_enum_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_float4_ops USING gist ADD
+    FUNCTION    11  (float4, float4) gbt_float4_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_float8_ops USING gist ADD
+    FUNCTION    11  (float8, float8) gbt_float8_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_inet_ops USING gist ADD
+    FUNCTION    11  (inet, inet) gbt_inet_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_cidr_ops USING gist ADD
+    FUNCTION    11  (inet, inet) gbt_inet_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_int2_ops USING gist ADD
+    FUNCTION    11  (int2, int2) gbt_int2_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_int4_ops USING gist ADD
+    FUNCTION    11  (int4, int4) gbt_int4_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_int8_ops USING gist ADD
+    FUNCTION    11  (int8, int8) gbt_int8_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_interval_ops USING gist ADD
+    FUNCTION    11  (interval, interval) gbt_intv_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_macaddr_ops USING gist ADD
+    FUNCTION    11  (macaddr, macaddr) gbt_macaddr_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_macaddr8_ops USING gist ADD
+    FUNCTION    11  (macaddr8, macaddr8) gbt_macad8_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_numeric_ops USING gist ADD
+    FUNCTION    11  (numeric, numeric) gbt_numeric_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_oid_ops USING gist ADD
+    FUNCTION    11  (oid, oid) gbt_oid_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_text_ops USING gist ADD
+    FUNCTION    11  (text, text) gbt_text_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_bpchar_ops USING gist ADD
+    FUNCTION    11  (bpchar, bpchar) bpchar_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_time_ops USING gist ADD
+    FUNCTION    11  (time, time) gbt_time_sortsupport (internal) ;
+
+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) ;
+
+ALTER OPERATOR FAMILY gist_timetz_ops USING gist ADD
+    FUNCTION    11  (timetz, timetz) gbt_time_sortsupport (internal) ;
+
+ALTER OPERATOR FAMILY gist_uuid_ops USING gist ADD
+    FUNCTION    11  (uuid, uuid) gbt_uuid_sortsupport (internal) ;
diff --git a/contrib/btree_gist/btree_gist.c b/contrib/btree_gist/btree_gist.c
index 5fd4cce27d0..c8acbe76b55 100644
--- a/contrib/btree_gist/btree_gist.c
+++ b/contrib/btree_gist/btree_gist.c
@@ -6,6 +6,9 @@
 #include "access/stratnum.h"
 #include "utils/builtins.h"
 
+#include "access/gist.h"
+#include "btree_gist.h"
+
 PG_MODULE_MAGIC;
 
 PG_FUNCTION_INFO_V1(gbt_decompress);
diff --git a/contrib/btree_gist/btree_gist.control b/contrib/btree_gist/btree_gist.control
index abf66538f32..69d9341a0ad 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.8'
+default_version = '1.9'
 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 0db8522c8a7..729a6602d1f 100644
--- a/contrib/btree_gist/btree_gist.h
+++ b/contrib/btree_gist/btree_gist.h
@@ -5,10 +5,17 @@
 #define __BTREE_GIST_H__
 
 #include "access/nbtree.h"
+#include "utils/injection_point.h"
 #include "fmgr.h"
 
 #define BtreeGistNotEqualStrategyNumber 6
 
+typedef struct int32key
+{
+  int32		lower;
+  int32		upper;
+} int32KEY;
+
 /* indexed types */
 
 enum gbtree_type
index c66ca99e0c3..4c845924424 100644
 
 typedef struct inetkey
 {
@@ -23,8 +24,23 @@ PG_FUNCTION_INFO_V1(gbt_inet_picksplit);

+static int
+gbt_inet_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	inetKEY *arg1 = (inetKEY *) DatumGetPointer(x);
+	inetKEY *arg2 = (inetKEY *) DatumGetPointer(y);
+
+	if (arg1->lower == arg2->lower)
+		return 0;
+	else if (arg1->lower > arg2->lower)
+		return 1;
+	else
+		return -1;
+}
+
 static bool
 gbt_inetgt(const void *a, const void *b, FmgrInfo *flinfo)
 {
@@ -184,3 +200,18 @@ gbt_inet_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_inet_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_inet_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_int2.c b/contrib/btree_gist/btree_int2.c
index fdbf156586c..40af403a209 100644
--- a/contrib/btree_gist/btree_int2.c
+++ b/contrib/btree_gist/btree_int2.c
@@ -5,6 +5,7 @@
 
 #include "btree_gist.h"
 
 typedef struct int16key
@@ -24,6 +25,35 @@ 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);
+
+/* sortsupport functions */
+static int
+gbt_int2_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	int16KEY *arg1 = (int16KEY *) DatumGetPointer(x);
+	int16KEY *arg2 = (int16KEY *) DatumGetPointer(y);
+
+	if (arg1->lower < arg2->lower)
+		return -1;
+	else if (arg1->lower > arg2->lower)
+		return 1;
+	else
+		return 0;
+}
+
+Datum
+gbt_int2_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_int2_ssup_cmp;
+	PG_RETURN_VOID();
+}
 
 static bool
 gbt_int2gt(const void *a, const void *b, FmgrInfo *flinfo)
diff --git a/contrib/btree_gist/btree_int4.c b/contrib/btree_gist/btree_int4.c
index 8915fb5d087..debfcb23a22 100644
--- a/contrib/btree_gist/btree_int4.c
+++ b/contrib/btree_gist/btree_int4.c
@@ -2,16 +2,10 @@
  * contrib/btree_gist/btree_int4.c
  */
 #include "postgres.h"
-
+#include "common/int.h"
+#include "utils/sortsupport.h"
 #include "btree_gist.h"
 #include "btree_utils_num.h"
-#include "common/int.h"
-
-typedef struct int32key
-{
-	int32		lower;
-	int32		upper;
-} int32KEY;
 
 /*
 ** int32 ops
@@ -24,6 +18,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
@@ -90,6 +85,33 @@ static const gbtree_ninfo tinfo =
 	gbt_int4_dist
 };
 
+static int
+gbt_int4_ssup_cmp(Datum a, Datum b, SortSupport ssup)
+{
+	int32KEY   *ia = (int32KEY *) DatumGetPointer(a);
+	int32KEY   *ib = (int32KEY *) DatumGetPointer(b);
+
+	/* int4KEY upper and lower are always the same for input keys here. */
+	if (ia->lower < ib->lower)
+		return -1;
+	else if (ia->lower > ib->lower)
+		return 1;
+	else
+		return 0;
+}
+
+Datum
+gbt_int4_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_int4_ssup_cmp;
+	PG_RETURN_VOID();
+}
 
 PG_FUNCTION_INFO_V1(int4_dist);
 Datum
diff --git a/contrib/btree_gist/btree_int8.c b/contrib/btree_gist/btree_int8.c
index 7c63a5b6dc1..8477f0134f0 100644
--- a/contrib/btree_gist/btree_int8.c
+++ b/contrib/btree_gist/btree_int8.c
@@ -6,6 +6,7 @@
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "common/int.h"
+#include "utils/sortsupport.h"
 
 typedef struct int64key
 {
@@ -24,7 +25,36 @@ 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);
 
+/* sortsupport functions */
+static int
+gbt_int8_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	int64KEY *arg1 = (int64KEY *) DatumGetPointer(x);
+	int64KEY *arg2 = (int64KEY *) DatumGetPointer(y);
+
+	if (arg1->lower < arg2->lower)
+		return -1;
+	else if (arg1->lower > arg2->lower)
+		return 1;
+	else
+		return 0;
+
+}
+
+Datum
+gbt_int8_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_int8_ssup_cmp;
+	PG_RETURN_VOID();
+}
 
 static bool
 gbt_int8gt(const void *a, const void *b, FmgrInfo *flinfo)
diff --git a/contrib/btree_gist/btree_interval.c b/contrib/btree_gist/btree_interval.c
index c2f6eede226..aaea7d731e8 100644
--- a/contrib/btree_gist/btree_interval.c
+++ b/contrib/btree_gist/btree_interval.c
@@ -6,6 +6,7 @@
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "utils/fmgrprotos.h"
+#include "utils/sortsupport.h"
 #include "utils/timestamp.h"
 
 typedef struct
@@ -27,8 +28,21 @@ PG_FUNCTION_INFO_V1(gbt_intv_consistent);

+static int
+gbt_intv_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	intvKEY *arg1 = (intvKEY *) DatumGetPointer(x);
+	intvKEY *arg2 = (intvKEY *) DatumGetPointer(y);
+
+	/* intvKEY lower and upper are always equal here, so compare just lower members is enough */
+	return DatumGetInt32(DirectFunctionCall2(interval_cmp,
+											 IntervalPGetDatum(&arg1->lower),
+											 IntervalPGetDatum(&arg2->lower)));
+}
+
 static bool
 gbt_intvgt(const void *a, const void *b, FmgrInfo *flinfo)
 {
@@ -295,3 +309,18 @@ gbt_intv_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_intv_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_intv_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_macaddr.c b/contrib/btree_gist/btree_macaddr.c
index 1367eaba735..8e28736f4fd 100644
--- a/contrib/btree_gist/btree_macaddr.c
+++ b/contrib/btree_gist/btree_macaddr.c
@@ -7,6 +7,7 @@
 #include "btree_utils_num.h"
 #include "utils/fmgrprotos.h"
 #include "utils/inet.h"
+#include "utils/sortsupport.h"
 
 typedef struct
 {
@@ -25,6 +26,38 @@ 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_macaddr_sortsupport);
+
+/* sortsupport functions */
+static int
+gbt_macaddr_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	macKEY *arg1 = (macKEY *) DatumGetPointer(x);
+	macKEY *arg2 = (macKEY *) DatumGetPointer(y);
+
+	/* macKEY lower and upper members are always equal here,
+	 * so its enough to compare just lower.
+	 */
+	return DatumGetInt32(DirectFunctionCall2(macaddr_cmp,
+											 MacaddrPGetDatum(&arg1->lower),
+											 MacaddrPGetDatum(&arg2->lower)));
+
+}
+
+Datum
+gbt_macaddr_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_macaddr_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}

 static bool
index 9676e5a15bd..24114ac09e6 100644
 
 typedef struct
 {
@@ -25,8 +26,20 @@ PG_FUNCTION_INFO_V1(gbt_macad8_picksplit);

+static int
+gbt_macaddr8_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	mac8KEY *arg1 = (mac8KEY *) DatumGetPointer(x);
+	mac8KEY *arg2 = (mac8KEY *) DatumGetPointer(y);
+
+	return DatumGetInt32(DirectFunctionCall2(macaddr8_cmp,
+											 Macaddr8PGetDatum(&arg1->lower),
+											 Macaddr8PGetDatum(&arg2->lower)));
+}
+
 static bool
 gbt_macad8gt(const void *a, const void *b, FmgrInfo *flinfo)
 {
@@ -194,3 +207,18 @@ gbt_macad8_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_macad8_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_macaddr8_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_numeric.c b/contrib/btree_gist/btree_numeric.c
index 35e466cdd94..b4878417aff 100644
--- a/contrib/btree_gist/btree_numeric.c
+++ b/contrib/btree_gist/btree_numeric.c
@@ -11,6 +11,7 @@
 #include "utils/builtins.h"
 #include "utils/numeric.h"
 #include "utils/rel.h"
+#include "utils/sortsupport.h"
 
 /*
 ** Bytea ops
@@ -21,7 +22,43 @@ 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);
 
+/* Sortsupport functions */
+static int
+gbt_numeric_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	GBT_VARKEY *key1 = PG_DETOAST_DATUM(x);
+	GBT_VARKEY *key2 = PG_DETOAST_DATUM(y);
+
+	GBT_VARKEY_R arg1 = gbt_var_key_readable(key1);
+	GBT_VARKEY_R arg2 = gbt_var_key_readable(key2);
+	Datum result;
+
+	result = DirectFunctionCall2(numeric_cmp,
+								 PointerGetDatum(arg1.lower),
+								 PointerGetDatum(arg2.lower));
+
+	GBT_FREE_IF_COPY(key1, x);
+	GBT_FREE_IF_COPY(key2, y);
+
+	return DatumGetInt32(result);
+}
+
+Datum
+gbt_numeric_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_numeric_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}

diff --git a/contrib/btree_gist/btree_oid.c b/contrib/btree_gist/btree_oid.c
index 3cc7d4245d4..818046e10c4 100644
--- a/contrib/btree_gist/btree_oid.c
+++ b/contrib/btree_gist/btree_oid.c
@@ -5,6 +5,7 @@
 
 #include "btree_gist.h"
 
 typedef struct
 {
@@ -23,7 +24,38 @@ 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);
 
+/* Sortsupport functions */
+static int
+gbt_oid_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	oidKEY *arg1 = (oidKEY *) DatumGetPointer(x);
+	oidKEY *arg2 = (oidKEY *) DatumGetPointer(y);
+
+	/* upper and lower fields are equal for each oidKEY, so just compare lower */
+	if (arg1->lower > arg2->lower)
+		return 1;
+	else if (arg1->lower < arg2->lower)
+		return -1;
+	else
+		return 0;
+}
+
+Datum
+gbt_oid_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_oid_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
 
 static bool
 gbt_oidgt(const void *a, const void *b, FmgrInfo *flinfo)
diff --git a/contrib/btree_gist/btree_text.c b/contrib/btree_gist/btree_text.c
index 28d6b5c9c2b..3f65209ab69 100644
--- a/contrib/btree_gist/btree_text.c
+++ b/contrib/btree_gist/btree_text.c
@@ -7,6 +7,7 @@
 #include "btree_utils_var.h"
 #include "mb/pg_wchar.h"
 #include "utils/fmgrprotos.h"
+#include "utils/sortsupport.h"
 
 /*
 ** Text ops
@@ -19,7 +20,44 @@ 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);
 
+/* Sortsupport functions */
+static int
+gbt_text_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	GBT_VARKEY *key1 = PG_DETOAST_DATUM(x);
+	GBT_VARKEY *key2 = PG_DETOAST_DATUM(y);
+
+	GBT_VARKEY_R arg1 = gbt_var_key_readable(key1);
+	GBT_VARKEY_R arg2 = gbt_var_key_readable(key2);
+	Datum result;
+
+	result = DirectFunctionCall2Coll(bttextcmp,
+									 ssup->ssup_collation,
+									 PointerGetDatum(arg1.lower),
+									 PointerGetDatum(arg2.lower));
+
+	GBT_FREE_IF_COPY(key1, x);
+	GBT_FREE_IF_COPY(key2, y);
+
+	return DatumGetInt32(result);
+}
+
+Datum
+gbt_text_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_text_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}

index 3034bbb456b..d25785c65d7 100644
 
 typedef struct
@@ -28,6 +29,8 @@ 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);
+PG_FUNCTION_INFO_V1(gbt_timetz_sortsupport);

 #ifdef USE_FLOAT8_BYVAL
@@ -37,6 +40,18 @@ PG_FUNCTION_INFO_V1(gbt_time_same);
 #endif

+static int
+gbt_timekey_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	timeKEY *arg1 = (timeKEY *) DatumGetPointer(x);
+	timeKEY *arg2 = (timeKEY *) DatumGetPointer(y);
+
+	/* lower and upper are equal during sortsupport comparison */
+	return DatumGetInt32(DirectFunctionCall2(time_cmp,
+											 TimeADTGetDatumFast(arg1->lower),
+											 TimeADTGetDatumFast(arg2->lower)));
+}
+
 static bool
 gbt_timegt(const void *a, const void *b, FmgrInfo *flinfo)
 {
@@ -332,3 +347,18 @@ gbt_time_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_time_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_timekey_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index b3cf2d6f60d..75ea777a1db 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -10,6 +10,7 @@
 #include "utils/fmgrprotos.h"
 #include "utils/timestamp.h"
 #include "utils/float.h"
+#include "utils/sortsupport.h"
 
 typedef struct
 {
@@ -31,6 +32,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
@@ -39,6 +41,33 @@ PG_FUNCTION_INFO_V1(gbt_ts_same);
 #define TimestampGetDatumFast(X) PointerGetDatum(&(X))
 #endif
 
+/* Sortsupport functions */
+static int
+gbt_ts_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	tsKEY *arg1 = (tsKEY *) DatumGetPointer(x);
+	tsKEY *arg2 = (tsKEY *) DatumGetPointer(y);
+
+	/* Sortsupport always gets the same lower and upper value for input keys */
+	return DatumGetInt32(DirectFunctionCall2(timestamp_cmp,
+											 TimestampGetDatumFast(arg1->lower),
+											 TimestampGetDatumFast(arg2->lower)));
+}
+
+Datum
+gbt_ts_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_ts_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
 
 static bool
 gbt_tsgt(const void *a, const void *b, FmgrInfo *flinfo)
diff --git a/contrib/btree_gist/btree_utils_var.h b/contrib/btree_gist/btree_utils_var.h
index 9302d41ced6..f79b553a1e1 100644
--- a/contrib/btree_gist/btree_utils_var.h
+++ b/contrib/btree_gist/btree_utils_var.h
@@ -41,7 +41,17 @@ typedef struct
 	GBT_VARKEY *(*f_l2n) (GBT_VARKEY *, FmgrInfo *flinfo);	/* convert leaf to node */
 } gbtree_vinfo;
 
-
+/*
+ * Free ptr1 in case its a copy of ptr2.
+ *
+ * This is adapted from varlena's PG_FREE_IF_COPY, though
+ * doesn't require fcinfo access.
+ */
+#define GBT_FREE_IF_COPY(ptr1, ptr2) \
+	do { \
+		if ((Pointer) (ptr1) != DatumGetPointer(ptr2)) \
+			pfree(ptr1); \
+	} while (0)
 
 extern GBT_VARKEY_R gbt_var_key_readable(const GBT_VARKEY *k);
 
diff --git a/contrib/btree_gist/btree_uuid.c b/contrib/btree_gist/btree_uuid.c
index fe8c679cbed..73440600c36 100644
--- a/contrib/btree_gist/btree_uuid.c
+++ b/contrib/btree_gist/btree_uuid.c
@@ -6,6 +6,7 @@
 #include "btree_gist.h"
 #include "btree_utils_num.h"
 #include "port/pg_bswap.h"
+#include "utils/sortsupport.h"
 #include "utils/uuid.h"
 
 typedef struct
@@ -25,7 +26,35 @@ 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 uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2);
+
+/* Sortsupport functions */
+static int
+gbt_uuid_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	uuidKEY *arg1 = (uuidKEY *) DatumGetPointer(x);
+	uuidKEY *arg2 = (uuidKEY *) DatumGetPointer(y);
+
+	/* Sortsupport gets equal upper and lower values for each key to compare */
+	return uuid_internal_cmp(&arg1->lower, &arg2->lower);
+}
+
+Datum
+gbt_uuid_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+#ifdef USE_INJECTION_POINTS
+	INJECTION_POINT("btree-gist-sorted-build");
+#endif
+
+	ssup->comparator = gbt_uuid_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
 
 static int
 uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2)
diff --git a/contrib/btree_gist/expected/bit.out b/contrib/btree_gist/expected/bit.out
index e57871f310b..f2fea7282bb 100644
--- a/contrib/btree_gist/expected/bit.out
+++ b/contrib/btree_gist/expected/bit.out
@@ -33,6 +33,7 @@ SELECT count(*) FROM bittmp WHERE a >   '011011000100010111011000110000100';
 (1 row)
 
 CREATE INDEX bitidx ON bittmp USING GIST ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM bittmp WHERE a <   '011011000100010111011000110000100';
  count 
diff --git a/contrib/btree_gist/expected/bit_buffering.out b/contrib/btree_gist/expected/bit_buffering.out
new file mode 100644
index 00000000000..7f39fd05c2c
--- /dev/null
+++ b/contrib/btree_gist/expected/bit_buffering.out
@@ -0,0 +1,46 @@
+-- bit check with buffer index builds
+DROP TABLE IF EXISTS bittmp;
+CREATE TABLE bittmp (a bit(33));
+\copy bittmp from 'data/bit.data'
+CREATE INDEX bitidx ON bittmp USING GIST ( a ) WITH(buffering=on);
+SET enable_seqscan=off;
+SELECT count(*) FROM bittmp WHERE a <   '011011000100010111011000110000100';
+ count 
+-------
+   249
+(1 row)
+
+SELECT count(*) FROM bittmp WHERE a <=  '011011000100010111011000110000100';
+ count 
+-------
+   250
+(1 row)
+
+SELECT count(*) FROM bittmp WHERE a  =  '011011000100010111011000110000100';
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM bittmp WHERE a >=  '011011000100010111011000110000100';
+ count 
+-------
+   351
+(1 row)
+
+SELECT count(*) FROM bittmp WHERE a >   '011011000100010111011000110000100';
+ count 
+-------
+   350
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT a FROM bittmp WHERE a BETWEEN '1000000' and '1000001';
+                             QUERY PLAN                              
+---------------------------------------------------------------------
+ Index Only Scan using bitidx on bittmp
+   Index Cond: ((a >= '1000000'::"bit") AND (a <= '1000001'::"bit"))
+(2 rows)
+
diff --git a/contrib/btree_gist/expected/bool.out b/contrib/btree_gist/expected/bool.out
index 29390f079c0..4dfcc7e945b 100644
--- a/contrib/btree_gist/expected/bool.out
+++ b/contrib/btree_gist/expected/bool.out
@@ -33,6 +33,7 @@ SELECT count(*) FROM booltmp WHERE a >  true;
 (1 row)
 
 CREATE INDEX boolidx ON booltmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM booltmp WHERE a <  true;
  count 
diff --git a/contrib/btree_gist/expected/bool_buffering.out b/contrib/btree_gist/expected/bool_buffering.out
new file mode 100644
index 00000000000..e243a43728d
--- /dev/null
+++ b/contrib/btree_gist/expected/bool_buffering.out
@@ -0,0 +1,66 @@
+-- bool check
+DROP TABLE IF EXISTS booltmp;
+CREATE TABLE booltmp (a bool);
+INSERT INTO booltmp VALUES (false), (true);
+CREATE INDEX boolidx ON booltmp USING gist ( a ) WITH(buffering=on);
+SET enable_seqscan=off;
+SELECT count(*) FROM booltmp WHERE a <  true;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM booltmp WHERE a <= true;
+ count 
+-------
+     2
+(1 row)
+
+SELECT count(*) FROM booltmp WHERE a  = true;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM booltmp WHERE a >= true;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM booltmp WHERE a >  true;
+ count 
+-------
+     0
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM booltmp WHERE a;
+                QUERY PLAN                
+------------------------------------------
+ Index Only Scan using boolidx on booltmp
+   Index Cond: (a = true)
+(2 rows)
+
+SELECT * FROM booltmp WHERE a;
+ a 
+---
+ t
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM booltmp WHERE NOT a;
+                QUERY PLAN                
+------------------------------------------
+ Index Only Scan using boolidx on booltmp
+   Index Cond: (a = false)
+(2 rows)
+
+SELECT * FROM booltmp WHERE NOT a;
+ a 
+---
+ f
+(1 row)
+
diff --git a/contrib/btree_gist/expected/bytea.out b/contrib/btree_gist/expected/bytea.out
index b9efa73c085..8d65a005921 100644
--- a/contrib/btree_gist/expected/bytea.out
+++ b/contrib/btree_gist/expected/bytea.out
@@ -34,6 +34,7 @@ SELECT count(*) FROM byteatmp WHERE a >   '31b0';
 (1 row)
 
 CREATE INDEX byteaidx ON byteatmp USING GIST ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM byteatmp WHERE a <   '31b0'::bytea;
  count 
diff --git a/contrib/btree_gist/expected/bytea_buffering.out b/contrib/btree_gist/expected/bytea_buffering.out
new file mode 100644
index 00000000000..dc2730b91e3
--- /dev/null
+++ b/contrib/btree_gist/expected/bytea_buffering.out
@@ -0,0 +1,60 @@
+-- bytea check
+DROP TABLE IF EXISTS byteatmp;
+CREATE TABLE byteatmp (a bytea);
+\copy byteatmp from 'data/text.data'
+\copy byteatmp from 'data/char.data'
+CREATE INDEX byteaidx ON byteatmp USING GIST ( a ) WITH(buffering=on);
+SET enable_seqscan=off;
+SELECT count(*) FROM byteatmp WHERE a <   '31b0'::bytea;
+ count 
+-------
+   588
+(1 row)
+
+SELECT count(*) FROM byteatmp WHERE a <=  '31b0'::bytea;
+ count 
+-------
+   589
+(1 row)
+
+SELECT count(*) FROM byteatmp WHERE a  =  '31b0'::bytea;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM byteatmp WHERE a >=  '31b0'::bytea;
+ count 
+-------
+   401
+(1 row)
+
+SELECT count(*) FROM byteatmp WHERE a >   '31b0'::bytea;
+ count 
+-------
+   400
+(1 row)
+
+SELECT count(*) FROM byteatmp WHERE a  =  '2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809'::bytea;
+ count 
+-------
+     1
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT a FROM byteatmp where a > 'ffa'::bytea;
+                 QUERY PLAN                 
+--------------------------------------------
+ Index Only Scan using byteaidx on byteatmp
+   Index Cond: (a > '\x666661'::bytea)
+(2 rows)
+
+SELECT a FROM byteatmp where a > 'ffa'::bytea;
+               a                
+--------------------------------
+ \x666662656532373363376262
+ \x6666626663313331336339633835
+(2 rows)
+
diff --git a/contrib/btree_gist/expected/cash.out b/contrib/btree_gist/expected/cash.out
index 7fbc7355929..5afccfead0a 100644
--- a/contrib/btree_gist/expected/cash.out
+++ b/contrib/btree_gist/expected/cash.out
@@ -41,6 +41,7 @@ SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3;
 (3 rows)
 
 CREATE INDEX moneyidx ON moneytmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM moneytmp WHERE a <  '22649.64'::money;
  count 
diff --git a/contrib/btree_gist/expected/cash_buffering.out b/contrib/btree_gist/expected/cash_buffering.out
new file mode 100644
index 00000000000..2ed8a80dd0c
--- /dev/null
+++ b/contrib/btree_gist/expected/cash_buffering.out
@@ -0,0 +1,53 @@
+-- money check
+DROP TABLE IF EXISTS moneytmp;
+CREATE TABLE moneytmp (a money);
+\copy moneytmp from 'data/cash.data'
+CREATE INDEX moneyidx ON moneytmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM moneytmp WHERE a <  '22649.64'::money;
+ count 
+-------
+   289
+(1 row)
+
+SELECT count(*) FROM moneytmp WHERE a <= '22649.64'::money;
+ count 
+-------
+   290
+(1 row)
+
+SELECT count(*) FROM moneytmp WHERE a  = '22649.64'::money;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM moneytmp WHERE a >= '22649.64'::money;
+ count 
+-------
+   254
+(1 row)
+
+SELECT count(*) FROM moneytmp WHERE a >  '22649.64'::money;
+ count 
+-------
+   253
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Limit
+   ->  Index Only Scan using moneyidx on moneytmp
+         Order By: (a <-> '$21,472.79'::money)
+(3 rows)
+
+SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3;
+     a      | ?column? 
+------------+----------
+ $21,472.79 |    $0.00
+ $21,469.25 |    $3.54
+ $21,915.01 |  $442.22
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/char_buffering.out b/contrib/btree_gist/expected/char_buffering.out
new file mode 100644
index 00000000000..58cd4bbcb52
--- /dev/null
+++ b/contrib/btree_gist/expected/char_buffering.out
@@ -0,0 +1,52 @@
+-- char check
+DROP TABLE IF EXISTS chartmp;
+CREATE TABLE chartmp (a char(32));
+\copy chartmp from 'data/char.data'
+CREATE INDEX charidx ON chartmp USING GIST ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM chartmp WHERE a <   '31b0'::char(32);
+ count 
+-------
+   587
+(1 row)
+
+SELECT count(*) FROM chartmp WHERE a <=  '31b0'::char(32);
+ count 
+-------
+   588
+(1 row)
+
+SELECT count(*) FROM chartmp WHERE a  =  '31b0'::char(32);
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM chartmp WHERE a >=  '31b0'::char(32);
+ count 
+-------
+   401
+(1 row)
+
+SELECT count(*) FROM chartmp WHERE a >   '31b0'::char(32);
+ count 
+-------
+   400
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM chartmp WHERE a BETWEEN '31a' AND '31c';
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Index Only Scan using charidx on chartmp
+   Index Cond: ((a >= '31a'::bpchar) AND (a <= '31c'::bpchar))
+(2 rows)
+
+SELECT * FROM chartmp WHERE a BETWEEN '31a' AND '31c';
+                a                 
+----------------------------------
+ 31b0                            
+(1 row)
+
diff --git a/contrib/btree_gist/expected/char_buffering_1.out b/contrib/btree_gist/expected/char_buffering_1.out
new file mode 100644
index 00000000000..4cde287d54f
--- /dev/null
+++ b/contrib/btree_gist/expected/char_buffering_1.out
@@ -0,0 +1,52 @@
+-- char check
+DROP TABLE IF EXISTS chartmp;
+CREATE TABLE chartmp (a char(32));
+\copy chartmp from 'data/char.data'
+CREATE INDEX charidx ON chartmp USING GIST ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM chartmp WHERE a <   '31b0'::char(32);
+ count 
+-------
+   773
+(1 row)
+
+SELECT count(*) FROM chartmp WHERE a <=  '31b0'::char(32);
+ count 
+-------
+   774
+(1 row)
+
+SELECT count(*) FROM chartmp WHERE a  =  '31b0'::char(32);
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM chartmp WHERE a >=  '31b0'::char(32);
+ count 
+-------
+   215
+(1 row)
+
+SELECT count(*) FROM chartmp WHERE a >   '31b0'::char(32);
+ count 
+-------
+   214
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM chartmp WHERE a BETWEEN '31a' AND '31c';
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Index Only Scan using charidx on chartmp
+   Index Cond: ((a >= '31a'::bpchar) AND (a <= '31c'::bpchar))
+(2 rows)
+
+SELECT * FROM chartmp WHERE a BETWEEN '31a' AND '31c';
+                a                 
+----------------------------------
+ 31b0                            
+(1 row)
+
diff --git a/contrib/btree_gist/expected/cidr_buffering.out b/contrib/btree_gist/expected/cidr_buffering.out
new file mode 100644
index 00000000000..bf5f3e08306
--- /dev/null
+++ b/contrib/btree_gist/expected/cidr_buffering.out
@@ -0,0 +1,36 @@
+-- cidr check
+DROP TABLE IF EXISTS cidrtmp;
+CREATE TABLE cidrtmp AS
+  SELECT cidr(a) AS a FROM inettmp ;
+CREATE INDEX cidridx ON cidrtmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM cidrtmp WHERE a <  '121.111.63.82'::cidr;
+ count 
+-------
+   290
+(1 row)
+
+SELECT count(*) FROM cidrtmp WHERE a <= '121.111.63.82'::cidr;
+ count 
+-------
+   291
+(1 row)
+
+SELECT count(*) FROM cidrtmp WHERE a  = '121.111.63.82'::cidr;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM cidrtmp WHERE a >= '121.111.63.82'::cidr;
+ count 
+-------
+   310
+(1 row)
+
+SELECT count(*) FROM cidrtmp WHERE a >  '121.111.63.82'::cidr;
+ count 
+-------
+   309
+(1 row)
+
diff --git a/contrib/btree_gist/expected/cleanup.out b/contrib/btree_gist/expected/cleanup.out
new file mode 100644
index 00000000000..119395c1d00
--- /dev/null
+++ b/contrib/btree_gist/expected/cleanup.out
@@ -0,0 +1,6 @@
+SELECT injection_points_detach('btree-gist-sorted-build');
+ injection_points_detach 
+-------------------------
+ 
+(1 row)
+
diff --git a/contrib/btree_gist/expected/date.out b/contrib/btree_gist/expected/date.out
index 5db864bb82c..8ada19be3c3 100644
--- a/contrib/btree_gist/expected/date.out
+++ b/contrib/btree_gist/expected/date.out
@@ -41,6 +41,7 @@ SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3;
 (3 rows)
 
 CREATE INDEX dateidx ON datetmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM datetmp WHERE a <  '2001-02-13'::date;
  count 
diff --git a/contrib/btree_gist/expected/date_buffering.out b/contrib/btree_gist/expected/date_buffering.out
new file mode 100644
index 00000000000..52f61ea10fd
--- /dev/null
+++ b/contrib/btree_gist/expected/date_buffering.out
@@ -0,0 +1,53 @@
+-- date check
+DROP TABLE IF EXISTS datetmp;
+CREATE TABLE datetmp (a date);
+\copy datetmp from 'data/date.data'
+CREATE INDEX dateidx ON datetmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM datetmp WHERE a <  '2001-02-13'::date;
+ count 
+-------
+   230
+(1 row)
+
+SELECT count(*) FROM datetmp WHERE a <= '2001-02-13'::date;
+ count 
+-------
+   231
+(1 row)
+
+SELECT count(*) FROM datetmp WHERE a  = '2001-02-13'::date;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM datetmp WHERE a >= '2001-02-13'::date;
+ count 
+-------
+   314
+(1 row)
+
+SELECT count(*) FROM datetmp WHERE a >  '2001-02-13'::date;
+ count 
+-------
+   313
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3;
+                   QUERY PLAN                   
+------------------------------------------------
+ Limit
+   ->  Index Only Scan using dateidx on datetmp
+         Order By: (a <-> '02-13-2001'::date)
+(3 rows)
+
+SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3;
+     a      | ?column? 
+------------+----------
+ 02-13-2001 |        0
+ 02-11-2001 |        2
+ 03-24-2001 |       39
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/enum.out b/contrib/btree_gist/expected/enum.out
index c4b769dd4b7..45fa035475a 100644
--- a/contrib/btree_gist/expected/enum.out
+++ b/contrib/btree_gist/expected/enum.out
@@ -47,6 +47,7 @@ SELECT count(*) FROM enumtmp WHERE a >  'g'::rainbow;
 (1 row)
 
 CREATE INDEX enumidx ON enumtmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM enumtmp WHERE a <  'g'::rainbow;
  count 
diff --git a/contrib/btree_gist/expected/enum_buffering.out b/contrib/btree_gist/expected/enum_buffering.out
new file mode 100644
index 00000000000..203d60b41b1
--- /dev/null
+++ b/contrib/btree_gist/expected/enum_buffering.out
@@ -0,0 +1,47 @@
+-- enum check
+DROP TABLE IF EXISTS enumtmp;
+CREATE TABLE enumtmp (a rainbow);
+\copy enumtmp from 'data/enum.data'
+CREATE INDEX enumidx ON enumtmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM enumtmp WHERE a <  'g'::rainbow;
+ count 
+-------
+   227
+(1 row)
+
+SELECT count(*) FROM enumtmp WHERE a <= 'g'::rainbow;
+ count 
+-------
+   302
+(1 row)
+
+SELECT count(*) FROM enumtmp WHERE a  = 'g'::rainbow;
+ count 
+-------
+    75
+(1 row)
+
+SELECT count(*) FROM enumtmp WHERE a >= 'g'::rainbow;
+ count 
+-------
+   305
+(1 row)
+
+SELECT count(*) FROM enumtmp WHERE a >  'g'::rainbow;
+ count 
+-------
+   230
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM enumtmp WHERE a >= 'g'::rainbow;
+                  QUERY PLAN                   
+-----------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on enumtmp
+         Recheck Cond: (a >= 'g'::rainbow)
+         ->  Bitmap Index Scan on enumidx
+               Index Cond: (a >= 'g'::rainbow)
+(5 rows)
+
diff --git a/contrib/btree_gist/expected/float4.out b/contrib/btree_gist/expected/float4.out
index dfe732049e6..e74e795c396 100644
--- a/contrib/btree_gist/expected/float4.out
+++ b/contrib/btree_gist/expected/float4.out
@@ -41,6 +41,7 @@ SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
 (3 rows)
 
 CREATE INDEX float4idx ON float4tmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM float4tmp WHERE a <  -179.0::float4;
  count 
diff --git a/contrib/btree_gist/expected/float4_buffering.out b/contrib/btree_gist/expected/float4_buffering.out
new file mode 100644
index 00000000000..f878e707263
--- /dev/null
+++ b/contrib/btree_gist/expected/float4_buffering.out
@@ -0,0 +1,53 @@
+-- float4 check
+DROP TABLE IF EXISTS float4tmp;
+CREATE TABLE float4tmp (a float4);
+\copy float4tmp from 'data/float4.data'
+CREATE INDEX float4idx ON float4tmp USING gist ( a ) WITH (buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM float4tmp WHERE a <  -179.0::float4;
+ count 
+-------
+   244
+(1 row)
+
+SELECT count(*) FROM float4tmp WHERE a <= -179.0::float4;
+ count 
+-------
+   245
+(1 row)
+
+SELECT count(*) FROM float4tmp WHERE a  = -179.0::float4;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM float4tmp WHERE a >= -179.0::float4;
+ count 
+-------
+   303
+(1 row)
+
+SELECT count(*) FROM float4tmp WHERE a >  -179.0::float4;
+ count 
+-------
+   302
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
+                     QUERY PLAN                     
+----------------------------------------------------
+ Limit
+   ->  Index Only Scan using float4idx on float4tmp
+         Order By: (a <-> '-179'::real)
+(3 rows)
+
+SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
+     a      | ?column?  
+------------+-----------
+       -179 |         0
+ -189.02386 | 10.023865
+ -158.17741 | 20.822586
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/float8.out b/contrib/btree_gist/expected/float8.out
index ebd0ef3d689..eb872a4a6dd 100644
--- a/contrib/btree_gist/expected/float8.out
+++ b/contrib/btree_gist/expected/float8.out
@@ -41,6 +41,7 @@ SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
 (3 rows)
 
 CREATE INDEX float8idx ON float8tmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM float8tmp WHERE a <  -1890.0::float8;
  count 
diff --git a/contrib/btree_gist/expected/float8_buffering.out b/contrib/btree_gist/expected/float8_buffering.out
new file mode 100644
index 00000000000..81a4d484023
--- /dev/null
+++ b/contrib/btree_gist/expected/float8_buffering.out
@@ -0,0 +1,53 @@
+-- float8 check
+DROP TABLE IF EXISTS float8tmp;
+CREATE TABLE float8tmp (a float8);
+\copy float8tmp from 'data/float8.data'
+CREATE INDEX float8idx ON float8tmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM float8tmp WHERE a <  -1890.0::float8;
+ count 
+-------
+   237
+(1 row)
+
+SELECT count(*) FROM float8tmp WHERE a <= -1890.0::float8;
+ count 
+-------
+   238
+(1 row)
+
+SELECT count(*) FROM float8tmp WHERE a  = -1890.0::float8;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM float8tmp WHERE a >= -1890.0::float8;
+ count 
+-------
+   307
+(1 row)
+
+SELECT count(*) FROM float8tmp WHERE a >  -1890.0::float8;
+ count 
+-------
+   306
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Limit
+   ->  Index Only Scan using float8idx on float8tmp
+         Order By: (a <-> '-1890'::double precision)
+(3 rows)
+
+SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
+      a       |      ?column?      
+--------------+--------------------
+        -1890 |                  0
+ -2003.634512 | 113.63451200000009
+  -1769.73634 | 120.26366000000007
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/inet.out b/contrib/btree_gist/expected/inet.out
index f15f1435f0a..58be5b6093a 100644
--- a/contrib/btree_gist/expected/inet.out
+++ b/contrib/btree_gist/expected/inet.out
@@ -33,6 +33,7 @@ SELECT count(*) FROM inettmp WHERE a >  '89.225.196.191';
 (1 row)
 
 CREATE INDEX inetidx ON inettmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM inettmp WHERE a <  '89.225.196.191'::inet;
  count 
diff --git a/contrib/btree_gist/expected/inet_buffering.out b/contrib/btree_gist/expected/inet_buffering.out
new file mode 100644
index 00000000000..a6ad06ce607
--- /dev/null
+++ b/contrib/btree_gist/expected/inet_buffering.out
@@ -0,0 +1,71 @@
+-- inet check
+DROP TABLE IF EXISTS inettmp;
+CREATE TABLE inettmp (a inet);
+\copy inettmp from 'data/inet.data'
+CREATE INDEX inetidx ON inettmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM inettmp WHERE a <  '89.225.196.191'::inet;
+ count 
+-------
+   213
+(1 row)
+
+SELECT count(*) FROM inettmp WHERE a <= '89.225.196.191'::inet;
+ count 
+-------
+   214
+(1 row)
+
+SELECT count(*) FROM inettmp WHERE a  = '89.225.196.191'::inet;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM inettmp WHERE a >= '89.225.196.191'::inet;
+ count 
+-------
+   387
+(1 row)
+
+SELECT count(*) FROM inettmp WHERE a >  '89.225.196.191'::inet;
+ count 
+-------
+   386
+(1 row)
+
+VACUUM ANALYZE inettmp;
+-- gist_inet_ops lacks a fetch function, so this should not be index-only scan
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM inettmp WHERE a  = '89.225.196.191'::inet;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Aggregate
+   ->  Index Scan using inetidx on inettmp
+         Index Cond: (a = '89.225.196.191'::inet)
+(3 rows)
+
+SELECT count(*) FROM inettmp WHERE a  = '89.225.196.191'::inet;
+ count 
+-------
+     1
+(1 row)
+
+DROP INDEX inetidx;
+CREATE INDEX ON inettmp USING gist (a gist_inet_ops, a inet_ops);
+-- this can be an index-only scan, as long as the planner uses the right column
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM inettmp WHERE a  = '89.225.196.191'::inet;
+                       QUERY PLAN                        
+---------------------------------------------------------
+ Aggregate
+   ->  Index Only Scan using inettmp_a_a1_idx on inettmp
+         Index Cond: (a = '89.225.196.191'::inet)
+(3 rows)
+
+SELECT count(*) FROM inettmp WHERE a  = '89.225.196.191'::inet;
+ count 
+-------
+     1
+(1 row)
+
diff --git a/contrib/btree_gist/expected/init.out b/contrib/btree_gist/expected/init.out
index ce4559d8b03..3430e9af9c5 100644
--- a/contrib/btree_gist/expected/init.out
+++ b/contrib/btree_gist/expected/init.out
@@ -1,3 +1,10 @@
+CREATE EXTENSION injection_points;
+SELECT injection_points_attach('btree-gist-sorted-build', 'notice');
+ injection_points_attach 
+-------------------------
+ 
+(1 row)
+
 CREATE EXTENSION btree_gist;
 -- Check whether any of our opclasses fail amvalidate
 SELECT amname, opcname
diff --git a/contrib/btree_gist/expected/int2.out b/contrib/btree_gist/expected/int2.out
index 50a332939bd..97ae0a55670 100644
--- a/contrib/btree_gist/expected/int2.out
+++ b/contrib/btree_gist/expected/int2.out
@@ -41,6 +41,7 @@ SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3;
 (3 rows)
 
 CREATE INDEX int2idx ON int2tmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM int2tmp WHERE a <  237::int2;
  count 
diff --git a/contrib/btree_gist/expected/int2_buffering.out b/contrib/btree_gist/expected/int2_buffering.out
new file mode 100644
index 00000000000..d6a34e11e36
--- /dev/null
+++ b/contrib/btree_gist/expected/int2_buffering.out
@@ -0,0 +1,53 @@
+-- int2 check
+DROP TABLE IF EXISTS int2tmp;
+CREATE TABLE int2tmp (a int2);
+\copy int2tmp from 'data/int2.data'
+CREATE INDEX int2idx ON int2tmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM int2tmp WHERE a <  237::int2;
+ count 
+-------
+   297
+(1 row)
+
+SELECT count(*) FROM int2tmp WHERE a <= 237::int2;
+ count 
+-------
+   298
+(1 row)
+
+SELECT count(*) FROM int2tmp WHERE a  = 237::int2;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM int2tmp WHERE a >= 237::int2;
+ count 
+-------
+   249
+(1 row)
+
+SELECT count(*) FROM int2tmp WHERE a >  237::int2;
+ count 
+-------
+   248
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3;
+                   QUERY PLAN                   
+------------------------------------------------
+ Limit
+   ->  Index Only Scan using int2idx on int2tmp
+         Order By: (a <-> '237'::smallint)
+(3 rows)
+
+SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3;
+  a  | ?column? 
+-----+----------
+ 237 |        0
+ 232 |        5
+ 228 |        9
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/int4.out b/contrib/btree_gist/expected/int4.out
index 6bbdc7c3f4b..af2a94583fb 100644
--- a/contrib/btree_gist/expected/int4.out
+++ b/contrib/btree_gist/expected/int4.out
@@ -41,6 +41,7 @@ SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3;
 (3 rows)
 
 CREATE INDEX int4idx ON int4tmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM int4tmp WHERE a <  237::int4;
  count 
diff --git a/contrib/btree_gist/expected/int4_buffering.out b/contrib/btree_gist/expected/int4_buffering.out
new file mode 100644
index 00000000000..a5b8fda2d2f
--- /dev/null
+++ b/contrib/btree_gist/expected/int4_buffering.out
@@ -0,0 +1,53 @@
+-- int4 check
+DROP TABLE IF EXISTS int4tmp;
+CREATE TABLE int4tmp (a int4);
+\copy int4tmp from 'data/int2.data'
+CREATE INDEX int4idx ON int4tmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM int4tmp WHERE a <  237::int4;
+ count 
+-------
+   297
+(1 row)
+
+SELECT count(*) FROM int4tmp WHERE a <= 237::int4;
+ count 
+-------
+   298
+(1 row)
+
+SELECT count(*) FROM int4tmp WHERE a  = 237::int4;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM int4tmp WHERE a >= 237::int4;
+ count 
+-------
+   249
+(1 row)
+
+SELECT count(*) FROM int4tmp WHERE a >  237::int4;
+ count 
+-------
+   248
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3;
+                   QUERY PLAN                   
+------------------------------------------------
+ Limit
+   ->  Index Only Scan using int4idx on int4tmp
+         Order By: (a <-> 237)
+(3 rows)
+
+SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3;
+  a  | ?column? 
+-----+----------
+ 237 |        0
+ 232 |        5
+ 228 |        9
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/int8.out b/contrib/btree_gist/expected/int8.out
index eff77c26b5a..73cfa84bfc7 100644
--- a/contrib/btree_gist/expected/int8.out
+++ b/contrib/btree_gist/expected/int8.out
@@ -41,6 +41,7 @@ SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841'
 (3 rows)
 
 CREATE INDEX int8idx ON int8tmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM int8tmp WHERE a <  464571291354841::int8;
  count 
diff --git a/contrib/btree_gist/expected/int8_buffering.out b/contrib/btree_gist/expected/int8_buffering.out
new file mode 100644
index 00000000000..c030a549c6e
--- /dev/null
+++ b/contrib/btree_gist/expected/int8_buffering.out
@@ -0,0 +1,53 @@
+-- int8 check
+DROP TABLE IF EXISTS int8tmp;
+CREATE TABLE int8tmp (a int8);
+\copy int8tmp from 'data/int8.data'
+CREATE INDEX int8idx ON int8tmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM int8tmp WHERE a <  464571291354841::int8;
+ count 
+-------
+   276
+(1 row)
+
+SELECT count(*) FROM int8tmp WHERE a <= 464571291354841::int8;
+ count 
+-------
+   277
+(1 row)
+
+SELECT count(*) FROM int8tmp WHERE a  = 464571291354841::int8;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM int8tmp WHERE a >= 464571291354841::int8;
+ count 
+-------
+   271
+(1 row)
+
+SELECT count(*) FROM int8tmp WHERE a >  464571291354841::int8;
+ count 
+-------
+   270
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3;
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Limit
+   ->  Index Only Scan using int8idx on int8tmp
+         Order By: (a <-> '464571291354841'::bigint)
+(3 rows)
+
+SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3;
+        a        |    ?column?    
+-----------------+----------------
+ 464571291354841 |              0
+ 457257666629329 |  7313624725512
+ 478227196042750 | 13655904687909
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/interval.out b/contrib/btree_gist/expected/interval.out
index 4c3d494e4a6..a5f6335c62f 100644
--- a/contrib/btree_gist/expected/interval.out
+++ b/contrib/btree_gist/expected/interval.out
@@ -41,6 +41,7 @@ SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21
 (3 rows)
 
 CREATE INDEX intervalidx ON intervaltmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM intervaltmp WHERE a <  '199 days 21:21:23'::interval;
  count 
diff --git a/contrib/btree_gist/expected/interval_buffering.out b/contrib/btree_gist/expected/interval_buffering.out
new file mode 100644
index 00000000000..863afad5039
--- /dev/null
+++ b/contrib/btree_gist/expected/interval_buffering.out
@@ -0,0 +1,71 @@
+-- interval check
+DROP TABLE IF EXISTS intervaltmp;
+CREATE TABLE intervaltmp (a interval);
+\copy intervaltmp from 'data/interval.data'
+CREATE INDEX intervalidx ON intervaltmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM intervaltmp WHERE a <  '199 days 21:21:23'::interval;
+ count 
+-------
+   329
+(1 row)
+
+SELECT count(*) FROM intervaltmp WHERE a <= '199 days 21:21:23'::interval;
+ count 
+-------
+   330
+(1 row)
+
+SELECT count(*) FROM intervaltmp WHERE a  = '199 days 21:21:23'::interval;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM intervaltmp WHERE a >= '199 days 21:21:23'::interval;
+ count 
+-------
+   271
+(1 row)
+
+SELECT count(*) FROM intervaltmp WHERE a >  '199 days 21:21:23'::interval;
+ count 
+-------
+   270
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3;
+                                QUERY PLAN                                 
+---------------------------------------------------------------------------
+ Limit
+   ->  Index Only Scan using intervalidx on intervaltmp
+         Order By: (a <-> '@ 199 days 21 hours 21 mins 23 secs'::interval)
+(3 rows)
+
+SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3;
+                  a                  |               ?column?               
+-------------------------------------+--------------------------------------
+ @ 199 days 21 hours 21 mins 23 secs | @ 0
+ @ 183 days 6 hours 52 mins 48 secs  | @ 16 days 14 hours 28 mins 35 secs
+ @ 220 days 19 hours 5 mins 42 secs  | @ 21 days -2 hours -15 mins -41 secs
+(3 rows)
+
+SET enable_indexonlyscan=off;
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3;
+                                QUERY PLAN                                 
+---------------------------------------------------------------------------
+ Limit
+   ->  Index Scan using intervalidx on intervaltmp
+         Order By: (a <-> '@ 199 days 21 hours 21 mins 23 secs'::interval)
+(3 rows)
+
+SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3;
+                  a                  |               ?column?               
+-------------------------------------+--------------------------------------
+ @ 199 days 21 hours 21 mins 23 secs | @ 0
+ @ 183 days 6 hours 52 mins 48 secs  | @ 16 days 14 hours 28 mins 35 secs
+ @ 220 days 19 hours 5 mins 42 secs  | @ 21 days -2 hours -15 mins -41 secs
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/macaddr.out b/contrib/btree_gist/expected/macaddr.out
index c0a4c6287f3..ba1324a790a 100644
--- a/contrib/btree_gist/expected/macaddr.out
+++ b/contrib/btree_gist/expected/macaddr.out
@@ -33,6 +33,7 @@ SELECT count(*) FROM macaddrtmp WHERE a >  '22:00:5c:e5:9b:0d';
 (1 row)
 
 CREATE INDEX macaddridx ON macaddrtmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM macaddrtmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr;
  count 
diff --git a/contrib/btree_gist/expected/macaddr8.out b/contrib/btree_gist/expected/macaddr8.out
index e5ec6a5deab..4126febe990 100644
--- a/contrib/btree_gist/expected/macaddr8.out
+++ b/contrib/btree_gist/expected/macaddr8.out
@@ -33,6 +33,7 @@ SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d';
 (1 row)
 
 CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
  count 
diff --git a/contrib/btree_gist/expected/macaddr8_buffering.out b/contrib/btree_gist/expected/macaddr8_buffering.out
new file mode 100644
index 00000000000..189888dfd86
--- /dev/null
+++ b/contrib/btree_gist/expected/macaddr8_buffering.out
@@ -0,0 +1,59 @@
+-- macaddr check
+DROP TABLE IF EXISTS macaddr8tmp;
+CREATE TABLE macaddr8tmp (a macaddr8);
+\copy macaddr8tmp from 'data/macaddr.data'
+CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+    56
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+    60
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+     4
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+   544
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+   540
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+                       QUERY PLAN                        
+---------------------------------------------------------
+ Index Only Scan using macaddr8idx on macaddr8tmp
+   Index Cond: (a < '02:03:04:ff:fe:05:06:07'::macaddr8)
+(2 rows)
+
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+            a            
+-------------------------
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+(8 rows)
+
diff --git a/contrib/btree_gist/expected/macaddr_buffering.out b/contrib/btree_gist/expected/macaddr_buffering.out
new file mode 100644
index 00000000000..8f168b2a895
--- /dev/null
+++ b/contrib/btree_gist/expected/macaddr_buffering.out
@@ -0,0 +1,59 @@
+-- macaddr check
+DROP TABLE IF EXISTS macaddrtmp;
+CREATE TABLE macaddrtmp (a macaddr);
+\copy macaddrtmp from 'data/macaddr.data'
+CREATE INDEX macaddridx ON macaddrtmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM macaddrtmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr;
+ count 
+-------
+    56
+(1 row)
+
+SELECT count(*) FROM macaddrtmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr;
+ count 
+-------
+    60
+(1 row)
+
+SELECT count(*) FROM macaddrtmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr;
+ count 
+-------
+     4
+(1 row)
+
+SELECT count(*) FROM macaddrtmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr;
+ count 
+-------
+   544
+(1 row)
+
+SELECT count(*) FROM macaddrtmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr;
+ count 
+-------
+   540
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddrtmp WHERE a < '02:03:04:05:06:07'::macaddr;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Index Only Scan using macaddridx on macaddrtmp
+   Index Cond: (a < '02:03:04:05:06:07'::macaddr)
+(2 rows)
+
+SELECT * FROM macaddrtmp WHERE a < '02:03:04:05:06:07'::macaddr;
+         a         
+-------------------
+ 01:02:37:05:4f:36
+ 01:02:37:05:4f:36
+ 01:02:37:05:4f:36
+ 01:02:37:05:4f:36
+ 01:43:b5:79:eb:0f
+ 01:43:b5:79:eb:0f
+ 01:43:b5:79:eb:0f
+ 01:43:b5:79:eb:0f
+(8 rows)
+
diff --git a/contrib/btree_gist/expected/not_equal.out b/contrib/btree_gist/expected/not_equal.out
index 85b1e868a87..17befb5b880 100644
--- a/contrib/btree_gist/expected/not_equal.out
+++ b/contrib/btree_gist/expected/not_equal.out
@@ -5,6 +5,8 @@ CREATE TABLE test_ne (
    b  NUMERIC
 );
 CREATE INDEX test_ne_idx ON test_ne USING gist (a, b);
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 INSERT INTO test_ne SELECT '2009-01-01', 10.7 FROM generate_series(1,1000);
 INSERT INTO test_ne VALUES('2007-02-03', -91.3);
 INSERT INTO test_ne VALUES('2011-09-01', 43.7);
@@ -33,6 +35,8 @@ CREATE TABLE zoo (
    animal TEXT,
    EXCLUDE USING gist (cage WITH =, animal WITH <>)
 );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 INSERT INTO zoo VALUES(123, 'zebra');
 INSERT INTO zoo VALUES(123, 'zebra');
 INSERT INTO zoo VALUES(123, 'lion');
diff --git a/contrib/btree_gist/expected/not_equal_buffering.out b/contrib/btree_gist/expected/not_equal_buffering.out
new file mode 100644
index 00000000000..b3c7f8e680b
--- /dev/null
+++ b/contrib/btree_gist/expected/not_equal_buffering.out
@@ -0,0 +1,43 @@
+SET enable_seqscan to false;
+-- test search for "not equals"
+DROP TABLE IF EXISTS test_ne;
+CREATE TABLE test_ne (
+   a  TIMESTAMP,
+   b  NUMERIC
+);
+CREATE INDEX test_ne_idx ON test_ne USING gist (a, b) WITH(buffering = on);
+INSERT INTO test_ne SELECT '2009-01-01', 10.7 FROM generate_series(1,1000);
+INSERT INTO test_ne VALUES('2007-02-03', -91.3);
+INSERT INTO test_ne VALUES('2011-09-01', 43.7);
+INSERT INTO test_ne SELECT '2009-01-01', 10.7 FROM generate_series(1,1000);
+SET enable_indexscan to false;
+EXPLAIN (COSTS OFF) SELECT * FROM test_ne WHERE a <> '2009-01-01' AND b <> 10.7;
+                                              QUERY PLAN                                              
+------------------------------------------------------------------------------------------------------
+ Bitmap Heap Scan on test_ne
+   Recheck Cond: ((a <> 'Thu Jan 01 00:00:00 2009'::timestamp without time zone) AND (b <> 10.7))
+   ->  Bitmap Index Scan on test_ne_idx
+         Index Cond: ((a <> 'Thu Jan 01 00:00:00 2009'::timestamp without time zone) AND (b <> 10.7))
+(4 rows)
+
+SELECT * FROM test_ne WHERE a <> '2009-01-01' AND b <> 10.7;
+            a             |   b   
+--------------------------+-------
+ Sat Feb 03 00:00:00 2007 | -91.3
+ Thu Sep 01 00:00:00 2011 |  43.7
+(2 rows)
+
+RESET enable_indexscan;
+-- test search for "not equals" using an exclusion constraint
+DROP TABLE IF EXISTS zoo;
+CREATE TABLE zoo (
+   cage   INTEGER,
+   animal TEXT,
+   EXCLUDE USING gist (cage WITH =, animal WITH <>) WITH(buffering = on)
+);
+INSERT INTO zoo VALUES(123, 'zebra');
+INSERT INTO zoo VALUES(123, 'zebra');
+INSERT INTO zoo VALUES(123, 'lion');
+ERROR:  conflicting key value violates exclusion constraint "zoo_cage_animal_excl"
+DETAIL:  Key (cage, animal)=(123, lion) conflicts with existing key (cage, animal)=(123, zebra).
+INSERT INTO zoo VALUES(124, 'lion');
diff --git a/contrib/btree_gist/expected/numeric.out b/contrib/btree_gist/expected/numeric.out
index ae839b8ec83..b4f991d4213 100644
--- a/contrib/btree_gist/expected/numeric.out
+++ b/contrib/btree_gist/expected/numeric.out
@@ -95,6 +95,7 @@ SELECT count(*) FROM numerictmp WHERE a >  0 ;
 (1 row)
 
 CREATE INDEX numericidx ON numerictmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM numerictmp WHERE a <  -1890.0;
  count 
diff --git a/contrib/btree_gist/expected/numeric_buffering.out b/contrib/btree_gist/expected/numeric_buffering.out
new file mode 100644
index 00000000000..e2ad4ae0d84
--- /dev/null
+++ b/contrib/btree_gist/expected/numeric_buffering.out
@@ -0,0 +1,117 @@
+-- numeric check
+DROP TABLE IF EXISTS numerictmp;
+CREATE TABLE numerictmp (a numeric);
+\copy numerictmp from 'data/int8.data'
+\copy numerictmp from 'data/numeric.data'
+\copy numerictmp from 'data/float8.data'
+CREATE INDEX numericidx ON numerictmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM numerictmp WHERE a <  -1890.0;
+ count 
+-------
+   505
+(1 row)
+
+SELECT count(*) FROM numerictmp WHERE a <= -1890.0;
+ count 
+-------
+   506
+(1 row)
+
+SELECT count(*) FROM numerictmp WHERE a  = -1890.0;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM numerictmp WHERE a >= -1890.0;
+ count 
+-------
+   597
+(1 row)
+
+SELECT count(*) FROM numerictmp WHERE a >  -1890.0;
+ count 
+-------
+   596
+(1 row)
+
+SELECT count(*) FROM numerictmp WHERE a <  'NaN' ;
+ count 
+-------
+  1100
+(1 row)
+
+SELECT count(*) FROM numerictmp WHERE a <= 'NaN' ;
+ count 
+-------
+  1102
+(1 row)
+
+SELECT count(*) FROM numerictmp WHERE a  = 'NaN' ;
+ count 
+-------
+     2
+(1 row)
+
+SELECT count(*) FROM numerictmp WHERE a >= 'NaN' ;
+ count 
+-------
+     2
+(1 row)
+
+SELECT count(*) FROM numerictmp WHERE a >  'NaN' ;
+ count 
+-------
+     0
+(1 row)
+
+SELECT count(*) FROM numerictmp WHERE a <  0 ;
+ count 
+-------
+   523
+(1 row)
+
+SELECT count(*) FROM numerictmp WHERE a <= 0 ;
+ count 
+-------
+   526
+(1 row)
+
+SELECT count(*) FROM numerictmp WHERE a  = 0 ;
+ count 
+-------
+     3
+(1 row)
+
+SELECT count(*) FROM numerictmp WHERE a >= 0 ;
+ count 
+-------
+   579
+(1 row)
+
+SELECT count(*) FROM numerictmp WHERE a >  0 ;
+ count 
+-------
+   576
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM numerictmp WHERE a BETWEEN 1 AND 300 ORDER BY a;
+                             QUERY PLAN                              
+---------------------------------------------------------------------
+ Sort
+   Sort Key: a
+   ->  Index Only Scan using numericidx on numerictmp
+         Index Cond: ((a >= '1'::numeric) AND (a <= '300'::numeric))
+(4 rows)
+
+SELECT * FROM numerictmp WHERE a BETWEEN 1 AND 300 ORDER BY a;
+     a      
+------------
+ 204.035430
+ 207.400532
+(2 rows)
+
diff --git a/contrib/btree_gist/expected/oid.out b/contrib/btree_gist/expected/oid.out
index 776bbb10267..cac832b904e 100644
--- a/contrib/btree_gist/expected/oid.out
+++ b/contrib/btree_gist/expected/oid.out
@@ -33,6 +33,7 @@ SELECT count(*) FROM oidtmp WHERE oid >  17;
 (1 row)
 
 CREATE INDEX oididx ON oidtmp USING gist ( oid );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM oidtmp WHERE oid <  17;
  count 
diff --git a/contrib/btree_gist/expected/oid_buffering.out b/contrib/btree_gist/expected/oid_buffering.out
new file mode 100644
index 00000000000..2df17ca06bd
--- /dev/null
+++ b/contrib/btree_gist/expected/oid_buffering.out
@@ -0,0 +1,35 @@
+-- oid check
+CREATE TEMPORARY TABLE oidtmp (oid oid);
+INSERT INTO oidtmp SELECT g.i::oid FROM generate_series(1, 1000) g(i);
+CREATE INDEX oididx ON oidtmp USING gist ( oid ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM oidtmp WHERE oid <  17;
+ count 
+-------
+    16
+(1 row)
+
+SELECT count(*) FROM oidtmp WHERE oid <= 17;
+ count 
+-------
+    17
+(1 row)
+
+SELECT count(*) FROM oidtmp WHERE oid  = 17;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM oidtmp WHERE oid >= 17;
+ count 
+-------
+   984
+(1 row)
+
+SELECT count(*) FROM oidtmp WHERE oid >  17;
+ count 
+-------
+   983
+(1 row)
+
diff --git a/contrib/btree_gist/expected/partitions.out b/contrib/btree_gist/expected/partitions.out
index 5bddb915871..dee6bfed971 100644
--- a/contrib/btree_gist/expected/partitions.out
+++ b/contrib/btree_gist/expected/partitions.out
@@ -2,13 +2,19 @@
 -- across a partitioned table.
 -- That code looks at strategy numbers that can differ in regular gist vs btree_gist,
 -- so we want to make sure it works here too.
+--
+-- Note that this also checks sorted builds for btree_gist and rangetypes.
 create table parttmp (
   id int,
   valid_at daterange,
   exclude using gist (id with =, valid_at with &&)
 ) partition by range (id);
 create table parttmp_1_to_10 partition of parttmp for values from (1) to (10);
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 create table parttmp_11_to_20 partition of parttmp for values from (11) to (20);
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 insert into parttmp (id, valid_at) values
   (1, '[2000-01-01, 2000-02-01)'),
   (1, '[2000-02-01, 2000-03-01)'),
diff --git a/contrib/btree_gist/expected/partitions_buffering.out b/contrib/btree_gist/expected/partitions_buffering.out
new file mode 100644
index 00000000000..b501e05e3eb
--- /dev/null
+++ b/contrib/btree_gist/expected/partitions_buffering.out
@@ -0,0 +1,84 @@
+drop table if exists parttmp;
+NOTICE:  table "parttmp" does not exist, skipping
+-- Make sure we can create an exclusion constraint
+-- across a partitioned table.
+-- That code looks at strategy numbers that can differ in regular gist vs btree_gist,
+-- so we want to make sure it works here too.
+create table parttmp (
+  id int,
+  valid_at daterange,
+  exclude using gist (id with =, valid_at with &&) with(buffering = on)
+) partition by range (id);
+create table parttmp_1_to_10 partition of parttmp for values from (1) to (10);
+create table parttmp_11_to_20 partition of parttmp for values from (11) to (20);
+insert into parttmp (id, valid_at) values
+  (1, '[2000-01-01, 2000-02-01)'),
+  (1, '[2000-02-01, 2000-03-01)'),
+  (2, '[2000-01-01, 2000-02-01)'),
+  (11, '[2000-01-01, 2000-02-01)'),
+  (11, '[2000-02-01, 2000-03-01)'),
+  (12, '[2000-01-01, 2000-02-01)');
+select * from parttmp order by id, valid_at;
+ id |        valid_at         
+----+-------------------------
+  1 | [01-01-2000,02-01-2000)
+  1 | [02-01-2000,03-01-2000)
+  2 | [01-01-2000,02-01-2000)
+ 11 | [01-01-2000,02-01-2000)
+ 11 | [02-01-2000,03-01-2000)
+ 12 | [01-01-2000,02-01-2000)
+(6 rows)
+
+select * from parttmp_1_to_10 order by id, valid_at;
+ id |        valid_at         
+----+-------------------------
+  1 | [01-01-2000,02-01-2000)
+  1 | [02-01-2000,03-01-2000)
+  2 | [01-01-2000,02-01-2000)
+(3 rows)
+
+select * from parttmp_11_to_20 order by id, valid_at;
+ id |        valid_at         
+----+-------------------------
+ 11 | [01-01-2000,02-01-2000)
+ 11 | [02-01-2000,03-01-2000)
+ 12 | [01-01-2000,02-01-2000)
+(3 rows)
+
+update parttmp set valid_at = valid_at * '[2000-01-15,2000-02-15)' where id = 1;
+select * from parttmp order by id, valid_at;
+ id |        valid_at         
+----+-------------------------
+  1 | [01-15-2000,02-01-2000)
+  1 | [02-01-2000,02-15-2000)
+  2 | [01-01-2000,02-01-2000)
+ 11 | [01-01-2000,02-01-2000)
+ 11 | [02-01-2000,03-01-2000)
+ 12 | [01-01-2000,02-01-2000)
+(6 rows)
+
+select * from parttmp_1_to_10 order by id, valid_at;
+ id |        valid_at         
+----+-------------------------
+  1 | [01-15-2000,02-01-2000)
+  1 | [02-01-2000,02-15-2000)
+  2 | [01-01-2000,02-01-2000)
+(3 rows)
+
+select * from parttmp_11_to_20 order by id, valid_at;
+ id |        valid_at         
+----+-------------------------
+ 11 | [01-01-2000,02-01-2000)
+ 11 | [02-01-2000,03-01-2000)
+ 12 | [01-01-2000,02-01-2000)
+(3 rows)
+
+-- make sure the excluson constraint excludes:
+insert into parttmp (id, valid_at) values
+  (2, '[2000-01-15, 2000-02-01)');
+ERROR:  conflicting key value violates exclusion constraint "parttmp_1_to_10_id_valid_at_excl"
+DETAIL:  Key (id, valid_at)=(2, [01-15-2000,02-01-2000)) conflicts with existing key (id, valid_at)=(2, [01-01-2000,02-01-2000)).
+drop table parttmp;
+-- should fail with a good error message:
+create table parttmp (id int, valid_at daterange, exclude using gist (id with <>, valid_at with &&) with (buffering = on)) partition by range (id);
+ERROR:  cannot match partition key to index on column "id" using non-equal operator "<>"
diff --git a/contrib/btree_gist/expected/text.out b/contrib/btree_gist/expected/text.out
index bb4e2e62d1d..64f10cb5004 100644
--- a/contrib/btree_gist/expected/text.out
+++ b/contrib/btree_gist/expected/text.out
@@ -34,6 +34,7 @@ SELECT count(*) FROM texttmp WHERE a >   '31b0';
 (1 row)
 
 CREATE INDEX textidx ON texttmp USING GIST ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM texttmp WHERE a <   '31b0'::text;
  count 
diff --git a/contrib/btree_gist/expected/text_buffering.out b/contrib/btree_gist/expected/text_buffering.out
new file mode 100644
index 00000000000..b410243e696
--- /dev/null
+++ b/contrib/btree_gist/expected/text_buffering.out
@@ -0,0 +1,59 @@
+-- text check
+DROP TABLE IF EXISTS texttmp;
+CREATE TABLE texttmp (a text);
+\copy texttmp from 'data/text.data'
+\copy texttmp from 'data/char.data'
+CREATE INDEX textidx ON texttmp USING GIST ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM texttmp WHERE a <   '31b0'::text;
+ count 
+-------
+   588
+(1 row)
+
+SELECT count(*) FROM texttmp WHERE a <=  '31b0'::text;
+ count 
+-------
+   589
+(1 row)
+
+SELECT count(*) FROM texttmp WHERE a  =  '31b0'::text;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM texttmp WHERE a >=  '31b0'::text;
+ count 
+-------
+   401
+(1 row)
+
+SELECT count(*) FROM texttmp WHERE a >   '31b0'::text;
+ count 
+-------
+   400
+(1 row)
+
+SELECT count(*) FROM texttmp WHERE a  =  '2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809'::text;
+ count 
+-------
+     1
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM texttmp WHERE a BETWEEN '31a' AND '31c';
+                        QUERY PLAN                         
+-----------------------------------------------------------
+ Index Only Scan using textidx on texttmp
+   Index Cond: ((a >= '31a'::text) AND (a <= '31c'::text))
+(2 rows)
+
+SELECT * FROM texttmp WHERE a BETWEEN '31a' AND '31c';
+  a   
+------
+ 31b0
+(1 row)
+
diff --git a/contrib/btree_gist/expected/text_buffering_1.out b/contrib/btree_gist/expected/text_buffering_1.out
new file mode 100644
index 00000000000..08037f49863
--- /dev/null
+++ b/contrib/btree_gist/expected/text_buffering_1.out
@@ -0,0 +1,59 @@
+-- text check
+DROP TABLE IF EXISTS texttmp;
+CREATE TABLE texttmp (a text);
+\copy texttmp from 'data/text.data'
+\copy texttmp from 'data/char.data'
+CREATE INDEX textidx ON texttmp USING GIST ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM texttmp WHERE a <   '31b0'::text;
+ count 
+-------
+   774
+(1 row)
+
+SELECT count(*) FROM texttmp WHERE a <=  '31b0'::text;
+ count 
+-------
+   775
+(1 row)
+
+SELECT count(*) FROM texttmp WHERE a  =  '31b0'::text;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM texttmp WHERE a >=  '31b0'::text;
+ count 
+-------
+   215
+(1 row)
+
+SELECT count(*) FROM texttmp WHERE a >   '31b0'::text;
+ count 
+-------
+   214
+(1 row)
+
+SELECT count(*) FROM texttmp WHERE a  =  '2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809'::text;
+ count 
+-------
+     1
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM texttmp WHERE a BETWEEN '31a' AND '31c';
+                        QUERY PLAN                         
+-----------------------------------------------------------
+ Index Only Scan using textidx on texttmp
+   Index Cond: ((a >= '31a'::text) AND (a <= '31c'::text))
+(2 rows)
+
+SELECT * FROM texttmp WHERE a BETWEEN '31a' AND '31c';
+  a   
+------
+ 31b0
+(1 row)
+
diff --git a/contrib/btree_gist/expected/time.out b/contrib/btree_gist/expected/time.out
index ec95ef77c57..64ea2cdef0b 100644
--- a/contrib/btree_gist/expected/time.out
+++ b/contrib/btree_gist/expected/time.out
@@ -41,6 +41,7 @@ SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3;
 (3 rows)
 
 CREATE INDEX timeidx ON timetmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM timetmp WHERE a <  '10:57:11'::time;
  count 
diff --git a/contrib/btree_gist/expected/time_buffering.out b/contrib/btree_gist/expected/time_buffering.out
new file mode 100644
index 00000000000..f0a0ec40752
--- /dev/null
+++ b/contrib/btree_gist/expected/time_buffering.out
@@ -0,0 +1,53 @@
+-- time check
+DROP TABLE IF EXISTS timetmp;
+CREATE TABLE timetmp (a time);
+\copy timetmp from 'data/time.data'
+CREATE INDEX timeidx ON timetmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM timetmp WHERE a <  '10:57:11'::time;
+ count 
+-------
+   251
+(1 row)
+
+SELECT count(*) FROM timetmp WHERE a <= '10:57:11'::time;
+ count 
+-------
+   252
+(1 row)
+
+SELECT count(*) FROM timetmp WHERE a  = '10:57:11'::time;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM timetmp WHERE a >= '10:57:11'::time;
+ count 
+-------
+   293
+(1 row)
+
+SELECT count(*) FROM timetmp WHERE a >  '10:57:11'::time;
+ count 
+-------
+   292
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Limit
+   ->  Index Only Scan using timeidx on timetmp
+         Order By: (a <-> '10:57:11'::time without time zone)
+(3 rows)
+
+SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3;
+    a     |    ?column?     
+----------+-----------------
+ 10:57:11 | @ 0
+ 10:57:10 | @ 1 sec
+ 10:55:32 | @ 1 min 39 secs
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/timestamp.out b/contrib/btree_gist/expected/timestamp.out
index 0d94f2f245c..9b4f5381c16 100644
--- a/contrib/btree_gist/expected/timestamp.out
+++ b/contrib/btree_gist/expected/timestamp.out
@@ -41,6 +41,7 @@ SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-
 (3 rows)
 
 CREATE INDEX timestampidx ON timestamptmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM timestamptmp WHERE a <  '2004-10-26 08:55:08'::timestamp;
  count 
diff --git a/contrib/btree_gist/expected/timestamp_buffering.out b/contrib/btree_gist/expected/timestamp_buffering.out
new file mode 100644
index 00000000000..ee968050212
--- /dev/null
+++ b/contrib/btree_gist/expected/timestamp_buffering.out
@@ -0,0 +1,53 @@
+-- timestamp check
+DROP TABLE IF EXISTS timestamptmp;
+CREATE TABLE timestamptmp (a timestamp);
+\copy timestamptmp from 'data/timestamp.data'
+CREATE INDEX timestampidx ON timestamptmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM timestamptmp WHERE a <  '2004-10-26 08:55:08'::timestamp;
+ count 
+-------
+   278
+(1 row)
+
+SELECT count(*) FROM timestamptmp WHERE a <= '2004-10-26 08:55:08'::timestamp;
+ count 
+-------
+   279
+(1 row)
+
+SELECT count(*) FROM timestamptmp WHERE a  = '2004-10-26 08:55:08'::timestamp;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM timestamptmp WHERE a >= '2004-10-26 08:55:08'::timestamp;
+ count 
+-------
+   290
+(1 row)
+
+SELECT count(*) FROM timestamptmp WHERE a >  '2004-10-26 08:55:08'::timestamp;
+ count 
+-------
+   289
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3;
+                                    QUERY PLAN                                     
+-----------------------------------------------------------------------------------
+ Limit
+   ->  Index Only Scan using timestampidx on timestamptmp
+         Order By: (a <-> 'Tue Oct 26 08:55:08 2004'::timestamp without time zone)
+(3 rows)
+
+SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3;
+            a             |              ?column?              
+--------------------------+------------------------------------
+ Tue Oct 26 08:55:08 2004 | @ 0
+ Sun Oct 31 06:35:03 2004 | @ 4 days 21 hours 39 mins 55 secs
+ Mon Nov 29 20:12:43 2004 | @ 34 days 11 hours 17 mins 35 secs
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/timestamptz.out b/contrib/btree_gist/expected/timestamptz.out
index 75a15a42568..6af41041216 100644
--- a/contrib/btree_gist/expected/timestamptz.out
+++ b/contrib/btree_gist/expected/timestamptz.out
@@ -101,6 +101,7 @@ SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '
 (3 rows)
 
 CREATE INDEX timestamptzidx ON timestamptztmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM timestamptztmp WHERE a <  '2018-12-18 10:59:54 GMT+3'::timestamptz;
  count 
diff --git a/contrib/btree_gist/expected/timestamptz_buffering.out b/contrib/btree_gist/expected/timestamptz_buffering.out
new file mode 100644
index 00000000000..00613a08fe4
--- /dev/null
+++ b/contrib/btree_gist/expected/timestamptz_buffering.out
@@ -0,0 +1,113 @@
+-- timestamptz check
+DROP TABLE IF EXISTS timestamptztmp;
+CREATE TABLE timestamptztmp (a timestamptz);
+\copy timestamptztmp from 'data/timestamptz.data'
+CREATE INDEX timestamptzidx ON timestamptztmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM timestamptztmp WHERE a <  '2018-12-18 10:59:54 GMT+3'::timestamptz;
+ count 
+-------
+   391
+(1 row)
+
+SELECT count(*) FROM timestamptztmp WHERE a <= '2018-12-18 10:59:54 GMT+3'::timestamptz;
+ count 
+-------
+   392
+(1 row)
+
+SELECT count(*) FROM timestamptztmp WHERE a  = '2018-12-18 10:59:54 GMT+3'::timestamptz;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM timestamptztmp WHERE a >= '2018-12-18 10:59:54 GMT+3'::timestamptz;
+ count 
+-------
+   158
+(1 row)
+
+SELECT count(*) FROM timestamptztmp WHERE a >  '2018-12-18 10:59:54 GMT+3'::timestamptz;
+ count 
+-------
+   157
+(1 row)
+
+SELECT count(*) FROM timestamptztmp WHERE a <  '2018-12-18 10:59:54 GMT+2'::timestamptz;
+ count 
+-------
+   391
+(1 row)
+
+SELECT count(*) FROM timestamptztmp WHERE a <= '2018-12-18 10:59:54 GMT+2'::timestamptz;
+ count 
+-------
+   391
+(1 row)
+
+SELECT count(*) FROM timestamptztmp WHERE a  = '2018-12-18 10:59:54 GMT+2'::timestamptz;
+ count 
+-------
+     0
+(1 row)
+
+SELECT count(*) FROM timestamptztmp WHERE a >= '2018-12-18 10:59:54 GMT+2'::timestamptz;
+ count 
+-------
+   158
+(1 row)
+
+SELECT count(*) FROM timestamptztmp WHERE a >  '2018-12-18 10:59:54 GMT+2'::timestamptz;
+ count 
+-------
+   158
+(1 row)
+
+SELECT count(*) FROM timestamptztmp WHERE a <  '2018-12-18 10:59:54 GMT+4'::timestamptz;
+ count 
+-------
+   392
+(1 row)
+
+SELECT count(*) FROM timestamptztmp WHERE a <= '2018-12-18 10:59:54 GMT+4'::timestamptz;
+ count 
+-------
+   392
+(1 row)
+
+SELECT count(*) FROM timestamptztmp WHERE a  = '2018-12-18 10:59:54 GMT+4'::timestamptz;
+ count 
+-------
+     0
+(1 row)
+
+SELECT count(*) FROM timestamptztmp WHERE a >= '2018-12-18 10:59:54 GMT+4'::timestamptz;
+ count 
+-------
+   157
+(1 row)
+
+SELECT count(*) FROM timestamptztmp WHERE a >  '2018-12-18 10:59:54 GMT+4'::timestamptz;
+ count 
+-------
+   157
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3;
+                                     QUERY PLAN                                     
+------------------------------------------------------------------------------------
+ Limit
+   ->  Index Only Scan using timestamptzidx on timestamptztmp
+         Order By: (a <-> 'Tue Dec 18 04:59:54 2018 PST'::timestamp with time zone)
+(3 rows)
+
+SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3;
+              a               |             ?column?              
+------------------------------+-----------------------------------
+ Tue Dec 18 05:59:54 2018 PST | @ 1 hour
+ Thu Jan 10 03:01:34 2019 PST | @ 22 days 22 hours 1 min 40 secs
+ Thu Jan 24 12:28:12 2019 PST | @ 37 days 7 hours 28 mins 18 secs
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/timetz.out b/contrib/btree_gist/expected/timetz.out
index 7f73e447977..f4d3c0f39fe 100644
--- a/contrib/btree_gist/expected/timetz.out
+++ b/contrib/btree_gist/expected/timetz.out
@@ -19,6 +19,7 @@ INSERT INTO timetzcmp (r_id,a) SELECT 23,count(*) FROM timetztmp WHERE a  = '07:
 INSERT INTO timetzcmp (r_id,a) SELECT 24,count(*) FROM timetztmp WHERE a >= '07:46:45 GMT+4';
 INSERT INTO timetzcmp (r_id,a) SELECT 25,count(*) FROM timetztmp WHERE a >  '07:46:45 GMT+4';
 CREATE INDEX timetzidx ON timetztmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a <  '07:46:45 GMT+3'::timetz ) q WHERE r_id=1 ;
 UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a <= '07:46:45 GMT+3'::timetz ) q WHERE r_id=2 ;
diff --git a/contrib/btree_gist/expected/timetz_buffering.out b/contrib/btree_gist/expected/timetz_buffering.out
new file mode 100644
index 00000000000..e0c52ca88ed
--- /dev/null
+++ b/contrib/btree_gist/expected/timetz_buffering.out
@@ -0,0 +1,45 @@
+-- timetz check
+DROP TABLE IF EXISTS timetztmp;
+DROP TABLE IF EXISTS timetzcmp;
+CREATE TABLE timetztmp (a timetz);
+\copy timetztmp from 'data/timetz.data'
+CREATE TABLE timetzcmp ( r_id int2, a int4, b int4 );
+SET enable_seqscan=on;
+INSERT INTO timetzcmp (r_id,a) SELECT  1,count(*) FROM timetztmp WHERE a <  '07:46:45 GMT+3';
+INSERT INTO timetzcmp (r_id,a) SELECT  2,count(*) FROM timetztmp WHERE a <= '07:46:45 GMT+3';
+INSERT INTO timetzcmp (r_id,a) SELECT  3,count(*) FROM timetztmp WHERE a  = '07:46:45 GMT+3';
+INSERT INTO timetzcmp (r_id,a) SELECT  4,count(*) FROM timetztmp WHERE a >= '07:46:45 GMT+3';
+INSERT INTO timetzcmp (r_id,a) SELECT  5,count(*) FROM timetztmp WHERE a >  '07:46:45 GMT+3';
+INSERT INTO timetzcmp (r_id,a) SELECT 11,count(*) FROM timetztmp WHERE a <  '07:46:45 GMT+2';
+INSERT INTO timetzcmp (r_id,a) SELECT 12,count(*) FROM timetztmp WHERE a <= '07:46:45 GMT+2';
+INSERT INTO timetzcmp (r_id,a) SELECT 13,count(*) FROM timetztmp WHERE a  = '07:46:45 GMT+2';
+INSERT INTO timetzcmp (r_id,a) SELECT 14,count(*) FROM timetztmp WHERE a >= '07:46:45 GMT+2';
+INSERT INTO timetzcmp (r_id,a) SELECT 15,count(*) FROM timetztmp WHERE a >  '07:46:45 GMT+2';
+INSERT INTO timetzcmp (r_id,a) SELECT 21,count(*) FROM timetztmp WHERE a <  '07:46:45 GMT+4';
+INSERT INTO timetzcmp (r_id,a) SELECT 22,count(*) FROM timetztmp WHERE a <= '07:46:45 GMT+4';
+INSERT INTO timetzcmp (r_id,a) SELECT 23,count(*) FROM timetztmp WHERE a  = '07:46:45 GMT+4';
+INSERT INTO timetzcmp (r_id,a) SELECT 24,count(*) FROM timetztmp WHERE a >= '07:46:45 GMT+4';
+INSERT INTO timetzcmp (r_id,a) SELECT 25,count(*) FROM timetztmp WHERE a >  '07:46:45 GMT+4';
+CREATE INDEX timetzidx ON timetztmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a <  '07:46:45 GMT+3'::timetz ) q WHERE r_id=1 ;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a <= '07:46:45 GMT+3'::timetz ) q WHERE r_id=2 ;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a  = '07:46:45 GMT+3'::timetz ) q WHERE r_id=3 ;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a >= '07:46:45 GMT+3'::timetz ) q WHERE r_id=4 ;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a >  '07:46:45 GMT+3'::timetz ) q WHERE r_id=5 ;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a <  '07:46:45 GMT+2'::timetz ) q WHERE r_id=11 ;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a <= '07:46:45 GMT+2'::timetz ) q WHERE r_id=12 ;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a  = '07:46:45 GMT+2'::timetz ) q WHERE r_id=13 ;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a >= '07:46:45 GMT+2'::timetz ) q WHERE r_id=14 ;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a >  '07:46:45 GMT+2'::timetz ) q WHERE r_id=15 ;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a <  '07:46:45 GMT+4'::timetz ) q WHERE r_id=21 ;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a <= '07:46:45 GMT+4'::timetz ) q WHERE r_id=22 ;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a  = '07:46:45 GMT+4'::timetz ) q WHERE r_id=23 ;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a >= '07:46:45 GMT+4'::timetz ) q WHERE r_id=24 ;
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a >  '07:46:45 GMT+4'::timetz ) q WHERE r_id=25 ;
+SELECT count(*) FROM timetzcmp WHERE a=b;
+ count 
+-------
+    15
+(1 row)
+
diff --git a/contrib/btree_gist/expected/uuid.out b/contrib/btree_gist/expected/uuid.out
index a34b0246032..7495c7f947b 100644
--- a/contrib/btree_gist/expected/uuid.out
+++ b/contrib/btree_gist/expected/uuid.out
@@ -33,6 +33,7 @@ SELECT count(*) FROM uuidtmp WHERE a >  '55e65ca2-4136-4a4b-ba78-cd3fe4678203';
 (1 row)
 
 CREATE INDEX uuididx ON uuidtmp USING gist ( a );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM uuidtmp WHERE a <  '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
  count 
diff --git a/contrib/btree_gist/expected/uuid_buffering.out b/contrib/btree_gist/expected/uuid_buffering.out
new file mode 100644
index 00000000000..df23c9278c3
--- /dev/null
+++ b/contrib/btree_gist/expected/uuid_buffering.out
@@ -0,0 +1,36 @@
+-- uuid check
+DROP TABLE IF EXISTS uuidtmp;
+CREATE TABLE uuidtmp (a uuid);
+\copy uuidtmp from 'data/uuid.data'
+CREATE INDEX uuididx ON uuidtmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM uuidtmp WHERE a <  '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
+ count 
+-------
+   227
+(1 row)
+
+SELECT count(*) FROM uuidtmp WHERE a <= '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
+ count 
+-------
+   228
+(1 row)
+
+SELECT count(*) FROM uuidtmp WHERE a  = '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM uuidtmp WHERE a >= '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
+ count 
+-------
+   376
+(1 row)
+
+SELECT count(*) FROM uuidtmp WHERE a >  '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
+ count 
+-------
+   375
+(1 row)
+
diff --git a/contrib/btree_gist/expected/varbit_buffering.out b/contrib/btree_gist/expected/varbit_buffering.out
new file mode 100644
index 00000000000..63fa8d034c0
--- /dev/null
+++ b/contrib/btree_gist/expected/varbit_buffering.out
@@ -0,0 +1,46 @@
+-- varbit check
+DROP TABLE IF EXISTS varbittmp;
+CREATE TABLE varbittmp (a varbit);
+\copy varbittmp from 'data/varbit.data'
+CREATE INDEX varbitidx ON varbittmp USING GIST ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM varbittmp WHERE a <   '1110100111010'::varbit;
+ count 
+-------
+   549
+(1 row)
+
+SELECT count(*) FROM varbittmp WHERE a <=  '1110100111010'::varbit;
+ count 
+-------
+   550
+(1 row)
+
+SELECT count(*) FROM varbittmp WHERE a  =  '1110100111010'::varbit;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM varbittmp WHERE a >=  '1110100111010'::varbit;
+ count 
+-------
+    51
+(1 row)
+
+SELECT count(*) FROM varbittmp WHERE a >   '1110100111010'::varbit;
+ count 
+-------
+    50
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT a FROM bittmp WHERE a BETWEEN '1000000' and '1000001';
+                             QUERY PLAN                              
+---------------------------------------------------------------------
+ Index Only Scan using bitidx on bittmp
+   Index Cond: ((a >= '1000000'::"bit") AND (a <= '1000001'::"bit"))
+(2 rows)
+
diff --git a/contrib/btree_gist/expected/varchar.out b/contrib/btree_gist/expected/varchar.out
index d071d714cdd..49a083e8aca 100644
--- a/contrib/btree_gist/expected/varchar.out
+++ b/contrib/btree_gist/expected/varchar.out
@@ -33,6 +33,7 @@ SELECT count(*) FROM vchartmp WHERE a >   '31b0'::varchar(32);
 (1 row)
 
 CREATE INDEX vcharidx ON vchartmp USING GIST ( text(a) );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM vchartmp WHERE a <   '31b0'::varchar(32);
  count 
diff --git a/contrib/btree_gist/expected/varchar_buffering.out b/contrib/btree_gist/expected/varchar_buffering.out
new file mode 100644
index 00000000000..f3d4b7dec64
--- /dev/null
+++ b/contrib/btree_gist/expected/varchar_buffering.out
@@ -0,0 +1,36 @@
+-- char check
+DROP TABLE IF EXISTS vchartmp;
+CREATE TABLE vchartmp (a varchar(32));
+\copy vchartmp from 'data/char.data'
+CREATE INDEX vcharidx ON vchartmp USING GIST ( text(a) ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM vchartmp WHERE a <   '31b0'::varchar(32);
+ count 
+-------
+   587
+(1 row)
+
+SELECT count(*) FROM vchartmp WHERE a <=  '31b0'::varchar(32);
+ count 
+-------
+   588
+(1 row)
+
+SELECT count(*) FROM vchartmp WHERE a  =  '31b0'::varchar(32);
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM vchartmp WHERE a >=  '31b0'::varchar(32);
+ count 
+-------
+   401
+(1 row)
+
+SELECT count(*) FROM vchartmp WHERE a >   '31b0'::varchar(32);
+ count 
+-------
+   400
+(1 row)
+
diff --git a/contrib/btree_gist/expected/varchar_buffering_1.out b/contrib/btree_gist/expected/varchar_buffering_1.out
new file mode 100644
index 00000000000..4d67d1d9330
--- /dev/null
+++ b/contrib/btree_gist/expected/varchar_buffering_1.out
@@ -0,0 +1,36 @@
+-- char check
+DROP TABLE IF EXISTS vchartmp;
+CREATE TABLE vchartmp (a varchar(32));
+\copy vchartmp from 'data/char.data'
+CREATE INDEX vcharidx ON vchartmp USING GIST ( text(a) ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM vchartmp WHERE a <   '31b0'::varchar(32);
+ count 
+-------
+   773
+(1 row)
+
+SELECT count(*) FROM vchartmp WHERE a <=  '31b0'::varchar(32);
+ count 
+-------
+   774
+(1 row)
+
+SELECT count(*) FROM vchartmp WHERE a  =  '31b0'::varchar(32);
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM vchartmp WHERE a >=  '31b0'::varchar(32);
+ count 
+-------
+   215
+(1 row)
+
+SELECT count(*) FROM vchartmp WHERE a >   '31b0'::varchar(32);
+ count 
+-------
+   214
+(1 row)
+
diff --git a/contrib/btree_gist/expected/without_overlaps.out b/contrib/btree_gist/expected/without_overlaps.out
index 18856900ded..82483322ba7 100644
--- a/contrib/btree_gist/expected/without_overlaps.out
+++ b/contrib/btree_gist/expected/without_overlaps.out
@@ -8,6 +8,8 @@ CREATE TABLE temporal_rng (
   valid_at daterange,
   CONSTRAINT temporal_rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS)
 );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 \d temporal_rng
               Table "public.temporal_rng"
   Column  |   Type    | Collation | Nullable | Default 
@@ -51,6 +53,8 @@ CREATE TABLE temporal_fk_rng2rng (
   CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, PERIOD valid_at)
     REFERENCES temporal_rng (id, PERIOD valid_at)
 );
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
+NOTICE:  notice triggered for injection point btree-gist-sorted-build
 \d temporal_fk_rng2rng
            Table "public.temporal_fk_rng2rng"
   Column   |   Type    | Collation | Nullable | Default 
diff --git a/contrib/btree_gist/expected/without_overlaps_buffering.out b/contrib/btree_gist/expected/without_overlaps_buffering.out
new file mode 100644
index 00000000000..c6aa60f1eaf
--- /dev/null
+++ b/contrib/btree_gist/expected/without_overlaps_buffering.out
@@ -0,0 +1,90 @@
+-- Core must test WITHOUT OVERLAPS
+-- with an int4range + daterange,
+-- so here we do some simple tests
+-- to make sure int + daterange works too,
+-- since that is the expected use-case.
+DROP TABLE IF EXISTS temporal_rng CASCADE ;
+NOTICE:  drop cascades to constraint temporal_fk_rng2rng_fk on table temporal_fk_rng2rng
+CREATE TABLE temporal_rng (
+  id integer,
+  valid_at daterange,
+  CONSTRAINT temporal_rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) WITH(buffering=on)
+);
+\d temporal_rng
+              Table "public.temporal_rng"
+  Column  |   Type    | Collation | Nullable | Default 
+----------+-----------+-----------+----------+---------
+ id       | integer   |           | not null | 
+ valid_at | daterange |           | not null | 
+Indexes:
+    "temporal_rng_pk" PRIMARY KEY (id, valid_at WITHOUT OVERLAPS)
+
+SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'temporal_rng_pk';
+            pg_get_constraintdef             
+---------------------------------------------
+ PRIMARY KEY (id, valid_at WITHOUT OVERLAPS)
+(1 row)
+
+SELECT pg_get_indexdef(conindid, 0, true) FROM pg_constraint WHERE conname = 'temporal_rng_pk';
+                                           pg_get_indexdef                                           
+-----------------------------------------------------------------------------------------------------
+ CREATE UNIQUE INDEX temporal_rng_pk ON temporal_rng USING gist (id, valid_at) WITH (buffering='on')
+(1 row)
+
+INSERT INTO temporal_rng VALUES
+  (1, '[2000-01-01,2001-01-01)');
+-- same key, doesn't overlap:
+INSERT INTO temporal_rng VALUES
+  (1, '[2001-01-01,2002-01-01)');
+-- overlaps but different key:
+INSERT INTO temporal_rng VALUES
+  (2, '[2000-01-01,2001-01-01)');
+-- should fail:
+INSERT INTO temporal_rng VALUES
+  (1, '[2000-06-01,2001-01-01)');
+ERROR:  conflicting key value violates exclusion constraint "temporal_rng_pk"
+DETAIL:  Key (id, valid_at)=(1, [06-01-2000,01-01-2001)) conflicts with existing key (id, valid_at)=(1, [01-01-2000,01-01-2001)).
+-- Foreign key
+CREATE TABLE temporal_fk_rng2rng (
+  id integer,
+  valid_at daterange,
+  parent_id integer,
+  CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) WITH(buffering=on),
+  CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, PERIOD valid_at)
+    REFERENCES temporal_rng (id, PERIOD valid_at)
+);
+ERROR:  relation "temporal_fk_rng2rng" already exists
+\d temporal_fk_rng2rng
+           Table "public.temporal_fk_rng2rng"
+  Column   |   Type    | Collation | Nullable | Default 
+-----------+-----------+-----------+----------+---------
+ id        | integer   |           | not null | 
+ valid_at  | daterange |           | not null | 
+ parent_id | integer   |           |          | 
+Indexes:
+    "temporal_fk_rng2rng_pk" PRIMARY KEY (id, valid_at WITHOUT OVERLAPS)
+
+SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'temporal_fk_rng2rng_fk';
+ pg_get_constraintdef 
+----------------------
+(0 rows)
+
+-- okay
+INSERT INTO temporal_fk_rng2rng VALUES
+  (1, '[2000-01-01,2001-01-01)', 1);
+ERROR:  conflicting key value violates exclusion constraint "temporal_fk_rng2rng_pk"
+DETAIL:  Key (id, valid_at)=(1, [01-01-2000,01-01-2001)) conflicts with existing key (id, valid_at)=(1, [01-01-2000,01-01-2001)).
+-- okay spanning two parent records:
+INSERT INTO temporal_fk_rng2rng VALUES
+  (2, '[2000-01-01,2002-01-01)', 1);
+ERROR:  conflicting key value violates exclusion constraint "temporal_fk_rng2rng_pk"
+DETAIL:  Key (id, valid_at)=(2, [01-01-2000,01-01-2002)) conflicts with existing key (id, valid_at)=(2, [01-01-2000,01-01-2002)).
+-- key is missing
+INSERT INTO temporal_fk_rng2rng VALUES
+  (3, '[2000-01-01,2001-01-01)', 3);
+-- key exist but is outside range
+INSERT INTO temporal_fk_rng2rng VALUES
+  (4, '[2001-01-01,2002-01-01)', 2);
+-- key exist but is partly outside range
+INSERT INTO temporal_fk_rng2rng VALUES
+  (5, '[2000-01-01,2002-01-01)', 2);
diff --git a/contrib/btree_gist/meson.build b/contrib/btree_gist/meson.build
index 73b1bbf52a6..5f6c0a64477 100644
--- a/contrib/btree_gist/meson.build
+++ b/contrib/btree_gist/meson.build
@@ -51,9 +51,11 @@ install_data(
   'btree_gist--1.5--1.6.sql',
   'btree_gist--1.6--1.7.sql',
   'btree_gist--1.7--1.8.sql',
+  'btree_gist--1.8--1.9.sql',
   kwargs: contrib_data_args,
 )
 
+# Make sure buffering tests appear after non-buffering.
 tests += {
   'name': 'btree_gist',
   'sd': meson.current_source_dir(),
@@ -62,36 +64,67 @@ tests += {
     'sql': [
       'init',
       'int2',
+      'int2_buffering',
       'int4',
+      'int4_buffering',
       'int8',
+      'int8_buffering',
       'float4',
+      'float4_buffering',
       'float8',
+      'float8_buffering',
       'cash',
+      'cash_buffering',
       'oid',
+      'oid_buffering',
       'timestamp',
+      'timestamp_buffering',
       'timestamptz',
+      'timestamptz_buffering',
       'time',
+      'time_buffering',
       'timetz',
+      'timetz_buffering',
       'date',
+      'date_buffering',
       'interval',
+      'interval_buffering',
       'macaddr',
+      'macaddr_buffering',
       'macaddr8',
+      'macaddr8_buffering',
       'inet',
+      'inet_buffering',
       'cidr',
+      'cidr_buffering',
       'text',
+      'text_buffering',
       'varchar',
+      'varchar_buffering',
       'char',
+      'char_buffering',
       'bytea',
+      'bytea_buffering',
       'bit',
+      'bit_buffering',
       'varbit',
+      'varbit_buffering',
       'numeric',
+      'numeric_buffering',
       'uuid',
+      'uuid_buffering',
       'not_equal',
+      'not_equal_buffering',
       'enum',
+      'enum_buffering',
       'bool',
+      'bool_buffering',
       'partitions',
+      'partitions_buffering',
       'stratnum',
       'without_overlaps',
+      'without_overlaps_buffering',
+      'cleanup',
     ],
   },
 }
diff --git a/contrib/btree_gist/sql/bit_buffering.sql b/contrib/btree_gist/sql/bit_buffering.sql
new file mode 100644
index 00000000000..7ef13fcef89
--- /dev/null
+++ b/contrib/btree_gist/sql/bit_buffering.sql
@@ -0,0 +1,25 @@
+-- bit check with buffer index builds
+
+DROP TABLE IF EXISTS bittmp;
+CREATE TABLE bittmp (a bit(33));
+
+\copy bittmp from 'data/bit.data'
+
+CREATE INDEX bitidx ON bittmp USING GIST ( a ) WITH(buffering=on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM bittmp WHERE a <   '011011000100010111011000110000100';
+
+SELECT count(*) FROM bittmp WHERE a <=  '011011000100010111011000110000100';
+
+SELECT count(*) FROM bittmp WHERE a  =  '011011000100010111011000110000100';
+
+SELECT count(*) FROM bittmp WHERE a >=  '011011000100010111011000110000100';
+
+SELECT count(*) FROM bittmp WHERE a >   '011011000100010111011000110000100';
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT a FROM bittmp WHERE a BETWEEN '1000000' and '1000001';
diff --git a/contrib/btree_gist/sql/bool_buffering.sql b/contrib/btree_gist/sql/bool_buffering.sql
new file mode 100644
index 00000000000..f9c933f00d0
--- /dev/null
+++ b/contrib/btree_gist/sql/bool_buffering.sql
@@ -0,0 +1,31 @@
+-- bool check
+
+DROP TABLE IF EXISTS booltmp;
+CREATE TABLE booltmp (a bool);
+
+INSERT INTO booltmp VALUES (false), (true);
+
+CREATE INDEX boolidx ON booltmp USING gist ( a ) WITH(buffering=on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM booltmp WHERE a <  true;
+
+SELECT count(*) FROM booltmp WHERE a <= true;
+
+SELECT count(*) FROM booltmp WHERE a  = true;
+
+SELECT count(*) FROM booltmp WHERE a >= true;
+
+SELECT count(*) FROM booltmp WHERE a >  true;
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM booltmp WHERE a;
+SELECT * FROM booltmp WHERE a;
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM booltmp WHERE NOT a;
+SELECT * FROM booltmp WHERE NOT a;
diff --git a/contrib/btree_gist/sql/bytea_buffering.sql b/contrib/btree_gist/sql/bytea_buffering.sql
new file mode 100644
index 00000000000..59c4365e613
--- /dev/null
+++ b/contrib/btree_gist/sql/bytea_buffering.sql
@@ -0,0 +1,29 @@
+-- bytea check
+
+DROP TABLE IF EXISTS byteatmp;
+CREATE TABLE byteatmp (a bytea);
+
+\copy byteatmp from 'data/text.data'
+\copy byteatmp from 'data/char.data'
+
+CREATE INDEX byteaidx ON byteatmp USING GIST ( a ) WITH(buffering=on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM byteatmp WHERE a <   '31b0'::bytea;
+
+SELECT count(*) FROM byteatmp WHERE a <=  '31b0'::bytea;
+
+SELECT count(*) FROM byteatmp WHERE a  =  '31b0'::bytea;
+
+SELECT count(*) FROM byteatmp WHERE a >=  '31b0'::bytea;
+
+SELECT count(*) FROM byteatmp WHERE a >   '31b0'::bytea;
+
+SELECT count(*) FROM byteatmp WHERE a  =  '2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809'::bytea;
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT a FROM byteatmp where a > 'ffa'::bytea;
+SELECT a FROM byteatmp where a > 'ffa'::bytea;
diff --git a/contrib/btree_gist/sql/cash_buffering.sql b/contrib/btree_gist/sql/cash_buffering.sql
new file mode 100644
index 00000000000..3f7d7bb34e6
--- /dev/null
+++ b/contrib/btree_gist/sql/cash_buffering.sql
@@ -0,0 +1,24 @@
+-- money check
+
+DROP TABLE IF EXISTS moneytmp;
+CREATE TABLE moneytmp (a money);
+
+\copy moneytmp from 'data/cash.data'
+
+CREATE INDEX moneyidx ON moneytmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM moneytmp WHERE a <  '22649.64'::money;
+
+SELECT count(*) FROM moneytmp WHERE a <= '22649.64'::money;
+
+SELECT count(*) FROM moneytmp WHERE a  = '22649.64'::money;
+
+SELECT count(*) FROM moneytmp WHERE a >= '22649.64'::money;
+
+SELECT count(*) FROM moneytmp WHERE a >  '22649.64'::money;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3;
+SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3;
diff --git a/contrib/btree_gist/sql/char_buffering.sql b/contrib/btree_gist/sql/char_buffering.sql
new file mode 100644
index 00000000000..b98c4759fa6
--- /dev/null
+++ b/contrib/btree_gist/sql/char_buffering.sql
@@ -0,0 +1,26 @@
+-- char check
+
+DROP TABLE IF EXISTS chartmp;
+CREATE TABLE chartmp (a char(32));
+
+\copy chartmp from 'data/char.data'
+
+CREATE INDEX charidx ON chartmp USING GIST ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM chartmp WHERE a <   '31b0'::char(32);
+
+SELECT count(*) FROM chartmp WHERE a <=  '31b0'::char(32);
+
+SELECT count(*) FROM chartmp WHERE a  =  '31b0'::char(32);
+
+SELECT count(*) FROM chartmp WHERE a >=  '31b0'::char(32);
+
+SELECT count(*) FROM chartmp WHERE a >   '31b0'::char(32);
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM chartmp WHERE a BETWEEN '31a' AND '31c';
+SELECT * FROM chartmp WHERE a BETWEEN '31a' AND '31c';
diff --git a/contrib/btree_gist/sql/cidr_buffering.sql b/contrib/btree_gist/sql/cidr_buffering.sql
new file mode 100644
index 00000000000..5bd335d60cb
--- /dev/null
+++ b/contrib/btree_gist/sql/cidr_buffering.sql
@@ -0,0 +1,19 @@
+-- cidr check
+
+DROP TABLE IF EXISTS cidrtmp;
+CREATE TABLE cidrtmp AS
+  SELECT cidr(a) AS a FROM inettmp ;
+
+CREATE INDEX cidridx ON cidrtmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM cidrtmp WHERE a <  '121.111.63.82'::cidr;
+
+SELECT count(*) FROM cidrtmp WHERE a <= '121.111.63.82'::cidr;
+
+SELECT count(*) FROM cidrtmp WHERE a  = '121.111.63.82'::cidr;
+
+SELECT count(*) FROM cidrtmp WHERE a >= '121.111.63.82'::cidr;
+
+SELECT count(*) FROM cidrtmp WHERE a >  '121.111.63.82'::cidr;
diff --git a/contrib/btree_gist/sql/cleanup.sql b/contrib/btree_gist/sql/cleanup.sql
new file mode 100644
index 00000000000..d5be5cc3eb7
--- /dev/null
+++ b/contrib/btree_gist/sql/cleanup.sql
@@ -0,0 +1 @@
+SELECT injection_points_detach('btree-gist-sorted-build');
\ No newline at end of file
diff --git a/contrib/btree_gist/sql/date_buffering.sql b/contrib/btree_gist/sql/date_buffering.sql
new file mode 100644
index 00000000000..499eb61746d
--- /dev/null
+++ b/contrib/btree_gist/sql/date_buffering.sql
@@ -0,0 +1,24 @@
+-- date check
+
+DROP TABLE IF EXISTS datetmp;
+CREATE TABLE datetmp (a date);
+
+\copy datetmp from 'data/date.data'
+
+CREATE INDEX dateidx ON datetmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM datetmp WHERE a <  '2001-02-13'::date;
+
+SELECT count(*) FROM datetmp WHERE a <= '2001-02-13'::date;
+
+SELECT count(*) FROM datetmp WHERE a  = '2001-02-13'::date;
+
+SELECT count(*) FROM datetmp WHERE a >= '2001-02-13'::date;
+
+SELECT count(*) FROM datetmp WHERE a >  '2001-02-13'::date;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3;
+SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3;
diff --git a/contrib/btree_gist/sql/enum_buffering.sql b/contrib/btree_gist/sql/enum_buffering.sql
new file mode 100644
index 00000000000..d4f66e910af
--- /dev/null
+++ b/contrib/btree_gist/sql/enum_buffering.sql
@@ -0,0 +1,23 @@
+-- enum check
+
+DROP TABLE IF EXISTS enumtmp;
+CREATE TABLE enumtmp (a rainbow);
+
+\copy enumtmp from 'data/enum.data'
+
+CREATE INDEX enumidx ON enumtmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM enumtmp WHERE a <  'g'::rainbow;
+
+SELECT count(*) FROM enumtmp WHERE a <= 'g'::rainbow;
+
+SELECT count(*) FROM enumtmp WHERE a  = 'g'::rainbow;
+
+SELECT count(*) FROM enumtmp WHERE a >= 'g'::rainbow;
+
+SELECT count(*) FROM enumtmp WHERE a >  'g'::rainbow;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM enumtmp WHERE a >= 'g'::rainbow;
diff --git a/contrib/btree_gist/sql/float4_buffering.sql b/contrib/btree_gist/sql/float4_buffering.sql
new file mode 100644
index 00000000000..f0dfa61bde2
--- /dev/null
+++ b/contrib/btree_gist/sql/float4_buffering.sql
@@ -0,0 +1,24 @@
+-- float4 check
+
+DROP TABLE IF EXISTS float4tmp;
+CREATE TABLE float4tmp (a float4);
+
+\copy float4tmp from 'data/float4.data'
+
+CREATE INDEX float4idx ON float4tmp USING gist ( a ) WITH (buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM float4tmp WHERE a <  -179.0::float4;
+
+SELECT count(*) FROM float4tmp WHERE a <= -179.0::float4;
+
+SELECT count(*) FROM float4tmp WHERE a  = -179.0::float4;
+
+SELECT count(*) FROM float4tmp WHERE a >= -179.0::float4;
+
+SELECT count(*) FROM float4tmp WHERE a >  -179.0::float4;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
+SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
diff --git a/contrib/btree_gist/sql/float8_buffering.sql b/contrib/btree_gist/sql/float8_buffering.sql
new file mode 100644
index 00000000000..0f0a0051469
--- /dev/null
+++ b/contrib/btree_gist/sql/float8_buffering.sql
@@ -0,0 +1,24 @@
+-- float8 check
+
+DROP TABLE IF EXISTS float8tmp;
+CREATE TABLE float8tmp (a float8);
+
+\copy float8tmp from 'data/float8.data'
+
+CREATE INDEX float8idx ON float8tmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM float8tmp WHERE a <  -1890.0::float8;
+
+SELECT count(*) FROM float8tmp WHERE a <= -1890.0::float8;
+
+SELECT count(*) FROM float8tmp WHERE a  = -1890.0::float8;
+
+SELECT count(*) FROM float8tmp WHERE a >= -1890.0::float8;
+
+SELECT count(*) FROM float8tmp WHERE a >  -1890.0::float8;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
+SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
diff --git a/contrib/btree_gist/sql/inet_buffering.sql b/contrib/btree_gist/sql/inet_buffering.sql
new file mode 100644
index 00000000000..78e5d583e77
--- /dev/null
+++ b/contrib/btree_gist/sql/inet_buffering.sql
@@ -0,0 +1,38 @@
+-- inet check
+
+DROP TABLE IF EXISTS inettmp;
+CREATE TABLE inettmp (a inet);
+
+\copy inettmp from 'data/inet.data'
+
+CREATE INDEX inetidx ON inettmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM inettmp WHERE a <  '89.225.196.191'::inet;
+
+SELECT count(*) FROM inettmp WHERE a <= '89.225.196.191'::inet;
+
+SELECT count(*) FROM inettmp WHERE a  = '89.225.196.191'::inet;
+
+SELECT count(*) FROM inettmp WHERE a >= '89.225.196.191'::inet;
+
+SELECT count(*) FROM inettmp WHERE a >  '89.225.196.191'::inet;
+
+VACUUM ANALYZE inettmp;
+
+-- gist_inet_ops lacks a fetch function, so this should not be index-only scan
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM inettmp WHERE a  = '89.225.196.191'::inet;
+
+SELECT count(*) FROM inettmp WHERE a  = '89.225.196.191'::inet;
+
+DROP INDEX inetidx;
+
+CREATE INDEX ON inettmp USING gist (a gist_inet_ops, a inet_ops);
+
+-- this can be an index-only scan, as long as the planner uses the right column
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM inettmp WHERE a  = '89.225.196.191'::inet;
+
+SELECT count(*) FROM inettmp WHERE a  = '89.225.196.191'::inet;
diff --git a/contrib/btree_gist/sql/init.sql b/contrib/btree_gist/sql/init.sql
index a6d2cffc677..d2e8f9e094c 100644
--- a/contrib/btree_gist/sql/init.sql
+++ b/contrib/btree_gist/sql/init.sql
@@ -1,3 +1,7 @@
+CREATE EXTENSION injection_points;
+
+SELECT injection_points_attach('btree-gist-sorted-build', 'notice');
+
 CREATE EXTENSION btree_gist;
 
 -- Check whether any of our opclasses fail amvalidate
diff --git a/contrib/btree_gist/sql/int2_buffering.sql b/contrib/btree_gist/sql/int2_buffering.sql
new file mode 100644
index 00000000000..ecc4504b053
--- /dev/null
+++ b/contrib/btree_gist/sql/int2_buffering.sql
@@ -0,0 +1,24 @@
+-- int2 check
+
+DROP TABLE IF EXISTS int2tmp;
+CREATE TABLE int2tmp (a int2);
+
+\copy int2tmp from 'data/int2.data'
+
+CREATE INDEX int2idx ON int2tmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM int2tmp WHERE a <  237::int2;
+
+SELECT count(*) FROM int2tmp WHERE a <= 237::int2;
+
+SELECT count(*) FROM int2tmp WHERE a  = 237::int2;
+
+SELECT count(*) FROM int2tmp WHERE a >= 237::int2;
+
+SELECT count(*) FROM int2tmp WHERE a >  237::int2;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3;
+SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3;
diff --git a/contrib/btree_gist/sql/int4_buffering.sql b/contrib/btree_gist/sql/int4_buffering.sql
new file mode 100644
index 00000000000..1046b646d58
--- /dev/null
+++ b/contrib/btree_gist/sql/int4_buffering.sql
@@ -0,0 +1,24 @@
+-- int4 check
+
+DROP TABLE IF EXISTS int4tmp;
+CREATE TABLE int4tmp (a int4);
+
+\copy int4tmp from 'data/int2.data'
+
+CREATE INDEX int4idx ON int4tmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM int4tmp WHERE a <  237::int4;
+
+SELECT count(*) FROM int4tmp WHERE a <= 237::int4;
+
+SELECT count(*) FROM int4tmp WHERE a  = 237::int4;
+
+SELECT count(*) FROM int4tmp WHERE a >= 237::int4;
+
+SELECT count(*) FROM int4tmp WHERE a >  237::int4;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3;
+SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3;
diff --git a/contrib/btree_gist/sql/int8_buffering.sql b/contrib/btree_gist/sql/int8_buffering.sql
new file mode 100644
index 00000000000..ac5a89854f2
--- /dev/null
+++ b/contrib/btree_gist/sql/int8_buffering.sql
@@ -0,0 +1,24 @@
+-- int8 check
+
+DROP TABLE IF EXISTS int8tmp;
+CREATE TABLE int8tmp (a int8);
+
+\copy int8tmp from 'data/int8.data'
+
+CREATE INDEX int8idx ON int8tmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM int8tmp WHERE a <  464571291354841::int8;
+
+SELECT count(*) FROM int8tmp WHERE a <= 464571291354841::int8;
+
+SELECT count(*) FROM int8tmp WHERE a  = 464571291354841::int8;
+
+SELECT count(*) FROM int8tmp WHERE a >= 464571291354841::int8;
+
+SELECT count(*) FROM int8tmp WHERE a >  464571291354841::int8;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3;
+SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3;
diff --git a/contrib/btree_gist/sql/interval_buffering.sql b/contrib/btree_gist/sql/interval_buffering.sql
new file mode 100644
index 00000000000..23e258f733f
--- /dev/null
+++ b/contrib/btree_gist/sql/interval_buffering.sql
@@ -0,0 +1,30 @@
+-- interval check
+
+DROP TABLE IF EXISTS intervaltmp;
+CREATE TABLE intervaltmp (a interval);
+
+\copy intervaltmp from 'data/interval.data'
+
+CREATE INDEX intervalidx ON intervaltmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM intervaltmp WHERE a <  '199 days 21:21:23'::interval;
+
+SELECT count(*) FROM intervaltmp WHERE a <= '199 days 21:21:23'::interval;
+
+SELECT count(*) FROM intervaltmp WHERE a  = '199 days 21:21:23'::interval;
+
+SELECT count(*) FROM intervaltmp WHERE a >= '199 days 21:21:23'::interval;
+
+SELECT count(*) FROM intervaltmp WHERE a >  '199 days 21:21:23'::interval;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3;
+SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3;
+
+SET enable_indexonlyscan=off;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3;
+SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3;
diff --git a/contrib/btree_gist/sql/macaddr8_buffering.sql b/contrib/btree_gist/sql/macaddr8_buffering.sql
new file mode 100644
index 00000000000..14558c827a7
--- /dev/null
+++ b/contrib/btree_gist/sql/macaddr8_buffering.sql
@@ -0,0 +1,26 @@
+-- macaddr check
+
+DROP TABLE IF EXISTS macaddr8tmp;
+CREATE TABLE macaddr8tmp (a macaddr8);
+
+\copy macaddr8tmp from 'data/macaddr.data'
+
+CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr8;
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
diff --git a/contrib/btree_gist/sql/macaddr_buffering.sql b/contrib/btree_gist/sql/macaddr_buffering.sql
new file mode 100644
index 00000000000..2848ad14f70
--- /dev/null
+++ b/contrib/btree_gist/sql/macaddr_buffering.sql
@@ -0,0 +1,26 @@
+-- macaddr check
+
+DROP TABLE IF EXISTS macaddrtmp;
+CREATE TABLE macaddrtmp (a macaddr);
+
+\copy macaddrtmp from 'data/macaddr.data'
+
+CREATE INDEX macaddridx ON macaddrtmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM macaddrtmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr;
+
+SELECT count(*) FROM macaddrtmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr;
+
+SELECT count(*) FROM macaddrtmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr;
+
+SELECT count(*) FROM macaddrtmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr;
+
+SELECT count(*) FROM macaddrtmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr;
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddrtmp WHERE a < '02:03:04:05:06:07'::macaddr;
+SELECT * FROM macaddrtmp WHERE a < '02:03:04:05:06:07'::macaddr;
diff --git a/contrib/btree_gist/sql/not_equal_buffering.sql b/contrib/btree_gist/sql/not_equal_buffering.sql
new file mode 100644
index 00000000000..7562565f818
--- /dev/null
+++ b/contrib/btree_gist/sql/not_equal_buffering.sql
@@ -0,0 +1,38 @@
+
+SET enable_seqscan to false;
+
+-- test search for "not equals"
+
+DROP TABLE IF EXISTS test_ne;
+CREATE TABLE test_ne (
+   a  TIMESTAMP,
+   b  NUMERIC
+);
+CREATE INDEX test_ne_idx ON test_ne USING gist (a, b) WITH(buffering = on);
+
+INSERT INTO test_ne SELECT '2009-01-01', 10.7 FROM generate_series(1,1000);
+INSERT INTO test_ne VALUES('2007-02-03', -91.3);
+INSERT INTO test_ne VALUES('2011-09-01', 43.7);
+INSERT INTO test_ne SELECT '2009-01-01', 10.7 FROM generate_series(1,1000);
+
+SET enable_indexscan to false;
+
+EXPLAIN (COSTS OFF) SELECT * FROM test_ne WHERE a <> '2009-01-01' AND b <> 10.7;
+
+SELECT * FROM test_ne WHERE a <> '2009-01-01' AND b <> 10.7;
+
+RESET enable_indexscan;
+
+-- test search for "not equals" using an exclusion constraint
+
+DROP TABLE IF EXISTS zoo;
+CREATE TABLE zoo (
+   cage   INTEGER,
+   animal TEXT,
+   EXCLUDE USING gist (cage WITH =, animal WITH <>) WITH(buffering = on)
+);
+
+INSERT INTO zoo VALUES(123, 'zebra');
+INSERT INTO zoo VALUES(123, 'zebra');
+INSERT INTO zoo VALUES(123, 'lion');
+INSERT INTO zoo VALUES(124, 'lion');
diff --git a/contrib/btree_gist/sql/numeric_buffering.sql b/contrib/btree_gist/sql/numeric_buffering.sql
new file mode 100644
index 00000000000..38c8677f579
--- /dev/null
+++ b/contrib/btree_gist/sql/numeric_buffering.sql
@@ -0,0 +1,50 @@
+-- numeric check
+
+DROP TABLE IF EXISTS numerictmp;
+CREATE TABLE numerictmp (a numeric);
+
+\copy numerictmp from 'data/int8.data'
+\copy numerictmp from 'data/numeric.data'
+\copy numerictmp from 'data/float8.data'
+
+CREATE INDEX numericidx ON numerictmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM numerictmp WHERE a <  -1890.0;
+
+SELECT count(*) FROM numerictmp WHERE a <= -1890.0;
+
+SELECT count(*) FROM numerictmp WHERE a  = -1890.0;
+
+SELECT count(*) FROM numerictmp WHERE a >= -1890.0;
+
+SELECT count(*) FROM numerictmp WHERE a >  -1890.0;
+
+
+SELECT count(*) FROM numerictmp WHERE a <  'NaN' ;
+
+SELECT count(*) FROM numerictmp WHERE a <= 'NaN' ;
+
+SELECT count(*) FROM numerictmp WHERE a  = 'NaN' ;
+
+SELECT count(*) FROM numerictmp WHERE a >= 'NaN' ;
+
+SELECT count(*) FROM numerictmp WHERE a >  'NaN' ;
+
+
+SELECT count(*) FROM numerictmp WHERE a <  0 ;
+
+SELECT count(*) FROM numerictmp WHERE a <= 0 ;
+
+SELECT count(*) FROM numerictmp WHERE a  = 0 ;
+
+SELECT count(*) FROM numerictmp WHERE a >= 0 ;
+
+SELECT count(*) FROM numerictmp WHERE a >  0 ;
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM numerictmp WHERE a BETWEEN 1 AND 300 ORDER BY a;
+SELECT * FROM numerictmp WHERE a BETWEEN 1 AND 300 ORDER BY a;
diff --git a/contrib/btree_gist/sql/oid_buffering.sql b/contrib/btree_gist/sql/oid_buffering.sql
new file mode 100644
index 00000000000..17c69d01975
--- /dev/null
+++ b/contrib/btree_gist/sql/oid_buffering.sql
@@ -0,0 +1,18 @@
+-- oid check
+
+CREATE TEMPORARY TABLE oidtmp (oid oid);
+INSERT INTO oidtmp SELECT g.i::oid FROM generate_series(1, 1000) g(i);
+
+CREATE INDEX oididx ON oidtmp USING gist ( oid ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM oidtmp WHERE oid <  17;
+
+SELECT count(*) FROM oidtmp WHERE oid <= 17;
+
+SELECT count(*) FROM oidtmp WHERE oid  = 17;
+
+SELECT count(*) FROM oidtmp WHERE oid >= 17;
+
+SELECT count(*) FROM oidtmp WHERE oid >  17;
diff --git a/contrib/btree_gist/sql/partitions.sql b/contrib/btree_gist/sql/partitions.sql
index 6265c10121f..93442bb6d26 100644
--- a/contrib/btree_gist/sql/partitions.sql
+++ b/contrib/btree_gist/sql/partitions.sql
@@ -2,6 +2,9 @@
 -- across a partitioned table.
 -- That code looks at strategy numbers that can differ in regular gist vs btree_gist,
 -- so we want to make sure it works here too.
+--
+-- Note that this also checks sorted builds for btree_gist and rangetypes.
+
 create table parttmp (
   id int,
   valid_at daterange,
diff --git a/contrib/btree_gist/sql/partitions_buffering.sql b/contrib/btree_gist/sql/partitions_buffering.sql
new file mode 100644
index 00000000000..6150f10941a
--- /dev/null
+++ b/contrib/btree_gist/sql/partitions_buffering.sql
@@ -0,0 +1,42 @@
+drop table if exists parttmp;
+
+-- Make sure we can create an exclusion constraint
+-- across a partitioned table.
+-- That code looks at strategy numbers that can differ in regular gist vs btree_gist,
+-- so we want to make sure it works here too.
+
+create table parttmp (
+  id int,
+  valid_at daterange,
+  exclude using gist (id with =, valid_at with &&) with(buffering = on)
+) partition by range (id);
+
+create table parttmp_1_to_10 partition of parttmp for values from (1) to (10);
+create table parttmp_11_to_20 partition of parttmp for values from (11) to (20);
+
+insert into parttmp (id, valid_at) values
+  (1, '[2000-01-01, 2000-02-01)'),
+  (1, '[2000-02-01, 2000-03-01)'),
+  (2, '[2000-01-01, 2000-02-01)'),
+  (11, '[2000-01-01, 2000-02-01)'),
+  (11, '[2000-02-01, 2000-03-01)'),
+  (12, '[2000-01-01, 2000-02-01)');
+
+select * from parttmp order by id, valid_at;
+select * from parttmp_1_to_10 order by id, valid_at;
+select * from parttmp_11_to_20 order by id, valid_at;
+
+update parttmp set valid_at = valid_at * '[2000-01-15,2000-02-15)' where id = 1;
+
+select * from parttmp order by id, valid_at;
+select * from parttmp_1_to_10 order by id, valid_at;
+select * from parttmp_11_to_20 order by id, valid_at;
+
+-- make sure the excluson constraint excludes:
+insert into parttmp (id, valid_at) values
+  (2, '[2000-01-15, 2000-02-01)');
+
+drop table parttmp;
+
+-- should fail with a good error message:
+create table parttmp (id int, valid_at daterange, exclude using gist (id with <>, valid_at with &&) with (buffering = on)) partition by range (id);
diff --git a/contrib/btree_gist/sql/text_buffering.sql b/contrib/btree_gist/sql/text_buffering.sql
new file mode 100644
index 00000000000..cc598e4b1fa
--- /dev/null
+++ b/contrib/btree_gist/sql/text_buffering.sql
@@ -0,0 +1,28 @@
+-- text check
+DROP TABLE IF EXISTS texttmp;
+CREATE TABLE texttmp (a text);
+
+\copy texttmp from 'data/text.data'
+\copy texttmp from 'data/char.data'
+
+CREATE INDEX textidx ON texttmp USING GIST ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM texttmp WHERE a <   '31b0'::text;
+
+SELECT count(*) FROM texttmp WHERE a <=  '31b0'::text;
+
+SELECT count(*) FROM texttmp WHERE a  =  '31b0'::text;
+
+SELECT count(*) FROM texttmp WHERE a >=  '31b0'::text;
+
+SELECT count(*) FROM texttmp WHERE a >   '31b0'::text;
+
+SELECT count(*) FROM texttmp WHERE a  =  '2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809 2eb2c961c1cbf6 cf8d7b68cb9a2f36 7bbedb4ae7 06ec46c55611a466eb7e3edcc009ca6 e 5ed9cd0ea5a4e55d601027c56a  64cacf3a42afc 90e63000c34506993345355640 79bce 173bb7 c5 574ea7c921cb0f25 089d56d16dff24f336e4740 6870470f1f9afcb4f7c56c9f b97e117fc965 7013029 e48f6dd481 7d00e1e227beef84a9 904d4c34241f cb5c0f14 3a8a70 f51a73164e92052fbb53b4cc2f1fed 3c3fecaa0270175 2521ef03594 fa05756812648f450fb 13c2f b39a0729d6182e9 15b5ea204fe73 d8991afd72d21acd188df1 a29fff57ab897338 de549b3ed5a024534c007125c 2fcf3e5c3e3 7427b6daec5c3f 473 8 a5d9 840410976ac2eeab58e1ca8bf46c2b7 1db9cc85a336f1291ea19922 db808f3548cda91 2e379ce80af12bd7ed56d0338c a ea67a7c847f6620fc894f0ba10044 0e 52e97d975af7201d8 d95e6f08184d8ff 19762476fa 42f278f3534f3f2be0abaed71 f0aba11835e4e1d94 e8534cf677046eafb8f5f761865 ffbee273c7bb 2bb77f6e780 c77e81851c491 e a9f45d765b01a030d5d317 ff7345a22bc360 c87363ba121297b063e83 13ea32e9618d 40304f6c2a7e92c1c66ff4208e a781b4a21419abfdf5eb467e4d48908 8a65656e514b2b3ef8f86310aaf85 4 90b7b2862e3dbc8f0eef3dfc6075bfa eb94a1c a58abb5def4fa43840e6e2716 260e6eaebb 42415d712bf83944dcd1204e 305254fc3b849150b5 5bbd7f8471dcd3621 2ae0548115a250 0c1988e9 76f98bef45639b7 0d5a28f01dc b71 c046576faa4d49eff8 c1e8d01c 10c86c457ea050455a742da4f8 ea7676af85c71c7eeca635 6a07137227404d a4 7186172 8150f31c9a15401c f1bb9057a9938bfa 22b482be08f424ec4 21daea994293589 15bff393f6b17fef24786dd6f9 d5a2d 4b3b5dd9370543e b4a93b2ac4341945d06 d384447812e0 4e3c97e9b8f7 f7d4d644b2a1d373 5102c b9531f725674b28 1aa16e7e34285797c1439 51aa762ea14b40fb8876c887eea6 45a62d3d5d3e946250904697486591 b3f1a8 243524767bf846d 8 95 45a922872 dd2497eb1e3da8d513d2 7821db9e14d4f 24c4f085de60d7c0c6ea3fc6bc e4c9f8c68596d7d afd6c8cb0f2516b87f24bbd8 61d2e457c70949 d2d362cdc657 3605f9d27fd6d72 32de91d66fe5bf537530 859e1a08b65 9b5a55f 4116cda9fddeb843964002 e81f3b2c0ca566ad3dbbc6e234 0d3b1d54 10c440be5c0bca95 7dad841f a61f041967972e805ccfee55c deee9cc16e92ab197 7627554073c1f56b9e 21bebcbfd2e2282f84 7b121a83eeb91db8bda81ba88c634b46394 59885ebc737617addaaf0cb809'::text;
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM texttmp WHERE a BETWEEN '31a' AND '31c';
+SELECT * FROM texttmp WHERE a BETWEEN '31a' AND '31c';
diff --git a/contrib/btree_gist/sql/time_buffering.sql b/contrib/btree_gist/sql/time_buffering.sql
new file mode 100644
index 00000000000..2b206195d6a
--- /dev/null
+++ b/contrib/btree_gist/sql/time_buffering.sql
@@ -0,0 +1,24 @@
+-- time check
+
+DROP TABLE IF EXISTS timetmp;
+CREATE TABLE timetmp (a time);
+
+\copy timetmp from 'data/time.data'
+
+CREATE INDEX timeidx ON timetmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM timetmp WHERE a <  '10:57:11'::time;
+
+SELECT count(*) FROM timetmp WHERE a <= '10:57:11'::time;
+
+SELECT count(*) FROM timetmp WHERE a  = '10:57:11'::time;
+
+SELECT count(*) FROM timetmp WHERE a >= '10:57:11'::time;
+
+SELECT count(*) FROM timetmp WHERE a >  '10:57:11'::time;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3;
+SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3;
diff --git a/contrib/btree_gist/sql/timestamp_buffering.sql b/contrib/btree_gist/sql/timestamp_buffering.sql
new file mode 100644
index 00000000000..7bf678386ae
--- /dev/null
+++ b/contrib/btree_gist/sql/timestamp_buffering.sql
@@ -0,0 +1,24 @@
+-- timestamp check
+
+DROP TABLE IF EXISTS timestamptmp;
+CREATE TABLE timestamptmp (a timestamp);
+
+\copy timestamptmp from 'data/timestamp.data'
+
+CREATE INDEX timestampidx ON timestamptmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM timestamptmp WHERE a <  '2004-10-26 08:55:08'::timestamp;
+
+SELECT count(*) FROM timestamptmp WHERE a <= '2004-10-26 08:55:08'::timestamp;
+
+SELECT count(*) FROM timestamptmp WHERE a  = '2004-10-26 08:55:08'::timestamp;
+
+SELECT count(*) FROM timestamptmp WHERE a >= '2004-10-26 08:55:08'::timestamp;
+
+SELECT count(*) FROM timestamptmp WHERE a >  '2004-10-26 08:55:08'::timestamp;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3;
+SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3;
diff --git a/contrib/btree_gist/sql/timestamptz_buffering.sql b/contrib/btree_gist/sql/timestamptz_buffering.sql
new file mode 100644
index 00000000000..d658384b7df
--- /dev/null
+++ b/contrib/btree_gist/sql/timestamptz_buffering.sql
@@ -0,0 +1,46 @@
+-- timestamptz check
+
+DROP TABLE IF EXISTS timestamptztmp;
+CREATE TABLE timestamptztmp (a timestamptz);
+
+\copy timestamptztmp from 'data/timestamptz.data'
+
+CREATE INDEX timestamptzidx ON timestamptztmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM timestamptztmp WHERE a <  '2018-12-18 10:59:54 GMT+3'::timestamptz;
+
+SELECT count(*) FROM timestamptztmp WHERE a <= '2018-12-18 10:59:54 GMT+3'::timestamptz;
+
+SELECT count(*) FROM timestamptztmp WHERE a  = '2018-12-18 10:59:54 GMT+3'::timestamptz;
+
+SELECT count(*) FROM timestamptztmp WHERE a >= '2018-12-18 10:59:54 GMT+3'::timestamptz;
+
+SELECT count(*) FROM timestamptztmp WHERE a >  '2018-12-18 10:59:54 GMT+3'::timestamptz;
+
+
+SELECT count(*) FROM timestamptztmp WHERE a <  '2018-12-18 10:59:54 GMT+2'::timestamptz;
+
+SELECT count(*) FROM timestamptztmp WHERE a <= '2018-12-18 10:59:54 GMT+2'::timestamptz;
+
+SELECT count(*) FROM timestamptztmp WHERE a  = '2018-12-18 10:59:54 GMT+2'::timestamptz;
+
+SELECT count(*) FROM timestamptztmp WHERE a >= '2018-12-18 10:59:54 GMT+2'::timestamptz;
+
+SELECT count(*) FROM timestamptztmp WHERE a >  '2018-12-18 10:59:54 GMT+2'::timestamptz;
+
+
+SELECT count(*) FROM timestamptztmp WHERE a <  '2018-12-18 10:59:54 GMT+4'::timestamptz;
+
+SELECT count(*) FROM timestamptztmp WHERE a <= '2018-12-18 10:59:54 GMT+4'::timestamptz;
+
+SELECT count(*) FROM timestamptztmp WHERE a  = '2018-12-18 10:59:54 GMT+4'::timestamptz;
+
+SELECT count(*) FROM timestamptztmp WHERE a >= '2018-12-18 10:59:54 GMT+4'::timestamptz;
+
+SELECT count(*) FROM timestamptztmp WHERE a >  '2018-12-18 10:59:54 GMT+4'::timestamptz;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3;
+SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3;
diff --git a/contrib/btree_gist/sql/timetz_buffering.sql b/contrib/btree_gist/sql/timetz_buffering.sql
new file mode 100644
index 00000000000..a7c797b9614
--- /dev/null
+++ b/contrib/btree_gist/sql/timetz_buffering.sql
@@ -0,0 +1,85 @@
+-- timetz check
+
+DROP TABLE IF EXISTS timetztmp;
+DROP TABLE IF EXISTS timetzcmp;
+
+CREATE TABLE timetztmp (a timetz);
+\copy timetztmp from 'data/timetz.data'
+
+CREATE TABLE timetzcmp ( r_id int2, a int4, b int4 );
+
+
+SET enable_seqscan=on;
+
+INSERT INTO timetzcmp (r_id,a) SELECT  1,count(*) FROM timetztmp WHERE a <  '07:46:45 GMT+3';
+
+INSERT INTO timetzcmp (r_id,a) SELECT  2,count(*) FROM timetztmp WHERE a <= '07:46:45 GMT+3';
+
+INSERT INTO timetzcmp (r_id,a) SELECT  3,count(*) FROM timetztmp WHERE a  = '07:46:45 GMT+3';
+
+INSERT INTO timetzcmp (r_id,a) SELECT  4,count(*) FROM timetztmp WHERE a >= '07:46:45 GMT+3';
+
+INSERT INTO timetzcmp (r_id,a) SELECT  5,count(*) FROM timetztmp WHERE a >  '07:46:45 GMT+3';
+
+
+INSERT INTO timetzcmp (r_id,a) SELECT 11,count(*) FROM timetztmp WHERE a <  '07:46:45 GMT+2';
+
+INSERT INTO timetzcmp (r_id,a) SELECT 12,count(*) FROM timetztmp WHERE a <= '07:46:45 GMT+2';
+
+INSERT INTO timetzcmp (r_id,a) SELECT 13,count(*) FROM timetztmp WHERE a  = '07:46:45 GMT+2';
+
+INSERT INTO timetzcmp (r_id,a) SELECT 14,count(*) FROM timetztmp WHERE a >= '07:46:45 GMT+2';
+
+INSERT INTO timetzcmp (r_id,a) SELECT 15,count(*) FROM timetztmp WHERE a >  '07:46:45 GMT+2';
+
+
+INSERT INTO timetzcmp (r_id,a) SELECT 21,count(*) FROM timetztmp WHERE a <  '07:46:45 GMT+4';
+
+INSERT INTO timetzcmp (r_id,a) SELECT 22,count(*) FROM timetztmp WHERE a <= '07:46:45 GMT+4';
+
+INSERT INTO timetzcmp (r_id,a) SELECT 23,count(*) FROM timetztmp WHERE a  = '07:46:45 GMT+4';
+
+INSERT INTO timetzcmp (r_id,a) SELECT 24,count(*) FROM timetztmp WHERE a >= '07:46:45 GMT+4';
+
+INSERT INTO timetzcmp (r_id,a) SELECT 25,count(*) FROM timetztmp WHERE a >  '07:46:45 GMT+4';
+
+
+
+CREATE INDEX timetzidx ON timetztmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a <  '07:46:45 GMT+3'::timetz ) q WHERE r_id=1 ;
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a <= '07:46:45 GMT+3'::timetz ) q WHERE r_id=2 ;
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a  = '07:46:45 GMT+3'::timetz ) q WHERE r_id=3 ;
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a >= '07:46:45 GMT+3'::timetz ) q WHERE r_id=4 ;
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a >  '07:46:45 GMT+3'::timetz ) q WHERE r_id=5 ;
+
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a <  '07:46:45 GMT+2'::timetz ) q WHERE r_id=11 ;
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a <= '07:46:45 GMT+2'::timetz ) q WHERE r_id=12 ;
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a  = '07:46:45 GMT+2'::timetz ) q WHERE r_id=13 ;
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a >= '07:46:45 GMT+2'::timetz ) q WHERE r_id=14 ;
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a >  '07:46:45 GMT+2'::timetz ) q WHERE r_id=15 ;
+
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a <  '07:46:45 GMT+4'::timetz ) q WHERE r_id=21 ;
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a <= '07:46:45 GMT+4'::timetz ) q WHERE r_id=22 ;
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a  = '07:46:45 GMT+4'::timetz ) q WHERE r_id=23 ;
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a >= '07:46:45 GMT+4'::timetz ) q WHERE r_id=24 ;
+
+UPDATE timetzcmp SET b=c FROM ( SELECT count(*) AS c FROM timetztmp WHERE a >  '07:46:45 GMT+4'::timetz ) q WHERE r_id=25 ;
+
+
+SELECT count(*) FROM timetzcmp WHERE a=b;
diff --git a/contrib/btree_gist/sql/uuid_buffering.sql b/contrib/btree_gist/sql/uuid_buffering.sql
new file mode 100644
index 00000000000..963368c4d6f
--- /dev/null
+++ b/contrib/btree_gist/sql/uuid_buffering.sql
@@ -0,0 +1,20 @@
+-- uuid check
+
+DROP TABLE IF EXISTS uuidtmp;
+CREATE TABLE uuidtmp (a uuid);
+
+\copy uuidtmp from 'data/uuid.data'
+
+CREATE INDEX uuididx ON uuidtmp USING gist ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM uuidtmp WHERE a <  '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
+
+SELECT count(*) FROM uuidtmp WHERE a <= '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
+
+SELECT count(*) FROM uuidtmp WHERE a  = '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
+
+SELECT count(*) FROM uuidtmp WHERE a >= '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
+
+SELECT count(*) FROM uuidtmp WHERE a >  '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
diff --git a/contrib/btree_gist/sql/varbit_buffering.sql b/contrib/btree_gist/sql/varbit_buffering.sql
new file mode 100644
index 00000000000..7d68caff69f
--- /dev/null
+++ b/contrib/btree_gist/sql/varbit_buffering.sql
@@ -0,0 +1,25 @@
+-- varbit check
+
+DROP TABLE IF EXISTS varbittmp;
+CREATE TABLE varbittmp (a varbit);
+
+\copy varbittmp from 'data/varbit.data'
+
+CREATE INDEX varbitidx ON varbittmp USING GIST ( a ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM varbittmp WHERE a <   '1110100111010'::varbit;
+
+SELECT count(*) FROM varbittmp WHERE a <=  '1110100111010'::varbit;
+
+SELECT count(*) FROM varbittmp WHERE a  =  '1110100111010'::varbit;
+
+SELECT count(*) FROM varbittmp WHERE a >=  '1110100111010'::varbit;
+
+SELECT count(*) FROM varbittmp WHERE a >   '1110100111010'::varbit;
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT a FROM bittmp WHERE a BETWEEN '1000000' and '1000001';
diff --git a/contrib/btree_gist/sql/varchar_buffering.sql b/contrib/btree_gist/sql/varchar_buffering.sql
new file mode 100644
index 00000000000..303de9825fb
--- /dev/null
+++ b/contrib/btree_gist/sql/varchar_buffering.sql
@@ -0,0 +1,20 @@
+-- char check
+
+DROP TABLE IF EXISTS vchartmp;
+CREATE TABLE vchartmp (a varchar(32));
+
+\copy vchartmp from 'data/char.data'
+
+CREATE INDEX vcharidx ON vchartmp USING GIST ( text(a) ) WITH(buffering = on);
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM vchartmp WHERE a <   '31b0'::varchar(32);
+
+SELECT count(*) FROM vchartmp WHERE a <=  '31b0'::varchar(32);
+
+SELECT count(*) FROM vchartmp WHERE a  =  '31b0'::varchar(32);
+
+SELECT count(*) FROM vchartmp WHERE a >=  '31b0'::varchar(32);
+
+SELECT count(*) FROM vchartmp WHERE a >   '31b0'::varchar(32);
diff --git a/contrib/btree_gist/sql/without_overlaps_buffering.sql b/contrib/btree_gist/sql/without_overlaps_buffering.sql
new file mode 100644
index 00000000000..fb278c51633
--- /dev/null
+++ b/contrib/btree_gist/sql/without_overlaps_buffering.sql
@@ -0,0 +1,56 @@
+-- Core must test WITHOUT OVERLAPS
+-- with an int4range + daterange,
+-- so here we do some simple tests
+-- to make sure int + daterange works too,
+-- since that is the expected use-case.
+
+DROP TABLE IF EXISTS temporal_rng CASCADE ;
+
+CREATE TABLE temporal_rng (
+  id integer,
+  valid_at daterange,
+  CONSTRAINT temporal_rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) WITH(buffering=on)
+);
+\d temporal_rng
+SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'temporal_rng_pk';
+SELECT pg_get_indexdef(conindid, 0, true) FROM pg_constraint WHERE conname = 'temporal_rng_pk';
+
+INSERT INTO temporal_rng VALUES
+  (1, '[2000-01-01,2001-01-01)');
+-- same key, doesn't overlap:
+INSERT INTO temporal_rng VALUES
+  (1, '[2001-01-01,2002-01-01)');
+-- overlaps but different key:
+INSERT INTO temporal_rng VALUES
+  (2, '[2000-01-01,2001-01-01)');
+-- should fail:
+INSERT INTO temporal_rng VALUES
+  (1, '[2000-06-01,2001-01-01)');
+
+-- Foreign key
+CREATE TABLE temporal_fk_rng2rng (
+  id integer,
+  valid_at daterange,
+  parent_id integer,
+  CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) WITH(buffering=on),
+  CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, PERIOD valid_at)
+    REFERENCES temporal_rng (id, PERIOD valid_at)
+);
+\d temporal_fk_rng2rng
+SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'temporal_fk_rng2rng_fk';
+
+-- okay
+INSERT INTO temporal_fk_rng2rng VALUES
+  (1, '[2000-01-01,2001-01-01)', 1);
+-- okay spanning two parent records:
+INSERT INTO temporal_fk_rng2rng VALUES
+  (2, '[2000-01-01,2002-01-01)', 1);
+-- key is missing
+INSERT INTO temporal_fk_rng2rng VALUES
+  (3, '[2000-01-01,2001-01-01)', 3);
+-- key exist but is outside range
+INSERT INTO temporal_fk_rng2rng VALUES
+  (4, '[2001-01-01,2002-01-01)', 2);
+-- key exist but is partly outside range
+INSERT INTO temporal_fk_rng2rng VALUES
+  (5, '[2000-01-01,2002-01-01)', 2);
diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index 31e7c78aaef..5edc2d8e43e 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -52,6 +52,13 @@
   <type>oid</type>, and <type>money</type>.
  </para>
 
+ <para>
+  By default <filename>btree_gist</filename> builds <acronym>GiST</acronym> index with
+  <function>sortsupport</function> in <firstterm>sorted</firstterm> mode. This usually results in
+  smaller index sizes and much faster index built speed. It is still possible to revert to buffered
+  built strategy by using the <literal>buffering</literal> parameter when creating the index.
+ </para>
+
  <para>
   This module is considered <quote>trusted</quote>, that is, it can be
   installed by non-superusers who have <literal>CREATE</literal> privilege
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index cb28e9859ab..b0c77390024 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -21,6 +21,7 @@
 #include "utils/fmgrprotos.h"
 #include "utils/multirangetypes.h"
 #include "utils/rangetypes.h"
+#include "utils/sortsupport.h"
 
 /*
 
+/*
 
+/*
+ * similar to range_cmp, but range typcache is cached.
+	if (typcache == NULL)
+	{
+	{
+		if (result == 0)
+			result = range_cmp_bounds(typcache, &upper1, &upper2);
index 5d7fe292bf6..c73a3243b65 100644
@@ -606,6 +606,9 @@
   amprocrighttype => 'anyrange', amprocnum => '12',
   amproc => 'gist_stratnum_identity' },
index 1ec0d6f6b5f..f019a59b6bc 100644
@@ -10768,6 +10768,9 @@

---

From: "Andrey M. Borodin" <[email-masked]>
Date: Mon, 11 Nov 2024 23:03:36 +0500

> On 11 Nov 2024, at 21:41, Bernd Helmle <[email-masked]> wrote:
> 
> Updated and rebased patches attached.

Hi Bernd!

Some nitpicking:
0. postgres % git apply ~/Downloads/v7.3-Add-GIST-sortsupport-*
/Users/x4mmm/Downloads/v7.3-Add-GIST-sortsupport-btree-gist.patch:19: space before tab in indent.
    oid oid_buffering timestamp timestamp_buffering timestamptz \
/Users/x4mmm/Downloads/v7.3-Add-GIST-sortsupport-btree-gist.patch:20: space before tab in indent.
    timestamptz_buffering time time_buffering timetz timetz_buffering date \
/Users/x4mmm/Downloads/v7.3-Add-GIST-sortsupport-btree-gist.patch:21: space before tab in indent.
    date_buffering interval interval_buffering macaddr macaddr_buffering \
/Users/x4mmm/Downloads/v7.3-Add-GIST-sortsupport-btree-gist.patch:22: space before tab in indent.
    macaddr8 macaddr8_buffering inet inet_buffering cidr cidr_buffering text \
/Users/x4mmm/Downloads/v7.3-Add-GIST-sortsupport-btree-gist.patch:23: space before tab in indent.
    text_buffering varchar varchar_buffering char char_buffering \
warning: 5 lines add whitespace errors.

1. I'm mostly seening patches formatted with `git patch-format` rather than diffs as patches...

2. Changes in contrib/btree_gist/btree_gist.c seem unnecessary.

3. Why do you move "typedef struct int32key" to btree_gist.h, but do not need to move all other keys?

4. These ifdedfs are not needed, just do INJECTION_POINT()
#ifdef USE_INJECTION_POINTS
INJECTION_POINT("btree-gist-sorted-build");
#endif

Also, there are 61 occurance of this code. Why not just 1 in gist_indexsortbuild() ?

Thanks!

---

From: Bernd Helmle <[email-masked]>
Date: Tue, 12 Nov 2024 16:43:50 +0100

> space before tab in indent.

I obviously shouldn't do patches after a long work day....

[...]

> rather than diffs as patches...

Will do.

> 2. Changes in contrib/btree_gist/btree_gist.c seem unnecessary.

Agreed. Will fix

> not need to move all other keys?

Hmm, afair i did this back in an earlier stage of the patch and forgot
about it. It needs to be moved back to btree_int4.c, will fix.

> INJECTION_POINT("btree-gist-sorted-build");

I never worked with injection points before, i copied that pattern from
the docs somewhere, where those #ifdef's are used. Will fix.

> Also, there are 61 occurance of this code. Why not just 1 in

Right, but after thinking about this i'd even go further: naming the
injection points for the sortsupport according to their datatype
they're called on. That would connect the regression test with the
specific datatype/sortsupport function and this would make sure the
correct sortsupport function for the specific test case is called.
Though that means that each test needs to attach/detach the injection
point itself...

What do you think?

Thanks,
	Bernd

---

From: Bernd Helmle <[email-masked]>
Date: Mon, 25 Nov 2024 16:40:55 +0100

Am Dienstag, dem 12.11.2024 um 16:43 +0100 schrieb Bernd Helmle:
> > /Users/x4mmm/Downloads/v7.3-Add-GIST-sortsupport-btree-
> > gist.patch:19:
> > space before tab in indent.
> 

Attached a new version of this patch. Note that i have combined the
previously separated patches for range types (patch to the backend) and
btree_gist into a single patch, since with the introduction of the
injection point "gist-sorted-build" this doesn't pass CI properly since
they're dependant now, which doesn't look very nice to me.

> > rather than diffs as patches...

Workflow adjusted.

> > 2. Changes in contrib/btree_gist/btree_gist.c seem unnecessary.

Done

> 
> > 3. Why do you move "typedef struct int32key" to btree_gist.h, but
> > do
> > not need to move all other keys?

> about it. It needs to be moved back to btree_int4.c, will fix.

Done. Moved back to its original place.

> > INJECTION_POINT("btree-gist-sorted-build");

Done, see below, too.

> Though that means that each test needs to attach/detach the injection

I've done it along your recommendation now. I followed the argument
that this way is far far less invasive from a code change perspective
and probably enough to check that sortsupport is used.

I've also spotted some oversights in the regression tests of the former
version of the patch, where i forgot to address the injection point
output in alternate expected files (char_1, text_1, ...) which are
created because of locale differences some time ago. This version also
addresses these.

Thanks,
	Bernd

From 7f1f5bc90a9052f2aaa5a961b119d156e44f8fbc Mon Sep 17 00:00:00 2001
From: Bernd Helmle <Bernd Helmle [email-masked]>
Date: Mon, 25 Nov 2024 16:37:12 +0100
Subject: [PATCH] Add support for sorted gist index builds to btree_gist
 extension.

This enables sortsupport in the btree_gist extension for faster
builds of gist indexes. Additionally sortsupport is also added for range types
to the backend so that gist indexes on range types also benefit from the
speed up.

Regression tests are extended to test sortsupport by using a new injection point
"gist-sorted-build" in gist_indexsortbuild(), which is currently enabled by
btree_gist regression test script (see init.sql and cleanup.sql).
---
 contrib/btree_gist/Makefile                   |  23 ++-
 contrib/btree_gist/btree_bit.c                |  46 +++++
 contrib/btree_gist/btree_bool.c               |  22 ++
 contrib/btree_gist/btree_bytea.c              |  35 ++++
 contrib/btree_gist/btree_cash.c               |  27 +++
 contrib/btree_gist/btree_date.c               |  25 +++
 contrib/btree_gist/btree_enum.c               |  33 +++
 contrib/btree_gist/btree_float4.c             |  28 +++
 contrib/btree_gist/btree_float8.c             |  27 +++
 contrib/btree_gist/btree_gist--1.8--1.9.sql   | 192 ++++++++++++++++++
 contrib/btree_gist/btree_gist.control         |   2 +-
 contrib/btree_gist/btree_gist.h               |   1 +
 contrib/btree_gist/btree_inet.c               |  27 +++
 contrib/btree_gist/btree_int2.c               |  26 +++
 contrib/btree_gist/btree_int4.c               |  33 ++-
 contrib/btree_gist/btree_int8.c               |  26 +++
 contrib/btree_gist/btree_interval.c           |  25 +++
 contrib/btree_gist/btree_macaddr.c            |  29 +++
 contrib/btree_gist/btree_macaddr8.c           |  24 +++
 contrib/btree_gist/btree_numeric.c            |  33 +++
 contrib/btree_gist/btree_oid.c                |  28 +++
 contrib/btree_gist/btree_text.c               |  34 ++++
 contrib/btree_gist/btree_time.c               |  26 +++
 contrib/btree_gist/btree_ts.c                 |  25 +++
 contrib/btree_gist/btree_utils_var.h          |  12 +-
 contrib/btree_gist/btree_uuid.c               |  25 +++
 contrib/btree_gist/expected/bit.out           |   1 +
 contrib/btree_gist/expected/bit_buffering.out |  46 +++++
 contrib/btree_gist/expected/bool.out          |   1 +
 .../btree_gist/expected/bool_buffering.out    |  66 ++++++
 contrib/btree_gist/expected/bytea.out         |   1 +
 .../btree_gist/expected/bytea_buffering.out   |  60 ++++++
 contrib/btree_gist/expected/cash.out          |   1 +
 .../btree_gist/expected/cash_buffering.out    |  53 +++++
 contrib/btree_gist/expected/char.out          |   1 +
 contrib/btree_gist/expected/char_1.out        |   1 +
 .../btree_gist/expected/char_buffering.out    |  52 +++++
 .../btree_gist/expected/char_buffering_1.out  |  52 +++++
 .../btree_gist/expected/cidr_buffering.out    |  36 ++++
 contrib/btree_gist/expected/cleanup.out       |   6 +
 contrib/btree_gist/expected/date.out          |   1 +
 .../btree_gist/expected/date_buffering.out    |  53 +++++
 contrib/btree_gist/expected/enum.out          |   1 +
 .../btree_gist/expected/enum_buffering.out    |  47 +++++
 contrib/btree_gist/expected/float4.out        |   1 +
 .../btree_gist/expected/float4_buffering.out  |  53 +++++
 contrib/btree_gist/expected/float8.out        |   1 +
 .../btree_gist/expected/float8_buffering.out  |  53 +++++
 contrib/btree_gist/expected/inet.out          |   1 +
 .../btree_gist/expected/inet_buffering.out    |  71 +++++++
 contrib/btree_gist/expected/init.out          |   7 +
 contrib/btree_gist/expected/int2.out          |   1 +
 .../btree_gist/expected/int2_buffering.out    |  53 +++++
 contrib/btree_gist/expected/int4.out          |   1 +
 .../btree_gist/expected/int4_buffering.out    |  53 +++++
 contrib/btree_gist/expected/int8.out          |   1 +
 .../btree_gist/expected/int8_buffering.out    |  53 +++++
 contrib/btree_gist/expected/interval.out      |   1 +
 .../expected/interval_buffering.out           |  71 +++++++
 contrib/btree_gist/expected/macaddr.out       |   1 +
 contrib/btree_gist/expected/macaddr8.out      |   1 +
 .../expected/macaddr8_buffering.out           |  59 ++++++
 .../btree_gist/expected/macaddr_buffering.out |  59 ++++++
 contrib/btree_gist/expected/not_equal.out     |   2 +
 .../expected/not_equal_buffering.out          |  43 ++++
 contrib/btree_gist/expected/numeric.out       |   1 +
 .../btree_gist/expected/numeric_buffering.out | 117 +++++++++++
 contrib/btree_gist/expected/oid.out           |   1 +
 contrib/btree_gist/expected/oid_buffering.out |  35 ++++
 contrib/btree_gist/expected/partitions.out    |   4 +
 .../expected/partitions_buffering.out         |  84 ++++++++
 contrib/btree_gist/expected/text.out          |   1 +
 contrib/btree_gist/expected/text_1.out        |   1 +
 .../btree_gist/expected/text_buffering.out    |  59 ++++++
 .../btree_gist/expected/text_buffering_1.out  |  59 ++++++
 contrib/btree_gist/expected/time.out          |   1 +
 .../btree_gist/expected/time_buffering.out    |  53 +++++
 contrib/btree_gist/expected/timestamp.out     |   1 +
 .../expected/timestamp_buffering.out          |  53 +++++
 contrib/btree_gist/expected/timestamptz.out   |   1 +
 .../expected/timestamptz_buffering.out        | 113 +++++++++++
 contrib/btree_gist/expected/timetz.out        |   1 +
 .../btree_gist/expected/timetz_buffering.out  |  45 ++++
 contrib/btree_gist/expected/uuid.out          |   1 +
 .../btree_gist/expected/uuid_buffering.out    |  36 ++++
 contrib/btree_gist/expected/varbit.out        |   1 +
 .../btree_gist/expected/varbit_buffering.out  |  46 +++++
 contrib/btree_gist/expected/varchar.out       |   1 +
 contrib/btree_gist/expected/varchar_1.out     |   1 +
 .../btree_gist/expected/varchar_buffering.out |  36 ++++
 .../expected/varchar_buffering_1.out          |  36 ++++
 .../btree_gist/expected/without_overlaps.out  |   2 +
 .../expected/without_overlaps_buffering.out   |  90 ++++++++
 contrib/btree_gist/meson.build                |  33 +++
 contrib/btree_gist/sql/bit_buffering.sql      |  25 +++
 contrib/btree_gist/sql/bool_buffering.sql     |  31 +++
 contrib/btree_gist/sql/bytea_buffering.sql    |  29 +++
 contrib/btree_gist/sql/cash_buffering.sql     |  24 +++
 contrib/btree_gist/sql/char_buffering.sql     |  26 +++
 contrib/btree_gist/sql/cidr_buffering.sql     |  19 ++
 contrib/btree_gist/sql/cleanup.sql            |   1 +
 contrib/btree_gist/sql/date_buffering.sql     |  24 +++
 contrib/btree_gist/sql/enum_buffering.sql     |  23 +++
 contrib/btree_gist/sql/float4_buffering.sql   |  24 +++
 contrib/btree_gist/sql/float8_buffering.sql   |  24 +++
 contrib/btree_gist/sql/inet_buffering.sql     |  38 ++++
 contrib/btree_gist/sql/init.sql               |   4 +
 contrib/btree_gist/sql/int2_buffering.sql     |  24 +++
 contrib/btree_gist/sql/int4_buffering.sql     |  24 +++
 contrib/btree_gist/sql/int8_buffering.sql     |  24 +++
 contrib/btree_gist/sql/interval_buffering.sql |  30 +++
 contrib/btree_gist/sql/macaddr8_buffering.sql |  26 +++
 contrib/btree_gist/sql/macaddr_buffering.sql  |  26 +++
 .../btree_gist/sql/not_equal_buffering.sql    |  38 ++++
 contrib/btree_gist/sql/numeric_buffering.sql  |  50 +++++
 contrib/btree_gist/sql/oid_buffering.sql      |  18 ++
 contrib/btree_gist/sql/partitions.sql         |   3 +
 .../btree_gist/sql/partitions_buffering.sql   |  42 ++++
 contrib/btree_gist/sql/text_buffering.sql     |  28 +++
 contrib/btree_gist/sql/time_buffering.sql     |  24 +++
 .../btree_gist/sql/timestamp_buffering.sql    |  24 +++
 .../btree_gist/sql/timestamptz_buffering.sql  |  46 +++++
 contrib/btree_gist/sql/timetz_buffering.sql   |  85 ++++++++
 contrib/btree_gist/sql/uuid_buffering.sql     |  20 ++
 contrib/btree_gist/sql/varbit_buffering.sql   |  25 +++
 contrib/btree_gist/sql/varchar_buffering.sql  |  20 ++
 .../sql/without_overlaps_buffering.sql        |  56 +++++
 doc/src/sgml/btree-gist.sgml                  |   7 +
 src/backend/access/gist/gistbuild.c           |   3 +
 src/backend/utils/adt/rangetypes_gist.c       |  73 +++++++
 src/include/catalog/pg_amproc.dat             |   3 +
 src/include/catalog/pg_proc.dat               |   3 +
 132 files changed, 3811 insertions(+), 15 deletions(-)
 create mode 100644 contrib/btree_gist/btree_gist--1.8--1.9.sql
 create mode 100644 contrib/btree_gist/expected/bit_buffering.out
 create mode 100644 contrib/btree_gist/expected/bool_buffering.out
 create mode 100644 contrib/btree_gist/expected/bytea_buffering.out
 create mode 100644 contrib/btree_gist/expected/cash_buffering.out
 create mode 100644 contrib/btree_gist/expected/char_buffering.out
 create mode 100644 contrib/btree_gist/expected/char_buffering_1.out
 create mode 100644 contrib/btree_gist/expected/cidr_buffering.out
 create mode 100644 contrib/btree_gist/expected/cleanup.out
 create mode 100644 contrib/btree_gist/expected/date_buffering.out
 create mode 100644 contrib/btree_gist/expected/enum_buffering.out
 create mode 100644 contrib/btree_gist/expected/float4_buffering.out
 create mode 100644 contrib/btree_gist/expected/float8_buffering.out
 create mode 100644 contrib/btree_gist/expected/inet_buffering.out
 create mode 100644 contrib/btree_gist/expected/int2_buffering.out
 create mode 100644 contrib/btree_gist/expected/int4_buffering.out
 create mode 100644 contrib/btree_gist/expected/int8_buffering.out
 create mode 100644 contrib/btree_gist/expected/interval_buffering.out
 create mode 100644 contrib/btree_gist/expected/macaddr8_buffering.out
 create mode 100644 contrib/btree_gist/expected/macaddr_buffering.out
 create mode 100644 contrib/btree_gist/expected/not_equal_buffering.out
 create mode 100644 contrib/btree_gist/expected/numeric_buffering.out
 create mode 100644 contrib/btree_gist/expected/oid_buffering.out
 create mode 100644 contrib/btree_gist/expected/partitions_buffering.out
 create mode 100644 contrib/btree_gist/expected/text_buffering.out
 create mode 100644 contrib/btree_gist/expected/text_buffering_1.out
 create mode 100644 contrib/btree_gist/expected/time_buffering.out
 create mode 100644 contrib/btree_gist/expected/timestamp_buffering.out
 create mode 100644 contrib/btree_gist/expected/timestamptz_buffering.out
 create mode 100644 contrib/btree_gist/expected/timetz_buffering.out
 create mode 100644 contrib/btree_gist/expected/uuid_buffering.out
 create mode 100644 contrib/btree_gist/expected/varbit_buffering.out
 create mode 100644 contrib/btree_gist/expected/varchar_buffering.out
 create mode 100644 contrib/btree_gist/expected/varchar_buffering_1.out
 create mode 100644 contrib/btree_gist/expected/without_overlaps_buffering.out
 create mode 100644 contrib/btree_gist/sql/bit_buffering.sql
 create mode 100644 contrib/btree_gist/sql/bool_buffering.sql
 create mode 100644 contrib/btree_gist/sql/bytea_buffering.sql
 create mode 100644 contrib/btree_gist/sql/cash_buffering.sql
 create mode 100644 contrib/btree_gist/sql/char_buffering.sql
 create mode 100644 contrib/btree_gist/sql/cidr_buffering.sql
 create mode 100644 contrib/btree_gist/sql/cleanup.sql
 create mode 100644 contrib/btree_gist/sql/date_buffering.sql
 create mode 100644 contrib/btree_gist/sql/enum_buffering.sql
 create mode 100644 contrib/btree_gist/sql/float4_buffering.sql
 create mode 100644 contrib/btree_gist/sql/float8_buffering.sql
 create mode 100644 contrib/btree_gist/sql/inet_buffering.sql
 create mode 100644 contrib/btree_gist/sql/int2_buffering.sql
 create mode 100644 contrib/btree_gist/sql/int4_buffering.sql
 create mode 100644 contrib/btree_gist/sql/int8_buffering.sql
 create mode 100644 contrib/btree_gist/sql/interval_buffering.sql
 create mode 100644 contrib/btree_gist/sql/macaddr8_buffering.sql
 create mode 100644 contrib/btree_gist/sql/macaddr_buffering.sql
 create mode 100644 contrib/btree_gist/sql/not_equal_buffering.sql
 create mode 100644 contrib/btree_gist/sql/numeric_buffering.sql
 create mode 100644 contrib/btree_gist/sql/oid_buffering.sql
 create mode 100644 contrib/btree_gist/sql/partitions_buffering.sql
 create mode 100644 contrib/btree_gist/sql/text_buffering.sql
 create mode 100644 contrib/btree_gist/sql/time_buffering.sql
 create mode 100644 contrib/btree_gist/sql/timestamp_buffering.sql
 create mode 100644 contrib/btree_gist/sql/timestamptz_buffering.sql
 create mode 100644 contrib/btree_gist/sql/timetz_buffering.sql
 create mode 100644 contrib/btree_gist/sql/uuid_buffering.sql
 create mode 100644 contrib/btree_gist/sql/varbit_buffering.sql
 create mode 100644 contrib/btree_gist/sql/varchar_buffering.sql
 create mode 100644 contrib/btree_gist/sql/without_overlaps_buffering.sql

diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile
index 7ac2df26c10..382b9a96575 100644
--- a/contrib/btree_gist/Makefile
+++ b/contrib/btree_gist/Makefile
@@ -31,16 +31,23 @@ OBJS =  \
 
 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.6--1.7.sql \
-       btree_gist--1.7--1.8.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.6--1.7.sql \
+		btree_gist--1.7--1.8.sql btree_gist--1.8--1.9.sql
 PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes"

 
index 9d5e01a1977..b385316f1f4 100644

 
+static int
@@ -207,3 +231,25 @@ gbt_bit_penalty(PG_FUNCTION_ARGS)
index bdc7834bb6a..b82de485e13 100644
 
 #include "btree_gist.h"
 
 typedef struct boolkey
 {
 
 static bool
@@ -166,3 +177,14 @@ gbt_bool_same(PG_FUNCTION_ARGS)
index 394e40ed16b..e86e3239f2b 100644

 /*
@@ -17,7 +18,41 @@ PG_FUNCTION_INFO_V1(gbt_bytea_picksplit);

 
index 546b948ea40..ec8cfa9ce84 100644
 
 typedef struct
 {
 
 static bool
@@ -215,3 +231,14 @@ gbt_cash_same(PG_FUNCTION_ARGS)
index 5efb5ef96f5..90444b2faa6 100644
 
 typedef struct
 {
@@ -25,6 +26,30 @@ PG_FUNCTION_INFO_V1(gbt_date_consistent);
 
 static bool
index 26682122f8e..67269ee5909 100644

+static int
@@ -183,3 +199,20 @@ gbt_enum_same(PG_FUNCTION_ARGS)
index 84ca5eee501..cbff00d1361 100644
 
 #include "btree_gist.h"
 
 typedef struct float4key
@@ -24,6 +25,33 @@ PG_FUNCTION_INFO_V1(gbt_float4_consistent);
 
 static bool
index 081a719b006..d9e1014e78b 100644
 
 #include "btree_gist.h"
 
 typedef struct float8key
@@ -24,7 +25,33 @@ PG_FUNCTION_INFO_V1(gbt_float8_consistent);

 static bool
index 0db8522c8a7..132d5e2dff5 100644

index c66ca99e0c3..11c21d64a1b 100644
 
 typedef struct inetkey
 {

+static int
@@ -184,3 +200,14 @@ gbt_inet_same(PG_FUNCTION_ARGS)
index fdbf156586c..b19770ff67f 100644
 
 #include "btree_gist.h"
 
 typedef struct int16key
@@ -24,6 +25,31 @@ PG_FUNCTION_INFO_V1(gbt_int2_consistent);
 
 static bool
index 8915fb5d087..f12e8d922bf 100644
@@ -2,15 +2,15 @@
 
 typedef struct int32key
 {
-	int32		lower;
-	int32		upper;
+  int32		lower;
+  int32		upper;
 } int32KEY;
 
 /*
@@ -24,7 +24,7 @@ PG_FUNCTION_INFO_V1(gbt_int4_consistent);
 
 static bool
 gbt_int4gt(const void *a, const void *b, FmgrInfo *flinfo)
@@ -90,6 +90,29 @@ static const gbtree_ninfo tinfo =
 	gbt_int4_dist
 };
 
+static int
 
index 7c63a5b6dc1..00d55163fc9 100644
 
 typedef struct int64key
 {
@@ -24,7 +25,32 @@ PG_FUNCTION_INFO_V1(gbt_int8_consistent);

 static bool
index c2f6eede226..ae931eed13c 100644
 
 typedef struct

+static int
@@ -295,3 +309,14 @@ gbt_intv_same(PG_FUNCTION_ARGS)
index 1367eaba735..af55a142d76 100644
 
 typedef struct
 {
@@ -25,6 +26,34 @@ PG_FUNCTION_INFO_V1(gbt_macad_picksplit);

 static bool
index 9676e5a15bd..b89cc66ed86 100644
 
 typedef struct
 {

+static int
@@ -194,3 +207,14 @@ gbt_macad8_same(PG_FUNCTION_ARGS)
index 35e466cdd94..227712645da 100644
 
 /*
 ** Bytea ops
@@ -21,7 +22,39 @@ PG_FUNCTION_INFO_V1(gbt_numeric_picksplit);

 
diff --git a/contrib/btree_gist/btree_oid.c b/contrib/btree_gist/btree_oid.c
index 3cc7d4245d4..4ce4d3ff87e 100644
--- a/contrib/btree_gist/btree_oid.c
+++ b/contrib/btree_gist/btree_oid.c
@@ -5,6 +5,7 @@
 
 #include "btree_gist.h"
 
 typedef struct
 {
@@ -23,7 +24,34 @@ PG_FUNCTION_INFO_V1(gbt_oid_consistent);

 static bool
index 28d6b5c9c2b..f9c9c3f828e 100644
 
 /*
 ** Text ops
@@ -19,7 +20,40 @@ PG_FUNCTION_INFO_V1(gbt_text_consistent);

 
index 3034bbb456b..cb334ff796e 100644
 
 typedef struct

 #ifdef USE_FLOAT8_BYVAL

+static int
@@ -332,3 +347,14 @@ gbt_time_same(PG_FUNCTION_ARGS)
index b3cf2d6f60d..254f551f3cd 100644
 
 typedef struct
 {

 #ifdef USE_FLOAT8_BYVAL
@@ -39,6 +41,29 @@ PG_FUNCTION_INFO_V1(gbt_ts_same);
 #define TimestampGetDatumFast(X) PointerGetDatum(&(X))
 #endif

 static bool
 
-
+/*

index fe8c679cbed..08372fc8bc9 100644
 
 typedef struct
@@ -25,7 +26,31 @@ PG_FUNCTION_INFO_V1(gbt_uuid_picksplit);

 static int
index e57871f310b..ed5dc6a6819 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index 29390f079c0..df2b8c0767b 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index b9efa73c085..0a6935f653d 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index 7fbc7355929..e10b5b00600 100644
 
 CREATE INDEX moneyidx ON moneytmp USING gist ( a );
+NOTICE:  notice triggered for injection point gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM moneytmp WHERE a <  '22649.64'::money;
  count 
diff --git a/contrib/btree_gist/expected/cash_buffering.out b/contrib/btree_gist/expected/cash_buffering.out
new file mode 100644
index 00000000000..2ed8a80dd0c
--- /dev/null
+++ b/contrib/btree_gist/expected/cash_buffering.out
@@ -0,0 +1,53 @@
+-- money check
+DROP TABLE IF EXISTS moneytmp;
+CREATE TABLE moneytmp (a money);
+\copy moneytmp from 'data/cash.data'
+CREATE INDEX moneyidx ON moneytmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM moneytmp WHERE a <  '22649.64'::money;
+ count 
+-------
+   289
+(1 row)
+
+SELECT count(*) FROM moneytmp WHERE a <= '22649.64'::money;
+ count 
+-------
+   290
+(1 row)
+
+SELECT count(*) FROM moneytmp WHERE a  = '22649.64'::money;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM moneytmp WHERE a >= '22649.64'::money;
+ count 
+-------
+   254
+(1 row)
+
+SELECT count(*) FROM moneytmp WHERE a >  '22649.64'::money;
+ count 
+-------
+   253
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Limit
+   ->  Index Only Scan using moneyidx on moneytmp
+         Order By: (a <-> '$21,472.79'::money)
+(3 rows)
+
+SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3;
+     a      | ?column? 
+------------+----------
+ $21,472.79 |    $0.00
+ $21,469.25 |    $3.54
+ $21,915.01 |  $442.22
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/char.out b/contrib/btree_gist/expected/char.out
index 45cf9f38d65..a353ff91421 100644
--- a/contrib/btree_gist/expected/char.out
+++ b/contrib/btree_gist/expected/char.out
@@ -33,6 +33,7 @@ SELECT count(*) FROM chartmp WHERE a >   '31b0'::char(32);
 (1 row)
 
 CREATE INDEX charidx ON chartmp USING GIST ( a );
+NOTICE:  notice triggered for injection point gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM chartmp WHERE a <   '31b0'::char(32);
  count 
diff --git a/contrib/btree_gist/expected/char_1.out b/contrib/btree_gist/expected/char_1.out
index 7b7824b7171..4c59fc80fa9 100644
--- a/contrib/btree_gist/expected/char_1.out
+++ b/contrib/btree_gist/expected/char_1.out
@@ -33,6 +33,7 @@ SELECT count(*) FROM chartmp WHERE a >   '31b0'::char(32);
 (1 row)
 
 CREATE INDEX charidx ON chartmp USING GIST ( a );
+NOTICE:  notice triggered for injection point gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM chartmp WHERE a <   '31b0'::char(32);
  count 
index 00000000000..46333ab3b47
+SELECT injection_points_detach('gist-sorted-build');
index 5db864bb82c..7dc8753a806 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index c4b769dd4b7..af8850ebf51 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index dfe732049e6..5546aeffee5 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index ebd0ef3d689..8eb67ae4f2d 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index f15f1435f0a..812181e680a 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index ce4559d8b03..a28b7adb7a8 100644
+SELECT injection_points_attach('gist-sorted-build', 'notice');
index 50a332939bd..c7e67f6e823 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index 6bbdc7c3f4b..ded4b40bb52 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index eff77c26b5a..3d5506b913a 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index 4c3d494e4a6..0b351ac56ac 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index c0a4c6287f3..dfe053e4dee 100644
 
 CREATE INDEX macaddridx ON macaddrtmp USING gist ( a );
+NOTICE:  notice triggered for injection point gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM macaddrtmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr;
  count 
diff --git a/contrib/btree_gist/expected/macaddr8.out b/contrib/btree_gist/expected/macaddr8.out
index e5ec6a5deab..715ff056696 100644
--- a/contrib/btree_gist/expected/macaddr8.out
+++ b/contrib/btree_gist/expected/macaddr8.out
@@ -33,6 +33,7 @@ SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d';
 (1 row)
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index 85b1e868a87..bf74c92a8af 100644
@@ -5,6 +5,7 @@ CREATE TABLE test_ne (
+NOTICE:  notice triggered for injection point gist-sorted-build
@@ -33,6 +34,7 @@ CREATE TABLE zoo (
+NOTICE:  notice triggered for injection point gist-sorted-build
index ae839b8ec83..16f06ba4de9 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index 776bbb10267..eaeeacdee17 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index 5bddb915871..129a91524b8 100644
@@ -2,13 +2,17 @@
+NOTICE:  notice triggered for injection point gist-sorted-build
+NOTICE:  notice triggered for injection point gist-sorted-build
index bb4e2e62d1d..18f32d1db29 100644
 
 CREATE INDEX textidx ON texttmp USING GIST ( a );
+NOTICE:  notice triggered for injection point gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM texttmp WHERE a <   '31b0'::text;
  count 
diff --git a/contrib/btree_gist/expected/text_1.out b/contrib/btree_gist/expected/text_1.out
index 8ef1ffb2d13..10e46c3d58c 100644
--- a/contrib/btree_gist/expected/text_1.out
+++ b/contrib/btree_gist/expected/text_1.out
@@ -34,6 +34,7 @@ SELECT count(*) FROM texttmp WHERE a >   '31b0';
 (1 row)
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index ec95ef77c57..44297224b2f 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index 0d94f2f245c..bb6bcecede0 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index 75a15a42568..b7a13a4b33a 100644
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index 7f73e447977..2963146d14b 100644
+NOTICE:  notice triggered for injection point gist-sorted-build
index a34b0246032..d3019284e6b 100644
 
 CREATE INDEX uuididx ON uuidtmp USING gist ( a );
+NOTICE:  notice triggered for injection point gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM uuidtmp WHERE a <  '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
  count 
diff --git a/contrib/btree_gist/expected/uuid_buffering.out b/contrib/btree_gist/expected/uuid_buffering.out
new file mode 100644
index 00000000000..df23c9278c3
--- /dev/null
+++ b/contrib/btree_gist/expected/uuid_buffering.out
@@ -0,0 +1,36 @@
+-- uuid check
+DROP TABLE IF EXISTS uuidtmp;
+CREATE TABLE uuidtmp (a uuid);
+\copy uuidtmp from 'data/uuid.data'
+CREATE INDEX uuididx ON uuidtmp USING gist ( a ) WITH(buffering = on);
+SET enable_seqscan=off;
+SELECT count(*) FROM uuidtmp WHERE a <  '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
+ count 
+-------
+   227
+(1 row)
+
+SELECT count(*) FROM uuidtmp WHERE a <= '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
+ count 
+-------
+   228
+(1 row)
+
+SELECT count(*) FROM uuidtmp WHERE a  = '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM uuidtmp WHERE a >= '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
+ count 
+-------
+   376
+(1 row)
+
+SELECT count(*) FROM uuidtmp WHERE a >  '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid;
+ count 
+-------
+   375
+(1 row)
+
diff --git a/contrib/btree_gist/expected/varbit.out b/contrib/btree_gist/expected/varbit.out
index ede36bc3ead..19eb8439140 100644
--- a/contrib/btree_gist/expected/varbit.out
+++ b/contrib/btree_gist/expected/varbit.out
@@ -33,6 +33,7 @@ SELECT count(*) FROM varbittmp WHERE a >   '1110100111010';
 (1 row)
 
 CREATE INDEX varbitidx ON varbittmp USING GIST ( a );
+NOTICE:  notice triggered for injection point gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM varbittmp WHERE a <   '1110100111010'::varbit;
  count 
index d071d714cdd..1726541978e 100644
 
 CREATE INDEX vcharidx ON vchartmp USING GIST ( text(a) );
+NOTICE:  notice triggered for injection point gist-sorted-build
 SET enable_seqscan=off;
 SELECT count(*) FROM vchartmp WHERE a <   '31b0'::varchar(32);
  count 
diff --git a/contrib/btree_gist/expected/varchar_1.out b/contrib/btree_gist/expected/varchar_1.out
index e4099d23c0c..0ae6e305d1c 100644
--- a/contrib/btree_gist/expected/varchar_1.out
+++ b/contrib/btree_gist/expected/varchar_1.out
@@ -33,6 +33,7 @@ SELECT count(*) FROM vchartmp WHERE a >   '31b0'::varchar(32);
 (1 row)
 
+NOTICE:  notice triggered for injection point gist-sorted-build
index 18856900ded..52bc4621ed1 100644
@@ -8,6 +8,7 @@ CREATE TABLE temporal_rng (
+NOTICE:  notice triggered for injection point gist-sorted-build
@@ -51,6 +52,7 @@ CREATE TABLE temporal_fk_rng2rng (
+NOTICE:  notice triggered for injection point gist-sorted-build
 
index 00000000000..faee17edf05
+SELECT injection_points_detach('gist-sorted-build');
index a6d2cffc677..1faceffcb4b 100644
+SELECT injection_points_attach('gist-sorted-build', 'notice');

+ <para>
+  By default <filename>btree_gist</filename> builds <acronym>GiST</acronym> index with
+  <function>sortsupport</function> in <firstterm>sorted</firstterm> mode. This usually results in
+  smaller index sizes and much faster index built speed. It is still possible to revert to buffered
+  built strategy by using the <literal>buffering</literal> parameter when creating the index.
+ </para>
+
  <para>
   This module is considered <quote>trusted</quote>, that is, it can be
   installed by non-superusers who have <literal>CREATE</literal> privilege
diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c
index ba06df30faf..9a69634be2c 100644
--- a/src/backend/access/gist/gistbuild.c
+++ b/src/backend/access/gist/gistbuild.c
@@ -44,6 +44,7 @@
 #include "storage/bufmgr.h"
 #include "storage/bulk_write.h"
 
+#include "utils/injection_point.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/tuplesort.h"
@@ -403,6 +404,8 @@ gist_indexsortbuild(GISTBuildState *state)
 	GistSortedBuildLevelState *levelstate;
 	BulkWriteBuffer rootbuf;
 
+	INJECTION_POINT("gist-sorted-build");
+
 	/* Reserve block 0 for the root page */
 	state->pages_allocated = 1;
 
index cb28e9859ab..42085cc0609 100644
@@ -19,8 +19,10 @@
 #include "utils/datum.h"
 
 /*
@@ -177,6 +179,7 @@ static void range_gist_double_sorting_split(TypeCacheEntry *typcache,
@@ -773,6 +776,22 @@ range_gist_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(v);
 }
 
+/*
@@ -1693,6 +1712,60 @@ range_gist_consider_split(ConsiderSplitContext *context,
 	}
 }
 
+/*
index cbbe8acd382..fd10d119516 100644
@@ -10770,6 +10770,9 @@
2.47.0

---

From: "Andrey M. Borodin" <[email-masked]>
Date: Thu, 28 Nov 2024 23:32:59 +0500

> On 25 Nov 2024, at 20:40, Bernd Helmle <[email-masked]> wrote:
> 
> 

Hi Bernd!

Thanks for the new patch version.

There are still some problems with tests.
0. You rely on order of test execution. "init.sql" test must prepend any other test. I doubt it is guaranteed.
1. There's a typo float8__buffering in Makefile
2. cidr type seems to be left behind
3. Tests do not seem to work when your configuration lacks injection points.

You can see how tests with injection points are excluded in other modules...

Perhaps, let's ask Michael.
Michael, we have 30 tests with checks that need injection points. But these 30 tests also test functionality that needs to be tested even in build without injection points.
Do we have to extract checks with injection point into separate regression test? So that we can exclude this test in builds without injection points.

Thanks!

---

From: Michael Paquier <[email-masked]>
Date: Fri, 29 Nov 2024 13:42:03 +0900

On Thu, Nov 28, 2024 at 11:32:59PM +0500, Andrey M. Borodin wrote:
> Michael, we have 30 tests with checks that need injection
> points. But these 30 tests also test functionality that needs to be
> tested even in build without injection points. 
> Do we have to extract checks with injection point into separate
> regression test? So that we can exclude this test in builds without
> injection points.

I've looked at what the patch is doing with injection points, and
that's incorrect.

This attaches points locally, meaning that this is going to create
some noise for any tests running in parallel taking the same code path
as where the point is created.  To make tests able to run safely in a
concurrent manner, please use injection_points_set_local().  As a
bonus, your points would be automatically detached when the session
turns off.

Any module that requires the module injection_points to be installed
can do a few things, none of them are done this way in this patch:
- Add EXTRA_INSTALL=src/test/modules/injection_points.
- You could make a test able to run installcheck, but you should use
an extra query that checks if the module is available for installation
by querying pg_available_extensions and use two possible output files:
one for the case where the module is *not* installed and one for the
case where the module is installed.  A simpler way would be to block
installcheck, or add SQL tests in src/test/modules/injection_points.
Both options don't seem adapted to me here as they impact the
portability of existing tests.

As a whole, I'm very dubious about the need for injection points at
all here.  The sortsupport property claimed for this patch tells that
this results in smaller index sizes, but the tests don't really check
that: they just make sure that sortsupport routine paths are taken.
What this should test is not the path taken, but how the new code
affects the index data generated.  Perhaps pageinspect could be
something to use to show the difference in contents, not sure though.

The number of tests added to contrib/btree_gist/Makefile is not
acceptable for a patch of this size, leading to a large bloat.  And
that's harder to maintain in the long-term.
--
Michael

---

From: "Andrey M. Borodin" <[email-masked]>
Date: Fri, 29 Nov 2024 14:41:56 +0500

Thanks for your valuable input, Michael!

> On 29 Nov 2024, at 09:42, Michael Paquier <[email-masked]> wrote:
> 
> affects the index data generated.

Actually, that’s exactly what we wanted to test: which paths are taken.
Resulting index might be of a very same size in case of B-tree-over-GiST. Resulting index is drastically smaller for geometry, e.g. PostGIS. But event that’s not main effect: the index is simply build much faster (on par with actual B-tree).
We need this sort support for btree_gist to be able to use non-geometry datatypes in combination with geometry.
e.g.
CREATE INDEX ON table USING gist(project_id_of_type_int,geometric_column);
Currently, having anything non-geometric in GiST slows down it 10x, because sorting build path is not taken.
In PG15 we put extra effort to make resulting indexes indistinguishable from normally-built. Primarily for the sake of IndexScan performance.

---

From: Bernd Helmle <[email-masked]>
Date: Sat, 30 Nov 2024 14:14:26 +0100

Hi Michael,

Am Freitag, dem 29.11.2024 um 13:42 +0900 schrieb Michael Paquier:

 [...]

> portability of existing tests.

I don't like this. This smells like we use the wrong tool. Andrey had
the idea to use them because it looked as a compelling idea to check
whether sortsupport is used in the code path or not. 

Maybe we should just use a specific DEBUG message and make sure it's
handled by the tests accordingly.

> something to use to show the difference in contents, not sure though.

No, this isn't the goal of sortsupport for btree_gist. It was a side
effect before PG15 that it yielded a better index quality, but the
primary goal is and was index creation speed. With sortsupport we're
much much faster that the traditional buffered method.

Originally this patch was pushed by a customer who had complains about
the long build times of btree_gist indexes used by exclusion
constraints they're heavily relying on. See a benchmark i've posted in
this thread here with test data:

https://www.postgresql.org/message-id/[email-masked]

> that's harder to maintain in the long-term.

Yes, it is not really nice, but i have no better idea atm on how to
test both code paths equally without repeating the tests again. Index
creation must yield the same results than buffered index build
strategy. Originally i just added the tests to the same test file, but
then decided to split them up to make it simpler to review and
maintain.

I'm open for better ideas.

Thanks for your comments

	Bernd

---

From: Andrey Borodin <[email-masked]>
Date: Sat, 30 Nov 2024 22:18:38 +0500

> On 30 Nov 2024, at 18:14, Bernd Helmle <[email-masked]> wrote:
> 

We tried to go that route, random DEBUG1 lines were breaking tests (autovacuum or something like that, there was something non-deterministic). I think we can dig exact reason from 2021 thread why we abandoned that idea...

I think we have two options:
1. Just do not commit tests. We ran it manually, saw that paths are taken, we are happy.
2. Have just one file that builds sorted index on a table with few tuples for each data type.

We do not need to test that core sorting (or buffered) build works. AFAIR there's plenty of other tests to verify that.

Injection points seemed to me exactly the technogy that could help us to have tests for this patch. But at this point It looks like it's reasonable to take approach 1, as we did before.

---

From: Bernd Helmle <[email-masked]>
Date: Mon, 09 Dec 2024 18:10:53 +0100

Am Samstag, dem 30.11.2024 um 22:18 +0500 schrieb Andrey Borodin:
> We tried to go that route, random DEBUG1 lines were breaking tests
> (autovacuum or something like that, there was something non-
> deterministic). I think we can dig exact reason from 2021 thread why
> we abandoned that idea...
> 

So here's a version with the original, unchanged regression tests and
injection point removed (i hope i forgot nothing to revert).

This version also fixes cidr sortsupport (thanks again Andrey for
spotting this), where i accidently used inet instead of the correct
cidr datatype to pass down to the sortsupport function.

Thanks,
	Bernd

From b38c1181d38526d0ccd948f3446ca31f6953815d Mon Sep 17 00:00:00 2001
From: Bernd Helmle <Bernd Helmle [email-masked]>
Date: Mon, 9 Dec 2024 18:02:31 +0100
Subject: [PATCH] Add support for sorted gist index builds to btree_gist

Sorted gist index build strategy is the new default now. Regression tests are
unchanged and are using the sorted build strategy instead.
---
 contrib/btree_gist/Makefile                 |  14 +-
 contrib/btree_gist/btree_bit.c              |  46 +++++
 contrib/btree_gist/btree_bool.c             |  22 +++
 contrib/btree_gist/btree_bytea.c            |  35 ++++
 contrib/btree_gist/btree_cash.c             |  27 +++
 contrib/btree_gist/btree_date.c             |  25 +++
 contrib/btree_gist/btree_enum.c             |  33 ++++
 contrib/btree_gist/btree_float4.c           |  28 +++
 contrib/btree_gist/btree_float8.c           |  27 +++
 contrib/btree_gist/btree_gist--1.8--1.9.sql | 192 ++++++++++++++++++++
 contrib/btree_gist/btree_gist.control       |   2 +-
 contrib/btree_gist/btree_inet.c             |  27 +++
 contrib/btree_gist/btree_int2.c             |  26 +++
 contrib/btree_gist/btree_int4.c             |  33 +++-
 contrib/btree_gist/btree_int8.c             |  26 +++
 contrib/btree_gist/btree_interval.c         |  25 +++
 contrib/btree_gist/btree_macaddr.c          |  29 +++
 contrib/btree_gist/btree_macaddr8.c         |  24 +++
 contrib/btree_gist/btree_numeric.c          |  33 ++++
 contrib/btree_gist/btree_oid.c              |  28 +++
 contrib/btree_gist/btree_text.c             |  34 ++++
 contrib/btree_gist/btree_time.c             |  26 +++
 contrib/btree_gist/btree_ts.c               |  25 +++
 contrib/btree_gist/btree_utils_var.h        |  12 +-
 contrib/btree_gist/btree_uuid.c             |  25 +++
 contrib/btree_gist/meson.build              |   1 +
 doc/src/sgml/btree-gist.sgml                |   7 +
 src/backend/utils/adt/rangetypes_gist.c     |  70 +++++++
 src/include/catalog/pg_amproc.dat           |   3 +
 src/include/catalog/pg_proc.dat             |   3 +
 30 files changed, 894 insertions(+), 14 deletions(-)
 create mode 100644 contrib/btree_gist/btree_gist--1.8--1.9.sql

diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile
index 7ac2df26c10..90d36a659e4 100644
--- a/contrib/btree_gist/Makefile
+++ b/contrib/btree_gist/Makefile
@@ -31,16 +31,16 @@ OBJS =  \
 
 EXTENSION = btree_gist
 
 REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \
-        time timetz date interval macaddr macaddr8 inet cidr text varchar char \
-        bytea bit varbit numeric uuid not_equal enum bool partitions \
-        stratnum without_overlaps
+		 time timetz date interval macaddr macaddr8 inet cidr text varchar char \
+		 bytea bit varbit numeric uuid not_equal enum bool partitions \
+		 stratnum without_overlaps

index f346b956fa9..35aa5578f83 100644

 
+static int
index adb724e16ac..e6b08f04e9d 100644
 
 #include "btree_gist.h"
 
 typedef struct boolkey
 {
 
 static bool
index 5eacb8c59a0..87b83d162bb 100644

 /*

 
index c18c34c8b83..4d50b0f0d9a 100644
 
 typedef struct
 {
 
 static bool
index 7a4a9d7a853..ee2d96e6006 100644
 
 typedef struct
 {
 
 static bool
index 05d02e704a0..9c4a7727102 100644

+static int
index d138aa94bf2..c23f7886e09 100644
 
 #include "btree_gist.h"
 
 typedef struct float4key
 
 static bool
index a74cd200529..129837f2a19 100644
 
 #include "btree_gist.h"
 
 typedef struct float8key

 static bool
index 00000000000..401e9965cf6
+    FUNCTION    11  (cidr, cidr) gbt_inet_sortsupport (internal) ;
index 4cffd349091..cf94cd0f300 100644
 
 typedef struct inetkey
 {

+static int
index 1751a6c055d..02df5813231 100644
 
 #include "btree_gist.h"
 
 typedef struct int16key
 
 static bool
index 90d183be6e8..1cef35aace0 100644
 
 typedef struct int32key
 {
-	int32		lower;
-	int32		upper;
+  int32		lower;
+  int32		upper;
 } int32KEY;
 
 /*
 
 static bool
 
+static int
 
index 661cf8189fc..f61a4da6801 100644
 
 typedef struct int64key
 {

 static bool
index 8f99a416965..25b4ecce192 100644
 
 typedef struct

+static int
index 558cfa2172f..7df85e5db3b 100644
 
 typedef struct
 {

 static bool
index 5d0c5509f51..e659168b1e2 100644
 
 typedef struct
 {

+static int
index d533648a295..fe6a5a48dd5 100644
 
 /*
 ** Bytea ops

 
diff --git a/contrib/btree_gist/btree_oid.c b/contrib/btree_gist/btree_oid.c
index d1976f4f091..e3bd78658d0 100644
--- a/contrib/btree_gist/btree_oid.c
+++ b/contrib/btree_gist/btree_oid.c
@@ -5,6 +5,7 @@
 
 #include "btree_gist.h"
 
 typedef struct
 {

 static bool
index 8f80f54240f..4c6dfa9a4e7 100644
 
 /*
 ** Text ops

 
index 2f7859340f6..28d4447ff59 100644
 
 typedef struct

 #ifdef USE_FLOAT8_BYVAL

+static int
index 9e0d979dda9..5ec739b4813 100644
 
 typedef struct
 {

 #ifdef USE_FLOAT8_BYVAL

 static bool
 
-
+/*

index f4c5c6e5892..85e57d52151 100644
 
 typedef struct

 static int
index 73b1bbf52a6..5b4caff5baf 100644
@@ -51,6 +51,7 @@ install_data(
 
index 31e7c78aaef..a4c1b99be1f 100644
 
+ <para>
+  much faster index built speed. It is still possible to revert to buffered built strategy
+  by using the <literal>buffering</literal> parameter when creating the index.
 
 /*
 
+/*
 
+/*
index 9575524007f..1ce739d0186 100644
@@ -10775,6 +10775,9 @@
2.47.1

---

From: "Andrey M. Borodin" <[email-masked]>
Date: Mon, 9 Dec 2024 23:26:02 +0500

> On 9 Dec 2024, at 22:10, Bernd Helmle <[email-masked]> wrote:
> 

Besides unnecessary indentation changes in contrib/btree_gist/Makefile, the patch seems good to me.

---

From: Bernd Helmle <[email-masked]>
Date: Tue, 10 Dec 2024 11:20:00 +0100

Am Montag, dem 09.12.2024 um 23:26 +0500 schrieb Andrey M. Borodin:
> Besides unnecessary indentation changes in
> contrib/btree_gist/Makefile, the patch seems good to me.

Oh yes, fixed.

-- 
Thanks,
	Bernd

From 2d2c3b5940a8ec15b1c6bd6b829c8d44c0e615e0 Mon Sep 17 00:00:00 2001
From: Bernd Helmle <Bernd Helmle [email-masked]>
Date: Tue, 10 Dec 2024 11:17:06 +0100
Subject: [PATCH] Add support for sorted gist index builds to btree_gist

 contrib/btree_gist/Makefile                 |   2 +-
 30 files changed, 888 insertions(+), 8 deletions(-)

index 7ac2df26c10..68190ac5e46 100644
@@ -34,7 +34,7 @@ DATA = btree_gist--1.0--1.1.sql \

 
+static int
 
 #include "btree_gist.h"
 
 typedef struct boolkey
 {
 
 static bool

 /*

 
 
 typedef struct
 {
 
 static bool
 
 typedef struct
 {
 
 static bool

+static int
 
 #include "btree_gist.h"
 
 typedef struct float4key
 
 static bool
 
 #include "btree_gist.h"
 
 typedef struct float8key

 static bool
 
 typedef struct inetkey
 {

+static int
 
 #include "btree_gist.h"
 
 typedef struct int16key
 
 static bool
 
 typedef struct int32key
 {
-	int32		lower;
-	int32		upper;
+  int32		lower;
+  int32		upper;
 } int32KEY;
 
 /*
 
 static bool
 
+static int

 typedef struct int64key
 {

 static bool
 
 typedef struct

+static int
 
 typedef struct
 {

 static bool
 
 typedef struct
 {

+static int
 
 /*
 ** Bytea ops

 
 
 #include "btree_gist.h"
 
 typedef struct
 {

 static bool
 
 /*
 ** Text ops

 
 
 typedef struct

 #ifdef USE_FLOAT8_BYVAL

+static int
 
 typedef struct
 {

 #ifdef USE_FLOAT8_BYVAL

 static bool
 
-
+/*

 
 typedef struct

 static int

+ <para>
 
 /*
 
+/*
 
+/*

---

From: Bernd Helmle <[email-masked]>
Date: Wed, 15 Jan 2025 14:20:24 +0100

> contrib/btree_gist/Makefile, the patch seems good to me.

Commit 630f9a43cece93cb4a5c243b30e34abce6a89514 created a conflict with
this patch so that it doesn't apply anymore.

Attached is a rebased version.

	Bernd

From dd4a0b06554d3b383539a27c0447ca64bf849b53 Mon Sep 17 00:00:00 2001
From: Bernd Helmle <Bernd Helmle [email-masked]>
Date: Wed, 15 Jan 2025 14:02:45 +0100
Subject: [PATCH] Add support for sorted gist index builds to btree_gist

 contrib/btree_gist/btree_gist--1.7--1.8.sql |   1 +
 31 files changed, 889 insertions(+), 8 deletions(-)

 
+static int
 
 #include "btree_gist.h"
 
 typedef struct boolkey
 {
 
 static bool

 /*

 
 
 typedef struct
 {
 
 static bool
 
 typedef struct
 {
 
 static bool

+static int
 
 #include "btree_gist.h"
 
 typedef struct float4key
 
 static bool
 
 #include "btree_gist.h"
 
 typedef struct float8key

 static bool
 gbt_float8gt(const void *a, const void *b, FmgrInfo *flinfo)
diff --git a/contrib/btree_gist/btree_gist--1.7--1.8.sql b/contrib/btree_gist/btree_gist--1.7--1.8.sql
index c702426deab..ff2ecbc543b 100644
--- a/contrib/btree_gist/btree_gist--1.7--1.8.sql
+++ b/contrib/btree_gist/btree_gist--1.7--1.8.sql
@@ -85,3 +85,4 @@ ALTER OPERATOR FAMILY gist_enum_ops USING gist ADD
 
 ALTER OPERATOR FAMILY gist_bool_ops USING gist ADD
 	FUNCTION 12 (bool, bool) gist_stratnum_btree (int) ;
+
 
 typedef struct inetkey
 {

+static int
 
 #include "btree_gist.h"
 
 typedef struct int16key
 
 static bool
 
 typedef struct int32key
 {
-	int32		lower;
-	int32		upper;
+  int32		lower;
+  int32		upper;
 } int32KEY;
 
 /*
 
 static bool
 
+static int

 typedef struct int64key
 {

 static bool
 
 typedef struct

+static int
 
 typedef struct
 {

 static bool
 
 typedef struct
 {

+static int
 
 /*
 ** Bytea ops

 
 
 #include "btree_gist.h"
 
 typedef struct
 {

 static bool
 
 /*
 ** Text ops

 
 
 typedef struct

 #ifdef USE_FLOAT8_BYVAL

+static int
 
 typedef struct
 {

 #ifdef USE_FLOAT8_BYVAL

 static bool
 
-
+/*

 
 typedef struct

 static int
index f4fa9574f1f..89932dd3844 100644

+ <para>
index a60ee985e74..fa7543be9de 100644
 
 /*
 
+/*
 
+/*
index 508f48d345c..ade8373927f 100644
   amproc => 'gist_stratnum_common' },
index ba02ba53b29..07951ccba58 100644
@@ -10797,6 +10797,9 @@

---

From: Bernd Helmle <[email-masked]>
Date: Wed, 15 Jan 2025 19:24:21 +0100

> this patch so that it doesn't apply anymore.

Seems i broke something during rebase (see cfbot). I will look at this
tomorrow.

	Bernd

---

From: Bernd Helmle <[email-masked]>
Date: Thu, 16 Jan 2025 15:14:25 +0100

Am Mittwoch, dem 15.01.2025 um 19:24 +0100 schrieb Bernd Helmle:
> Seems i broke something during rebase (see cfbot). I will look at
> this tomorrow.

This was related to 630f9a43cec and fixed by Peter already in
d5221c49a30, so unrelated to my rebase of this patch. 

I attach a new rebased version to master anyways, which fixes an
unnecessary whitespace in the patch, no other changes.

I am going to reflag this patch as "Ready For Committer" again.

	Bernd

From 58a48f47e5efa31b23f2f6ef904ae366b39ae199 Mon Sep 17 00:00:00 2001
From: Bernd Helmle <Bernd Helmle [email-masked]>
Date: Thu, 16 Jan 2025 15:01:45 +0100
Subject: [PATCH] Add support for sorted gist index builds to btree_gist

 

 
+static int
 
 #include "btree_gist.h"
 
 typedef struct boolkey
 {
 
 static bool

 /*

 
 
 typedef struct
 {
 
 static bool
 
 typedef struct
 {
 
 static bool

+static int
 
 #include "btree_gist.h"
 
 typedef struct float4key
 
 static bool
 
 #include "btree_gist.h"
 
 typedef struct float8key

 static bool
 
 typedef struct inetkey
 {

+static int
 
 #include "btree_gist.h"
 
 typedef struct int16key
 
 static bool
 
 typedef struct int32key
 {
-	int32		lower;
-	int32		upper;
+  int32		lower;
+  int32		upper;
 } int32KEY;
 
 /*
 
 static bool
 
+static int

 typedef struct int64key
 {

 static bool
 
 typedef struct

+static int
 
 typedef struct
 {

 static bool
 
 typedef struct
 {

+static int
 
 /*
 ** Bytea ops

 
 
 #include "btree_gist.h"
 
 typedef struct
 {

 static bool
 
 /*
 ** Text ops

 
 
 typedef struct

 #ifdef USE_FLOAT8_BYVAL

+static int
 
 typedef struct
 {

 #ifdef USE_FLOAT8_BYVAL

 static bool
 
-
+/*

 
 typedef struct

 static int

+ <para>
 
 /*
 
+/*
 
+/*
2.48.0

---

From: Bernd Helmle <[email-masked]>
Date: Tue, 11 Mar 2025 19:28:54 +0100

Hi,

> cidr datatype to pass down to the sortsupport function.

Please find a new rebased version of this patch. No changes to the
patch itself, but it didn't apply without conflicts anymore.

Thanks,
	Bernd

From 5cd326a29d5f6bb7ffb0c6328870cfd113ed1b42 Mon Sep 17 00:00:00 2001
From: Bernd Helmle <Bernd Helmle [email-masked]>
Date: Tue, 11 Mar 2025 19:15:13 +0100
Subject: [PATCH] Add support for sorted gist index builds to btree_gist

 

 
+static int
 
 #include "btree_gist.h"
 
 typedef struct boolkey
 {
 
 static bool

 /*

 
 
 typedef struct
 {
 
 static bool
 
 typedef struct
 {
 
 static bool

+static int
 
 #include "btree_gist.h"
 
 typedef struct float4key
 
 static bool
 
 #include "btree_gist.h"
 
 typedef struct float8key

 static bool
 
 typedef struct inetkey
 {

+static int
 
 #include "btree_gist.h"
 
 typedef struct int16key
 
 static bool
 
 typedef struct int32key
 {
-	int32		lower;
-	int32		upper;
+  int32		lower;
+  int32		upper;
 } int32KEY;
 
 /*
 
 static bool
 
+static int

 typedef struct int64key
 {

 static bool
 
 typedef struct

+static int
 
 typedef struct
 {

 static bool
 
 typedef struct
 {

+static int
 
 /*
 ** Bytea ops

 
 
 #include "btree_gist.h"
 
 typedef struct
 {

 static bool
 
 /*
 ** Text ops

 
 
 typedef struct

 #ifdef USE_FLOAT8_BYVAL

+static int
 
 typedef struct
 {

 #ifdef USE_FLOAT8_BYVAL

 static bool
 
-
+/*

 
 typedef struct

 static int

+ <para>
 
 /*
 
+/*
 
+/*
index 19100482ba4..4b812b680d4 100644
 { amprocfamily => 'gist/range_ops', amproclefttype => 'any',
   amprocrighttype => 'any', amprocnum => '12',
index 42e427f8fe8..9e423d9d970 100644
@@ -10854,6 +10854,9 @@
2.48.1

---

From: Heikki Linnakangas <[email-masked]>
Date: Wed, 2 Apr 2025 20:18:33 +0300

On 11/03/2025 20:28, Bernd Helmle wrote:
> Please find a new rebased version of this patch.

Hmm, if we implement sortsupport function for GiST, we can register it 
for B-tree opfamily as well. The range comparison function has quite 
high overhead thanks to detoasting, but I'm nevertheless seeing a tiny 
speedup. I tested that with:

setup:

create table intranges (r int4range);
insert into intranges select int4range(g, g+10) from generate_series(1, 
1000000) g;
vacuum freeze intranges;

test script 'rangesort.sql':

set work_mem='100 MB';
explain analyze select r from intranges order by r;

test:

pgbench -n -f rangesort.sql -P1 postgres -t100

On my laptop, that reports avg latency of 152 ms on master, and 149 ms 
latency with the patch. Nothing to write home about, but we might as 
well take it if we have the sortsupport function for gist anyway.

So I added it for the btree opfamily too, and moved the function to 
rangetypes.c since it's not just for gist anymore. I Ccmmitted that 
part, and will start looking more closely at the remaining btree_gist 
parts now.

-- 
Heikki Linnakangas
Neon (https://neon.tech)

---

From: Heikki Linnakangas <[email-masked]>
Date: Wed, 2 Apr 2025 22:41:48 +0300

> part, and will start looking more closely at the remaining btree_gist 

Here's an updated version of the remaining parts. Found a couple of bugs:

* The stuff to save the FmgrInfo for gbt_enum_sortsupport() was broken. 
It saved the address of FmgrInfo struct that was allocated in a local 
variable, on the stack, in SortSupport->ssup-extra, and expected it to 
be valid on subsequent call to gbt_enum_ssup_cmp(). It went unnoticed 
because enum_cmp() only accesses the FmgrInfo struct if it encounters 
odd enum values, i.e. enum values that have been added with ALTER TYPE 
ADD VALUE. I fixed that, and modified the existing enum test to cover 
that case.

* The gist_bpchar_ops opfamily was using the built-in 
bpchar_sortsupport() function directly. That's not right, you need to 
have a shim that extracts and comparse just the 'lower' value, just like 
for all other datatypes. I think that was just a simple oversight, but 
it happened to pass the tests because bpchar_sortsupport() would not 
outright crash, even though we were passing it garbage. It's interesting 
that because the gist sortsupport function is used just to order the 
input during build, everything still works if it sorts the input to a 
completely bogus ordering, it just gets slower. At one point while 
fixing that, I also accidentally used "btcharcmp" instead of 
"bpcharcmp", and all the tests passed with that too.

Those are now fixed. I also harmonized the comments to use the same 
phrasing for all the datatypes, marked all the sortsupport functions as 
PARALLEL SAFE, and reformatted slightly.

> +  by using the <literal>buffering</literal> parameter when creating the index.

I'm inclined to leave out this paragraph. That's not specific to the 
btree_gist module, you can make any GiST index slower by disabling the 
sorted mode; but why would you do that? Let's mention in the release 
notes that btree_gist index builds got faster, and leave it at that.

-- 
Heikki Linnakangas
Neon (https://neon.tech)
From e447f8ebe2510dc7d6494a5a6e6ea7b09c8542be Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <[email-masked]>
Date: Wed, 2 Apr 2025 22:24:55 +0300
Subject: [PATCH v2 1/1] Add support for sorted gist index builds to btree_gist

builds of gist indexes.

Sorted gist index build strategy is the new default now. Regression
tests are unchanged (except for one small change in the 'enum' test to
add coverage for enum values added later) and are using the sorted
build strategy instead.

One version of this was committed a long time ago already, in commit
9f984ba6d2, but it was reverted because of buildfarm failures. The
failures were presumably caused by some small bugs, but we never got
around to debug and commit it again. This patch was written from
scratch, implementing the same idea, with some fragments copied from
the original patch.

Author: Bernd Helmle <[email-masked]>
Author: Andrey Borodin <[email-masked]>
Discussion: https://www.postgresql.org/message-id/[email-masked]
---
 contrib/btree_gist/Makefile                 |   2 +-
 contrib/btree_gist/btree_bit.c              |  46 +++++
 contrib/btree_gist/btree_bool.c             |  23 +++
 contrib/btree_gist/btree_bytea.c            |  35 ++++
 contrib/btree_gist/btree_cash.c             |  30 +++
 contrib/btree_gist/btree_date.c             |  27 +++
 contrib/btree_gist/btree_enum.c             |  39 ++++
 contrib/btree_gist/btree_float4.c           |  26 +++
 contrib/btree_gist/btree_float8.c           |  25 +++
 contrib/btree_gist/btree_gist--1.8--1.9.sql | 197 ++++++++++++++++++++
 contrib/btree_gist/btree_gist.control       |   2 +-
 contrib/btree_gist/btree_inet.c             |  28 +++
 contrib/btree_gist/btree_int2.c             |  27 +++
 contrib/btree_gist/btree_int4.c             |  29 ++-
 contrib/btree_gist/btree_int8.c             |  27 +++
 contrib/btree_gist/btree_interval.c         |  25 +++
 contrib/btree_gist/btree_macaddr.c          |  27 +++
 contrib/btree_gist/btree_macaddr8.c         |  25 +++
 contrib/btree_gist/btree_numeric.c          |  34 ++++
 contrib/btree_gist/btree_oid.c              |  28 +++
 contrib/btree_gist/btree_text.c             |  69 +++++++
 contrib/btree_gist/btree_time.c             |  26 +++
 contrib/btree_gist/btree_ts.c               |  25 +++
 contrib/btree_gist/btree_utils_var.h        |  12 +-
 contrib/btree_gist/btree_uuid.c             |  25 +++
 contrib/btree_gist/expected/enum.out        |   5 +-
 contrib/btree_gist/meson.build              |   1 +
 contrib/btree_gist/sql/enum.sql             |   6 +-
 doc/src/sgml/btree-gist.sgml                |   7 +
 29 files changed, 870 insertions(+), 8 deletions(-)
 create mode 100644 contrib/btree_gist/btree_gist--1.8--1.9.sql

index f346b956fa9..5e0adbe51ef 100644

 
+static int
+	/* for leaf items we expect lower == upper, so only compare lower */
index adb724e16ac..08d6912bb4d 100644
 
 #include "btree_gist.h"
 
 typedef struct boolkey
 {
@@ -22,6 +23,17 @@ PG_FUNCTION_INFO_V1(gbt_bool_picksplit);
 PG_FUNCTION_INFO_V1(gbt_bool_consistent);
 PG_FUNCTION_INFO_V1(gbt_bool_penalty);
 PG_FUNCTION_INFO_V1(gbt_bool_same);
+PG_FUNCTION_INFO_V1(gbt_bool_sortsupport);
+
+static int
+gbt_bool_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	boolKEY    *arg1 = (boolKEY *) DatumGetPointer(x);
+	boolKEY    *arg2 = (boolKEY *) DatumGetPointer(y);
+
+	/* for leaf items we expect lower == upper, so only compare lower */
+	return (int32) arg1->lower - (int32) arg2->lower;
+}
 
 static bool
@@ -166,3 +178,14 @@ gbt_bool_same(PG_FUNCTION_ARGS)
index 2e14bdfd328..efe3c212367 100644

 /*
 
+	/* for leaf items we expect lower == upper, so only compare lower */

index c18c34c8b83..b980edbaf44 100644
 
 typedef struct
 {
@@ -25,6 +26,24 @@ PG_FUNCTION_INFO_V1(gbt_cash_consistent);
+	/* for leaf items we expect lower == upper, so only compare lower */
 
 static bool
@@ -215,3 +234,14 @@ gbt_cash_same(PG_FUNCTION_ARGS)
index 7a4a9d7a853..adb3a217e30 100644
 
 typedef struct
 {
@@ -25,6 +26,32 @@ PG_FUNCTION_INFO_V1(gbt_date_consistent);
+gbt_date_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+	/* for leaf items we expect lower == upper, so only compare lower */
 
 static bool
 gbt_dategt(const void *a, const void *b, FmgrInfo *flinfo)
diff --git a/contrib/btree_gist/btree_enum.c b/contrib/btree_gist/btree_enum.c
index 05d02e704a0..a29b59eb698 100644
--- a/contrib/btree_gist/btree_enum.c
+++ b/contrib/btree_gist/btree_enum.c
@@ -7,6 +7,8 @@
 #include "btree_utils_num.h"
 #include "fmgr.h"
 #include "utils/fmgrprotos.h"
+#include "utils/fmgroids.h"
+#include "utils/sortsupport.h"

@@ -26,8 +28,23 @@ PG_FUNCTION_INFO_V1(gbt_enum_picksplit);

+static int
+gbt_enum_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	oidKEY	   *arg1 = (oidKEY *) DatumGetPointer(x);
+	oidKEY	   *arg2 = (oidKEY *) DatumGetPointer(y);
+
+	/* for leaf items we expect lower == upper, so only compare lower */
+	return DatumGetInt32(CallerFInfoFunctionCall2(enum_cmp,
+												  ssup->ssup_extra,
+												  InvalidOid,
+												  arg1->lower,
+												  arg2->lower));
+}
+
 static bool
 gbt_enumgt(const void *a, const void *b, FmgrInfo *flinfo)
 {
@@ -183,3 +200,25 @@ gbt_enum_same(PG_FUNCTION_ARGS)
 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
+
+Datum
+gbt_enum_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+	FmgrInfo   *flinfo;
+
+	ssup->comparator = gbt_enum_ssup_cmp;
+
+	/*
+	 * Since gbt_enum_ssup_cmp() uses enum_cmp() like the rest of the
+	 * comparison functions, it also needs to pass flinfo when calling it. The
+	 * caller to a SortSupport comparison function doesn't provide an FmgrInfo
+	 * struct, so look it up now, save it in ssup_extra and use it in
+	 * gbt_enum_ssup_cmp() later.
+	 */
+	flinfo = MemoryContextAlloc(ssup->ssup_cxt, sizeof(FmgrInfo));
+	fmgr_info_cxt(F_ENUM_CMP, flinfo, ssup->ssup_cxt);
+	ssup->ssup_extra = flinfo;
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/btree_gist/btree_float4.c b/contrib/btree_gist/btree_float4.c
index d138aa94bf2..0b4ce16eada 100644
--- a/contrib/btree_gist/btree_float4.c
+++ b/contrib/btree_gist/btree_float4.c
@@ -5,6 +5,7 @@
 
 #include "btree_gist.h"
 
 typedef struct float4key
@@ -24,6 +25,31 @@ PG_FUNCTION_INFO_V1(gbt_float4_consistent);
+	/* for leaf items we expect lower == upper, so only compare lower */
+	return float4_cmp_internal(arg1->lower, arg2->lower);
 
 static bool
index a74cd200529..bfa7f825000 100644
 
 #include "btree_gist.h"
 
 typedef struct float8key
@@ -24,7 +25,31 @@ PG_FUNCTION_INFO_V1(gbt_float8_consistent);
 
+	/* for leaf items we expect lower == upper, so only compare lower */
+	return float8_cmp_internal(arg1->lower, arg2->lower);
 
 static bool
index 00000000000..4b38749bf5f
@@ -0,0 +1,197 @@
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+CREATE FUNCTION gbt_bpchar_sortsupport(internal)
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+	FUNCTION	11  (bpchar, bpchar) gbt_bpchar_sortsupport (internal) ;
index 4cffd349091..ade85b853e8 100644
 
 typedef struct inetkey
 {
@@ -23,8 +24,24 @@ PG_FUNCTION_INFO_V1(gbt_inet_picksplit);

+static int
+	/* for leaf items we expect lower == upper, so only compare lower */
@@ -184,3 +201,14 @@ gbt_inet_same(PG_FUNCTION_ARGS)
index 1751a6c055d..87655b33598 100644
 
 #include "btree_gist.h"
 
 typedef struct int16key
@@ -24,6 +25,32 @@ PG_FUNCTION_INFO_V1(gbt_int2_consistent);
+	/* for leaf items we expect lower == upper, so only compare lower */
 
 static bool
index 90d183be6e8..e0ddeb6e775 100644
@@ -2,10 +2,10 @@
 
 typedef struct int32key
 {
 
 static bool
 
+static int
+	/* for leaf items we expect lower == upper, so only compare lower */
 
index 661cf8189fc..6c525c67220 100644
 
 typedef struct int64key
 {
@@ -24,7 +25,33 @@ PG_FUNCTION_INFO_V1(gbt_int8_consistent);
 
+	/* for leaf items we expect lower == upper, so only compare lower */
 
 static bool
index 8f99a416965..58633f5a894 100644
 
 typedef struct

+static int
+	/* for leaf items we expect lower == upper, so only compare lower */
index 558cfa2172f..cecfe2271e5 100644
 
 typedef struct
 {
@@ -25,6 +26,32 @@ PG_FUNCTION_INFO_V1(gbt_macad_picksplit);
+	/* for leaf items we expect lower == upper, so only compare lower */

 static bool
index 5d0c5509f51..481c303795d 100644
 
 typedef struct
 {
@@ -25,8 +26,21 @@ PG_FUNCTION_INFO_V1(gbt_macad8_picksplit);

+static int
+	/* for leaf items we expect lower == upper, so only compare lower */
@@ -194,3 +208,14 @@ gbt_macad8_same(PG_FUNCTION_ARGS)
index d533648a295..736896e7755 100644
 
 /*
 ** Bytea ops
@@ -21,7 +22,40 @@ PG_FUNCTION_INFO_V1(gbt_numeric_picksplit);
 
+	/* for leaf items we expect lower == upper, so only compare lower */

diff --git a/contrib/btree_gist/btree_oid.c b/contrib/btree_gist/btree_oid.c
index d1976f4f091..c6b7dc61366 100644
--- a/contrib/btree_gist/btree_oid.c
+++ b/contrib/btree_gist/btree_oid.c
@@ -5,6 +5,7 @@
 
 #include "btree_gist.h"
 
 typedef struct
 {
 
+	/* for leaf items we expect lower == upper, so only compare lower */
 
 static bool
index 8f80f54240f..5783dc4cc7d 100644
 
 /*
 ** Text ops
@@ -19,7 +20,42 @@ 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);
+PG_FUNCTION_INFO_V1(gbt_bpchar_sortsupport);
 
+	/* for leaf items we expect lower == upper, so only compare lower */

@@ -93,6 +129,39 @@ static gbtree_vinfo tinfo =
 
 /* bpchar needs its own comparison rules */
 
+static int
+gbt_bpchar_ssup_cmp(Datum x, Datum y, SortSupport ssup)
+{
+	GBT_VARKEY *key1 = PG_DETOAST_DATUM(x);
+	GBT_VARKEY *key2 = PG_DETOAST_DATUM(y);
+
+	GBT_VARKEY_R arg1 = gbt_var_key_readable(key1);
+	GBT_VARKEY_R arg2 = gbt_var_key_readable(key2);
+	Datum		result;
+
+	/* for leaf items we expect lower == upper, so only compare lower */
+	result = DirectFunctionCall2Coll(bpcharcmp,
+									 ssup->ssup_collation,
+									 PointerGetDatum(arg1.lower),
+									 PointerGetDatum(arg2.lower));
+
+	GBT_FREE_IF_COPY(key1, x);
+	GBT_FREE_IF_COPY(key2, y);
+
+	return DatumGetInt32(result);
+}
+
+Datum
+gbt_bpchar_sortsupport(PG_FUNCTION_ARGS)
+{
+	SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
+
+	ssup->comparator = gbt_bpchar_ssup_cmp;
+	ssup->ssup_extra = NULL;
+
+	PG_RETURN_VOID();
+}
+
 static bool
 gbt_bpchargt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
 {
diff --git a/contrib/btree_gist/btree_time.c b/contrib/btree_gist/btree_time.c
index 2f7859340f6..6c0f0628f9f 100644
--- a/contrib/btree_gist/btree_time.c
+++ b/contrib/btree_gist/btree_time.c
@@ -7,6 +7,7 @@
 #include "btree_utils_num.h"
 #include "utils/fmgrprotos.h"
 #include "utils/date.h"
+#include "utils/sortsupport.h"
 #include "utils/timestamp.h"
 
 typedef struct

 #ifdef USE_FLOAT8_BYVAL

+static int
+	/* for leaf items we expect lower == upper, so only compare lower */
index 9e0d979dda9..06a745be865 100644
 
 typedef struct
 {

 #ifdef USE_FLOAT8_BYVAL
 
+	/* for leaf items we expect lower == upper, so only compare lower */
 
 static bool
 
-
+/*

index f4c5c6e5892..ce040a025e7 100644
 
 typedef struct
 
+	/* for leaf items we expect lower == upper, so only compare lower */
 
 static int
 uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2)
diff --git a/contrib/btree_gist/expected/enum.out b/contrib/btree_gist/expected/enum.out
index c4b769dd4b7..5782f438838 100644
--- a/contrib/btree_gist/expected/enum.out
+++ b/contrib/btree_gist/expected/enum.out
@@ -1,5 +1,8 @@
 -- enum check
-create type rainbow as enum ('r','o','y','g','b','i','v');
+create type rainbow as enum ('r','o','g','b','i','v');
+-- enum values added later take some different codepaths internally,
+-- so make sure we have coverage for those too
+alter type rainbow add value 'y' before 'g';
 CREATE TABLE enumtmp (a rainbow);
 \copy enumtmp from 'data/enum.data'
 SET enable_seqscan=on;
diff --git a/contrib/btree_gist/meson.build b/contrib/btree_gist/meson.build
index f4fa9574f1f..89932dd3844 100644
--- a/contrib/btree_gist/meson.build
+++ b/contrib/btree_gist/meson.build
@@ -51,6 +51,7 @@ install_data(
   'btree_gist--1.5--1.6.sql',
   'btree_gist--1.6--1.7.sql',
   'btree_gist--1.7--1.8.sql',
+  'btree_gist--1.8--1.9.sql',
   kwargs: contrib_data_args,
 )
 
diff --git a/contrib/btree_gist/sql/enum.sql b/contrib/btree_gist/sql/enum.sql
index 476211e9795..d662cb63221 100644
--- a/contrib/btree_gist/sql/enum.sql
+++ b/contrib/btree_gist/sql/enum.sql
@@ -1,6 +1,10 @@
 -- enum check
 
-create type rainbow as enum ('r','o','y','g','b','i','v');
+create type rainbow as enum ('r','o','g','b','i','v');
+
+-- enum values added later take some different codepaths internally,
+-- so make sure we have coverage for those too
+alter type rainbow add value 'y' before 'g';
 
 CREATE TABLE enumtmp (a rainbow);

+ <para>
2.39.5

---

From: Heikki Linnakangas <[email-masked]>
Date: Thu, 3 Apr 2025 14:13:38 +0300

> Here's an updated version of the remaining parts. Found a couple of bugs:

Committed with some further cosmetic fixes. Thanks for the patience, 
this has been lingering for a long time, especially if you count the 
earlier attempt back in 2021!

-- 
Heikki Linnakangas
Neon (https://neon.tech)

---

From: Bernd Helmle <[email-masked]>
Date: Thu, 03 Apr 2025 17:00:43 +0200

> ADD VALUE. I fixed that, and modified the existing enum test to cover

Ugh, i obviously didn't pay enough attention here. 

> "bpcharcmp", and all the tests passed with that too.

Yes, i missed that. Originally the code did this all over the place
with many other types, too. I seem to have overseen this somehow.

> PARALLEL SAFE, and reformatted slightly.

Note that the original coding was by Christoph Heiss and i picked up
his work and rewrote/fixed especially the part with the direct use of
sortsupport functions and many other issues spotted by testing and by
Andrey.

Many thanks for picking this up. There are users out there which are
going to be very happy with this if no further issues arise. :)

---

From: Heikki Linnakangas <[email-masked]>
Date: Thu, 3 Apr 2025 18:18:52 +0300

> sortsupport functions and many other issues spotted by testing and by

Sorry Christoph I missed you in the commit message!

-- 
Heikki Linnakangas
Neon (https://neon.tech)

---

From: Andrey Borodin <[email-masked]>
Date: Thu, 3 Apr 2025 20:49:52 +0500

> On 3 Apr 2025, at 16:13, Heikki Linnakangas <[email-masked]> wrote:
> 
> Committed

Cool! Thank you!!!