On 02/26/2017 04:09 PM, Andrew Dunstan wrote:
>
> On 02/26/2017 03:26 PM, Tom Lane wrote:
>> Andrew Dunstan <andrew.duns...@2ndquadrant.com> writes:
>>> This works for the btree_gin case. However, there's a difficulty for
>>> btree_gist - in the puicksplit routine the cmp function is passed to
>>> qsort() so there is no chance to pass it an flinfo to set up the call to
>>> the real comparison routine. Implementing a custom sort routine to work
>>> around the problem seems a bridge too far. I can;t think of an
>>> alternative off hand.
>> We already have qsort_arg ... can't you change it to use that?
>>
>>                      
>
> Yes, wasn't aware of that, that looks like exactly what I need. thanks.
>
>


OK, here's the whole series of patches.


Patch 1 adds the CallerFInfoFunctionCall{1,2} functions.

Patch 2 adds btree_gist support for their use for non-varlena types

Patch 3 does the same for varlena types (Not required for patch 4, but
better to be consistent, I think.)

Patch 4 adds enum support to btree_gist

Patch 5 adds enum support to btree_gin

cheers

andrew

-- 
Andrew Dunstan                https://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

>From 74ebe1490de916409458e3d1adf47dfa20b1fefb Mon Sep 17 00:00:00 2001
From: Andrew Dunstan <and...@dunslane.net>
Date: Mon, 27 Feb 2017 15:41:03 -0500
Subject: [PATCH 4/4] Add btree_gist support for enum types.

This will alow enums to be used in exclusio n constraints.

The code uses the new CallerFInfoFunctionCall infrastructure in fmgr,
and the support for it added to btree_gist in a nearby patch.
---
 contrib/btree_gist/Makefile                 |   8 +-
 contrib/btree_gist/btree_enum.c             | 187 +++++++++
 contrib/btree_gist/btree_gist--1.3--1.4.sql |  69 ++++
 contrib/btree_gist/btree_gist.control       |   2 +-
 contrib/btree_gist/btree_gist.h             |   3 +-
 contrib/btree_gist/btree_utils_num.c        |   2 +
 contrib/btree_gist/data/enum.data           | 595 ++++++++++++++++++++++++++++
 contrib/btree_gist/expected/enum.out        |  91 +++++
 contrib/btree_gist/sql/enum.sql             |  38 ++
 doc/src/sgml/btree-gist.sgml                |   2 +-
 10 files changed, 991 insertions(+), 6 deletions(-)
 create mode 100644 contrib/btree_gist/btree_enum.c
 create mode 100644 contrib/btree_gist/btree_gist--1.3--1.4.sql
 create mode 100644 contrib/btree_gist/data/enum.data
 create mode 100644 contrib/btree_gist/expected/enum.out
 create mode 100644 contrib/btree_gist/sql/enum.sql

diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile
index d36f517..beb2ed7 100644
--- a/contrib/btree_gist/Makefile
+++ b/contrib/btree_gist/Makefile
@@ -6,16 +6,18 @@ OBJS =  btree_gist.o btree_utils_num.o btree_utils_var.o btree_int2.o \
         btree_int4.o btree_int8.o btree_float4.o btree_float8.o btree_cash.o \
         btree_oid.o btree_ts.o btree_time.o btree_date.o btree_interval.o \
         btree_macaddr.o btree_inet.o btree_text.o btree_bytea.o btree_bit.o \
-        btree_numeric.o btree_uuid.o $(WIN32RES)
+        btree_numeric.o btree_uuid.o btree_enum.o $(WIN32RES)
 
 EXTENSION = btree_gist
 DATA = btree_gist--unpackaged--1.0.sql 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.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql \
+	   btree_gist--1.3--1.4.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 inet cidr text varchar char bytea \
-        bit varbit numeric uuid not_equal
+        bit varbit numeric uuid enum not_equal
 
 SHLIB_LINK += $(filter -lm, $(LIBS))
 
diff --git a/contrib/btree_gist/btree_enum.c b/contrib/btree_gist/btree_enum.c
new file mode 100644
index 0000000..5e46e78
--- /dev/null
+++ b/contrib/btree_gist/btree_enum.c
@@ -0,0 +1,187 @@
+/*
+ * contrib/btree_gist/btree_enum.c
+ */
+#include "postgres.h"
+#include "fmgr.h"
+#include "utils/builtins.h"
+
+#include "btree_gist.h"
+#include "btree_utils_num.h"
+
+/* enums are really Oids, so we just use the same structure */
+
+typedef struct
+{
+	Oid			lower;
+	Oid			upper;
+} oidKEY;
+
+/*
+** enum ops
+*/
+PG_FUNCTION_INFO_V1(gbt_enum_compress);
+PG_FUNCTION_INFO_V1(gbt_enum_fetch);
+PG_FUNCTION_INFO_V1(gbt_enum_union);
+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);
+
+
+static bool
+gbt_enumgt(const void *a, const void *b, FmgrInfo *flinfo)
+{
+	return DatumGetBool(
+		CallerFInfoFunctionCall2(enum_gt, flinfo, InvalidOid, ObjectIdGetDatum(*((const Oid *) a)), ObjectIdGetDatum(*((const Oid *) b)))
+		);
+}
+static bool
+gbt_enumge(const void *a, const void *b, FmgrInfo *flinfo)
+{
+	return DatumGetBool(
+		CallerFInfoFunctionCall2(enum_ge, flinfo, InvalidOid, ObjectIdGetDatum(*((const Oid *) a)), ObjectIdGetDatum(*((const Oid *) b)))
+		);
+}
+static bool
+gbt_enumeq(const void *a, const void *b, FmgrInfo *flinfo)
+{
+	return (*((const Oid *) a) == *((const Oid *) b));
+}
+static bool
+gbt_enumle(const void *a, const void *b, FmgrInfo *flinfo)
+{
+	return DatumGetBool(
+						CallerFInfoFunctionCall2(enum_le, flinfo, InvalidOid, ObjectIdGetDatum(*((const Oid *) a)), ObjectIdGetDatum(*((const Oid *) b)))
+		);
+}
+static bool
+gbt_enumlt(const void *a, const void *b, FmgrInfo *flinfo)
+{
+	return DatumGetBool(
+						CallerFInfoFunctionCall2(enum_lt, flinfo, InvalidOid, ObjectIdGetDatum(*((const Oid *) a)), ObjectIdGetDatum(*((const Oid *) b)))
+		);
+}
+
+static int
+gbt_enumkey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
+{
+	oidKEY	   *ia = (oidKEY *) (((const Nsrt *) a)->t);
+	oidKEY	   *ib = (oidKEY *) (((const Nsrt *) b)->t);
+
+	if (ia->lower == ib->lower)
+	{
+		if (ia->upper == ib->upper)
+			return 0;
+
+		return DatumGetInt32(
+			CallerFInfoFunctionCall2(enum_cmp, flinfo, InvalidOid, ObjectIdGetDatum(ia->upper), ObjectIdGetDatum(ib->upper))
+			);
+	}
+
+	return DatumGetInt32(
+		CallerFInfoFunctionCall2(enum_cmp, flinfo, InvalidOid, ObjectIdGetDatum(ia->lower), ObjectIdGetDatum(ib->lower))
+		);
+}
+
+static const gbtree_ninfo tinfo =
+{
+	gbt_t_enum,
+	sizeof(Oid),
+	8,							/* sizeof(gbtreekey8) */
+	gbt_enumgt,
+	gbt_enumge,
+	gbt_enumeq,
+	gbt_enumle,
+	gbt_enumlt,
+	gbt_enumkey_cmp,
+	NULL /* no KNN support at least for now */
+};
+
+
+/**************************************************
+ * Enum ops
+ **************************************************/
+
+
+Datum
+gbt_enum_compress(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
+}
+
+Datum
+gbt_enum_fetch(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
+}
+
+Datum
+gbt_enum_consistent(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	Oid			query = PG_GETARG_OID(1);
+	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+
+	/* Oid		subtype = PG_GETARG_OID(3); */
+	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
+	oidKEY	   *kkk = (oidKEY *) DatumGetPointer(entry->key);
+	GBT_NUMKEY_R key;
+
+	/* All cases served by this function are exact */
+	*recheck = false;
+
+	key.lower = (GBT_NUMKEY *) &kkk->lower;
+	key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+	PG_RETURN_BOOL(
+				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
+		);
+}
+
+Datum
+gbt_enum_union(PG_FUNCTION_ARGS)
+{
+	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+	void	   *out = palloc(sizeof(oidKEY));
+
+	*(int *) PG_GETARG_POINTER(1) = sizeof(oidKEY);
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
+}
+
+
+Datum
+gbt_enum_penalty(PG_FUNCTION_ARGS)
+{
+	oidKEY	   *origentry = (oidKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
+	oidKEY	   *newentry = (oidKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
+	float	   *result = (float *) PG_GETARG_POINTER(2);
+
+	penalty_num(result, origentry->lower, origentry->upper, newentry->lower, newentry->upper);
+
+	PG_RETURN_POINTER(result);
+}
+
+Datum
+gbt_enum_picksplit(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_POINTER(gbt_num_picksplit(
+									(GistEntryVector *) PG_GETARG_POINTER(0),
+									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
+										&tinfo, fcinfo->flinfo
+										));
+}
+
+Datum
+gbt_enum_same(PG_FUNCTION_ARGS)
+{
+	oidKEY	   *b1 = (oidKEY *) PG_GETARG_POINTER(0);
+	oidKEY	   *b2 = (oidKEY *) PG_GETARG_POINTER(1);
+	bool	   *result = (bool *) PG_GETARG_POINTER(2);
+
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
+	PG_RETURN_POINTER(result);
+}
diff --git a/contrib/btree_gist/btree_gist--1.3--1.4.sql b/contrib/btree_gist/btree_gist--1.3--1.4.sql
new file mode 100644
index 0000000..1233aec
--- /dev/null
+++ b/contrib/btree_gist/btree_gist--1.3--1.4.sql
@@ -0,0 +1,69 @@
+/* contrib/btree_gist/btree_gist--1.3--1.4.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.4'" to load this file. \quit
+
+--
+--
+--
+-- enum ops
+--
+--
+--
+-- define the GiST support methods
+CREATE FUNCTION gbt_enum_consistent(internal,anyenum,int2,oid,internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_enum_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_enum_fetch(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_enum_penalty(internal,internal,internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_enum_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_enum_union(internal, internal)
+RETURNS gbtreekey8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_enum_same(gbtreekey8, gbtreekey8, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+-- Create the operator class
+CREATE OPERATOR CLASS gist_enum_ops
+DEFAULT FOR TYPE anyenum USING gist
+AS
+	OPERATOR	1	<  ,
+	OPERATOR	2	<= ,
+	OPERATOR	3	=  ,
+	OPERATOR	4	>= ,
+	OPERATOR	5	>  ,
+	FUNCTION	1	gbt_enum_consistent (internal, anyenum, int2, oid, internal),
+	FUNCTION	2	gbt_enum_union (internal, internal),
+	FUNCTION	3	gbt_enum_compress (internal),
+	FUNCTION	4	gbt_decompress (internal),
+	FUNCTION	5	gbt_enum_penalty (internal, internal, internal),
+	FUNCTION	6	gbt_enum_picksplit (internal, internal),
+	FUNCTION	7	gbt_enum_same (gbtreekey8, gbtreekey8, internal),
+	STORAGE		gbtreekey8;
+
+ALTER OPERATOR FAMILY gist_enum_ops USING gist ADD
+	OPERATOR	6	<> (anyenum, anyenum) ,
+	FUNCTION	9 (anyenum, anyenum) gbt_enum_fetch (internal) ;
diff --git a/contrib/btree_gist/btree_gist.control b/contrib/btree_gist/btree_gist.control
index ddbf83d..fdf0e6a 100644
--- a/contrib/btree_gist/btree_gist.control
+++ b/contrib/btree_gist/btree_gist.control
@@ -1,5 +1,5 @@
 # btree_gist extension
 comment = 'support for indexing common datatypes in GiST'
-default_version = '1.3'
+default_version = '1.4'
 module_pathname = '$libdir/btree_gist'
 relocatable = true
diff --git a/contrib/btree_gist/btree_gist.h b/contrib/btree_gist/btree_gist.h
index 9b3e22c..219ca89 100644
--- a/contrib/btree_gist/btree_gist.h
+++ b/contrib/btree_gist/btree_gist.h
@@ -32,7 +32,8 @@ enum gbtree_type
 	gbt_t_bytea,
 	gbt_t_bit,
 	gbt_t_inet,
-	gbt_t_uuid
+	gbt_t_uuid,
+	gbt_t_enum
 };
 
 #endif
diff --git a/contrib/btree_gist/btree_utils_num.c b/contrib/btree_gist/btree_utils_num.c
index e30924b..d4fee91 100644
--- a/contrib/btree_gist/btree_utils_num.c
+++ b/contrib/btree_gist/btree_utils_num.c
@@ -48,6 +48,7 @@ gbt_num_compress(GISTENTRY *entry, const gbtree_ninfo *tinfo)
 				leaf = &v.i8;
 				break;
 			case gbt_t_oid:
+			case gbt_t_enum:
 				v.i4 = DatumGetObjectId(entry->key);
 				leaf = &v.i4;
 				break;
@@ -122,6 +123,7 @@ gbt_num_fetch(GISTENTRY *entry, const gbtree_ninfo *tinfo)
 			datum = Int64GetDatum(*(int64 *) entry->key);
 			break;
 		case gbt_t_oid:
+		case gbt_t_enum:
 			datum = ObjectIdGetDatum(*(Oid *) entry->key);
 			break;
 		case gbt_t_float4:
diff --git a/contrib/btree_gist/data/enum.data b/contrib/btree_gist/data/enum.data
new file mode 100644
index 0000000..d03bfce
--- /dev/null
+++ b/contrib/btree_gist/data/enum.data
@@ -0,0 +1,595 @@
+r
+v
+i
+b
+r
+\N
+y
+v
+g
+o
+y
+b
+o
+o
+o
+o
+v
+r
+i
+o
+b
+r
+g
+b
+i
+o
+r
+r
+r
+\N
+o
+b
+v
+y
+o
+\N
+i
+o
+o
+g
+g
+b
+y
+v
+g
+g
+\N
+v
+g
+i
+i
+\N
+v
+y
+i
+r
+\N
+r
+\N
+g
+\N
+g
+\N
+v
+g
+y
+v
+r
+v
+r
+v
+y
+i
+i
+v
+y
+v
+i
+b
+i
+i
+r
+r
+\N
+\N
+y
+r
+g
+i
+y
+i
+i
+r
+g
+y
+\N
+i
+o
+r
+y
+y
+g
+o
+o
+g
+y
+r
+g
+v
+r
+i
+r
+i
+r
+y
+v
+b
+i
+o
+r
+\N
+o
+i
+v
+o
+b
+\N
+b
+g
+y
+o
+v
+b
+i
+v
+v
+o
+y
+i
+i
+i
+g
+b
+b
+g
+r
+i
+y
+o
+\N
+r
+\N
+i
+i
+g
+v
+o
+y
+y
+o
+i
+b
+r
+y
+y
+o
+g
+g
+g
+\N
+y
+o
+v
+g
+y
+g
+v
+\N
+i
+o
+v
+b
+b
+\N
+y
+v
+\N
+v
+\N
+i
+\N
+r
+b
+r
+o
+r
+b
+o
+g
+i
+r
+b
+g
+g
+y
+b
+b
+g
+y
+g
+v
+v
+b
+\N
+i
+v
+y
+b
+b
+o
+g
+b
+v
+g
+g
+b
+\N
+y
+r
+r
+b
+\N
+r
+g
+i
+o
+v
+\N
+o
+r
+b
+o
+b
+i
+\N
+\N
+y
+b
+y
+\N
+i
+i
+i
+o
+y
+o
+i
+b
+o
+g
+r
+\N
+b
+y
+\N
+g
+b
+y
+y
+o
+o
+b
+g
+i
+i
+v
+b
+o
+o
+v
+i
+g
+i
+o
+r
+o
+i
+i
+r
+b
+g
+o
+o
+y
+v
+g
+g
+g
+r
+o
+i
+i
+g
+\N
+o
+v
+b
+b
+v
+i
+g
+y
+i
+i
+g
+r
+y
+i
+b
+\N
+g
+y
+o
+\N
+i
+i
+b
+v
+o
+b
+v
+r
+g
+o
+v
+v
+y
+r
+v
+g
+\N
+v
+v
+b
+y
+o
+g
+i
+o
+b
+r
+y
+r
+v
+b
+b
+\N
+i
+v
+y
+r
+b
+i
+y
+g
+\N
+g
+r
+y
+y
+g
+b
+o
+v
+r
+i
+g
+r
+b
+b
+b
+\N
+y
+y
+y
+i
+o
+r
+g
+g
+i
+y
+g
+y
+v
+o
+o
+g
+\N
+b
+v
+o
+y
+r
+\N
+o
+i
+g
+\N
+i
+i
+i
+o
+b
+\N
+\N
+b
+\N
+v
+v
+r
+\N
+o
+b
+r
+o
+b
+o
+r
+y
+\N
+r
+i
+b
+b
+y
+v
+r
+g
+r
+r
+\N
+g
+\N
+v
+v
+y
+r
+o
+r
+o
+i
+o
+\N
+r
+\N
+i
+v
+b
+v
+\N
+b
+r
+v
+o
+\N
+i
+r
+b
+g
+o
+\N
+o
+g
+r
+v
+y
+g
+v
+r
+b
+r
+v
+o
+g
+i
+i
+g
+i
+y
+b
+i
+y
+r
+y
+o
+r
+b
+y
+y
+b
+y
+g
+b
+\N
+r
+g
+b
+o
+y
+o
+g
+r
+g
+b
+\N
+v
+v
+v
+g
+b
+y
+v
+o
+v
+g
+o
+g
+i
+b
+v
+i
+r
+r
+i
+b
+i
+b
+o
+\N
+\N
+y
+r
+g
+v
+o
+y
+\N
+g
+v
+o
+b
+v
+v
+\N
+r
+v
+y
+g
+b
+o
+v
+b
+v
+b
+r
+r
+i
+r
+v
+y
+v
+y
+o
+v
+g
+i
+r
+o
+o
+i
+y
+r
+\N
+y
+r
+b
+y
+y
+\N
+b
+\N
+\N
+i
+v
diff --git a/contrib/btree_gist/expected/enum.out b/contrib/btree_gist/expected/enum.out
new file mode 100644
index 0000000..c4b769d
--- /dev/null
+++ b/contrib/btree_gist/expected/enum.out
@@ -0,0 +1,91 @@
+-- enum check
+create type rainbow as enum ('r','o','y','g','b','i','v');
+CREATE TABLE enumtmp (a rainbow);
+\copy enumtmp from 'data/enum.data'
+SET enable_seqscan=on;
+select a, count(*) from enumtmp group by a order by 1;
+ a | count 
+---+-------
+ r |    76
+ o |    78
+ y |    73
+ g |    75
+ b |    77
+ i |    78
+ v |    75
+   |    63
+(8 rows)
+
+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)
+
+CREATE INDEX enumidx ON enumtmp USING gist ( a );
+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/sql/enum.sql b/contrib/btree_gist/sql/enum.sql
new file mode 100644
index 0000000..476211e
--- /dev/null
+++ b/contrib/btree_gist/sql/enum.sql
@@ -0,0 +1,38 @@
+-- enum check
+
+create type rainbow as enum ('r','o','y','g','b','i','v');
+
+CREATE TABLE enumtmp (a rainbow);
+
+\copy enumtmp from 'data/enum.data'
+
+SET enable_seqscan=on;
+
+select a, count(*) from enumtmp group by a order by 1;
+
+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;
+
+CREATE INDEX enumidx ON enumtmp USING gist ( a );
+
+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/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index d08647c..358feb5 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -17,7 +17,7 @@
   <type>oid</>, <type>money</>, <type>char</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
   <type>varbit</>, <type>macaddr</>, <type>inet</>, <type>cidr</>,
-  and <type>uuid</>.
+  <type>uuid</> and all <type>enum</> types.
  </para>
 
  <para>
-- 
2.4.11

>From 087e53c587ea26c3abd1ca1f377005892b356eb3 Mon Sep 17 00:00:00 2001
From: Andrew Dunstan <and...@dunslane.net>
Date: Mon, 27 Feb 2017 14:26:51 -0500
Subject: [PATCH 3/4] Allow use of CallerFInfoFunctionCall with btree_gist for
 varlena types

---
 contrib/btree_gist/btree_bit.c       | 26 ++++++------
 contrib/btree_gist/btree_bytea.c     | 22 +++++------
 contrib/btree_gist/btree_numeric.c   | 22 +++++------
 contrib/btree_gist/btree_text.c      | 24 +++++------
 contrib/btree_gist/btree_utils_var.c | 77 +++++++++++++++++++-----------------
 contrib/btree_gist/btree_utils_var.h | 26 ++++++------
 6 files changed, 100 insertions(+), 97 deletions(-)

diff --git a/contrib/btree_gist/btree_bit.c b/contrib/btree_gist/btree_bit.c
index f34fa87..a57f45f 100644
--- a/contrib/btree_gist/btree_bit.c
+++ b/contrib/btree_gist/btree_bit.c
@@ -24,7 +24,7 @@ PG_FUNCTION_INFO_V1(gbt_bit_same);
 /* define for comparison */
 
 static bool
-gbt_bitgt(const void *a, const void *b, Oid collation)
+gbt_bitgt(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(bitgt,
 											PointerGetDatum(a),
@@ -32,7 +32,7 @@ gbt_bitgt(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_bitge(const void *a, const void *b, Oid collation)
+gbt_bitge(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(bitge,
 											PointerGetDatum(a),
@@ -40,7 +40,7 @@ gbt_bitge(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_biteq(const void *a, const void *b, Oid collation)
+gbt_biteq(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(biteq,
 											PointerGetDatum(a),
@@ -48,7 +48,7 @@ gbt_biteq(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_bitle(const void *a, const void *b, Oid collation)
+gbt_bitle(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(bitle,
 											PointerGetDatum(a),
@@ -56,7 +56,7 @@ gbt_bitle(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_bitlt(const void *a, const void *b, Oid collation)
+gbt_bitlt(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(bitlt,
 											PointerGetDatum(a),
@@ -64,7 +64,7 @@ gbt_bitlt(const void *a, const void *b, Oid collation)
 }
 
 static int32
-gbt_bitcmp(const void *a, const void *b, Oid collation)
+gbt_bitcmp(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetInt32(DirectFunctionCall2(byteacmp,
 											 PointerGetDatum(a),
@@ -92,7 +92,7 @@ gbt_bit_xfrm(bytea *leaf)
 
 
 static GBT_VARKEY *
-gbt_bit_l2n(GBT_VARKEY *leaf)
+gbt_bit_l2n(GBT_VARKEY *leaf, FmgrInfo *flinfo)
 {
 	GBT_VARKEY *out = leaf;
 	GBT_VARKEY_R r = gbt_var_key_readable(leaf);
@@ -152,13 +152,13 @@ gbt_bit_consistent(PG_FUNCTION_ARGS)
 
 	if (GIST_LEAF(entry))
 		retval = gbt_var_consistent(&r, query, strategy, PG_GET_COLLATION(),
-									TRUE, &tinfo);
+									TRUE, &tinfo, fcinfo->flinfo);
 	else
 	{
 		bytea	   *q = gbt_bit_xfrm((bytea *) query);
 
 		retval = gbt_var_consistent(&r, q, strategy, PG_GET_COLLATION(),
-									FALSE, &tinfo);
+									FALSE, &tinfo, fcinfo->flinfo);
 	}
 	PG_RETURN_BOOL(retval);
 }
@@ -172,7 +172,7 @@ gbt_bit_union(PG_FUNCTION_ARGS)
 	int32	   *size = (int *) PG_GETARG_POINTER(1);
 
 	PG_RETURN_POINTER(gbt_var_union(entryvec, size, PG_GET_COLLATION(),
-									&tinfo));
+									&tinfo, fcinfo->flinfo));
 }
 
 
@@ -183,7 +183,7 @@ gbt_bit_picksplit(PG_FUNCTION_ARGS)
 	GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
 
 	gbt_var_picksplit(entryvec, v, PG_GET_COLLATION(),
-					  &tinfo);
+					  &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(v);
 }
 
@@ -194,7 +194,7 @@ gbt_bit_same(PG_FUNCTION_ARGS)
 	Datum		d2 = PG_GETARG_DATUM(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_var_same(d1, d2, PG_GET_COLLATION(), &tinfo);
+	*result = gbt_var_same(d1, d2, PG_GET_COLLATION(), &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
 
@@ -207,5 +207,5 @@ gbt_bit_penalty(PG_FUNCTION_ARGS)
 	float	   *result = (float *) PG_GETARG_POINTER(2);
 
 	PG_RETURN_POINTER(gbt_var_penalty(result, o, n, PG_GET_COLLATION(),
-									  &tinfo));
+									  &tinfo, fcinfo->flinfo));
 }
diff --git a/contrib/btree_gist/btree_bytea.c b/contrib/btree_gist/btree_bytea.c
index df6c960..b9cd00f 100644
--- a/contrib/btree_gist/btree_bytea.c
+++ b/contrib/btree_gist/btree_bytea.c
@@ -23,7 +23,7 @@ PG_FUNCTION_INFO_V1(gbt_bytea_same);
 /* define for comparison */
 
 static bool
-gbt_byteagt(const void *a, const void *b, Oid collation)
+gbt_byteagt(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(byteagt,
 											PointerGetDatum(a),
@@ -31,7 +31,7 @@ gbt_byteagt(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_byteage(const void *a, const void *b, Oid collation)
+gbt_byteage(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(byteage,
 											PointerGetDatum(a),
@@ -39,7 +39,7 @@ gbt_byteage(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_byteaeq(const void *a, const void *b, Oid collation)
+gbt_byteaeq(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(byteaeq,
 											PointerGetDatum(a),
@@ -47,7 +47,7 @@ gbt_byteaeq(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_byteale(const void *a, const void *b, Oid collation)
+gbt_byteale(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(byteale,
 											PointerGetDatum(a),
@@ -55,7 +55,7 @@ gbt_byteale(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_bytealt(const void *a, const void *b, Oid collation)
+gbt_bytealt(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(bytealt,
 											PointerGetDatum(a),
@@ -63,7 +63,7 @@ gbt_bytealt(const void *a, const void *b, Oid collation)
 }
 
 static int32
-gbt_byteacmp(const void *a, const void *b, Oid collation)
+gbt_byteacmp(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetInt32(DirectFunctionCall2(byteacmp,
 											 PointerGetDatum(a),
@@ -118,7 +118,7 @@ gbt_bytea_consistent(PG_FUNCTION_ARGS)
 	*recheck = false;
 
 	retval = gbt_var_consistent(&r, query, strategy, PG_GET_COLLATION(),
-								GIST_LEAF(entry), &tinfo);
+								GIST_LEAF(entry), &tinfo, fcinfo->flinfo);
 	PG_RETURN_BOOL(retval);
 }
 
@@ -131,7 +131,7 @@ gbt_bytea_union(PG_FUNCTION_ARGS)
 	int32	   *size = (int *) PG_GETARG_POINTER(1);
 
 	PG_RETURN_POINTER(gbt_var_union(entryvec, size, PG_GET_COLLATION(),
-									&tinfo));
+									&tinfo, fcinfo->flinfo));
 }
 
 
@@ -142,7 +142,7 @@ gbt_bytea_picksplit(PG_FUNCTION_ARGS)
 	GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
 
 	gbt_var_picksplit(entryvec, v, PG_GET_COLLATION(),
-					  &tinfo);
+					  &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(v);
 }
 
@@ -153,7 +153,7 @@ gbt_bytea_same(PG_FUNCTION_ARGS)
 	Datum		d2 = PG_GETARG_DATUM(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_var_same(d1, d2, PG_GET_COLLATION(), &tinfo);
+	*result = gbt_var_same(d1, d2, PG_GET_COLLATION(), &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
 
@@ -166,5 +166,5 @@ gbt_bytea_penalty(PG_FUNCTION_ARGS)
 	float	   *result = (float *) PG_GETARG_POINTER(2);
 
 	PG_RETURN_POINTER(gbt_var_penalty(result, o, n, PG_GET_COLLATION(),
-									  &tinfo));
+									  &tinfo, fcinfo->flinfo));
 }
diff --git a/contrib/btree_gist/btree_numeric.c b/contrib/btree_gist/btree_numeric.c
index 47b0020..62e8f9d 100644
--- a/contrib/btree_gist/btree_numeric.c
+++ b/contrib/btree_gist/btree_numeric.c
@@ -27,7 +27,7 @@ PG_FUNCTION_INFO_V1(gbt_numeric_same);
 /* define for comparison */
 
 static bool
-gbt_numeric_gt(const void *a, const void *b, Oid collation)
+gbt_numeric_gt(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(numeric_gt,
 											PointerGetDatum(a),
@@ -35,7 +35,7 @@ gbt_numeric_gt(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_numeric_ge(const void *a, const void *b, Oid collation)
+gbt_numeric_ge(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(numeric_ge,
 											PointerGetDatum(a),
@@ -43,7 +43,7 @@ gbt_numeric_ge(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_numeric_eq(const void *a, const void *b, Oid collation)
+gbt_numeric_eq(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(numeric_eq,
 											PointerGetDatum(a),
@@ -51,7 +51,7 @@ gbt_numeric_eq(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_numeric_le(const void *a, const void *b, Oid collation)
+gbt_numeric_le(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(numeric_le,
 											PointerGetDatum(a),
@@ -59,7 +59,7 @@ gbt_numeric_le(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_numeric_lt(const void *a, const void *b, Oid collation)
+gbt_numeric_lt(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2(numeric_lt,
 											PointerGetDatum(a),
@@ -67,7 +67,7 @@ gbt_numeric_lt(const void *a, const void *b, Oid collation)
 }
 
 static int32
-gbt_numeric_cmp(const void *a, const void *b, Oid collation)
+gbt_numeric_cmp(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetInt32(DirectFunctionCall2(numeric_cmp,
 											 PointerGetDatum(a),
@@ -122,7 +122,7 @@ gbt_numeric_consistent(PG_FUNCTION_ARGS)
 	*recheck = false;
 
 	retval = gbt_var_consistent(&r, query, strategy, PG_GET_COLLATION(),
-								GIST_LEAF(entry), &tinfo);
+								GIST_LEAF(entry), &tinfo, fcinfo->flinfo);
 	PG_RETURN_BOOL(retval);
 }
 
@@ -135,7 +135,7 @@ gbt_numeric_union(PG_FUNCTION_ARGS)
 	int32	   *size = (int *) PG_GETARG_POINTER(1);
 
 	PG_RETURN_POINTER(gbt_var_union(entryvec, size, PG_GET_COLLATION(),
-									&tinfo));
+									&tinfo, fcinfo->flinfo));
 }
 
 
@@ -146,7 +146,7 @@ gbt_numeric_same(PG_FUNCTION_ARGS)
 	Datum		d2 = PG_GETARG_DATUM(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_var_same(d1, d2, PG_GET_COLLATION(), &tinfo);
+	*result = gbt_var_same(d1, d2, PG_GET_COLLATION(), &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
 
@@ -171,7 +171,7 @@ gbt_numeric_penalty(PG_FUNCTION_ARGS)
 
 	rk = gbt_var_key_readable(org);
 	uni = PointerGetDatum(gbt_var_key_copy(&rk));
-	gbt_var_bin_union(&uni, newe, PG_GET_COLLATION(), &tinfo);
+	gbt_var_bin_union(&uni, newe, PG_GET_COLLATION(), &tinfo, fcinfo->flinfo);
 	ok = gbt_var_key_readable(org);
 	uk = gbt_var_key_readable((GBT_VARKEY *) DatumGetPointer(uni));
 
@@ -233,6 +233,6 @@ gbt_numeric_picksplit(PG_FUNCTION_ARGS)
 	GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
 
 	gbt_var_picksplit(entryvec, v, PG_GET_COLLATION(),
-					  &tinfo);
+					  &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(v);
 }
diff --git a/contrib/btree_gist/btree_text.c b/contrib/btree_gist/btree_text.c
index 2e00cb6..51fc310 100644
--- a/contrib/btree_gist/btree_text.c
+++ b/contrib/btree_gist/btree_text.c
@@ -23,7 +23,7 @@ PG_FUNCTION_INFO_V1(gbt_text_same);
 /* define for comparison */
 
 static bool
-gbt_textgt(const void *a, const void *b, Oid collation)
+gbt_textgt(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2Coll(text_gt,
 												collation,
@@ -32,7 +32,7 @@ gbt_textgt(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_textge(const void *a, const void *b, Oid collation)
+gbt_textge(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2Coll(text_ge,
 												collation,
@@ -41,7 +41,7 @@ gbt_textge(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_texteq(const void *a, const void *b, Oid collation)
+gbt_texteq(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2Coll(texteq,
 												collation,
@@ -50,7 +50,7 @@ gbt_texteq(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_textle(const void *a, const void *b, Oid collation)
+gbt_textle(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2Coll(text_le,
 												collation,
@@ -59,7 +59,7 @@ gbt_textle(const void *a, const void *b, Oid collation)
 }
 
 static bool
-gbt_textlt(const void *a, const void *b, Oid collation)
+gbt_textlt(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetBool(DirectFunctionCall2Coll(text_lt,
 												collation,
@@ -68,7 +68,7 @@ gbt_textlt(const void *a, const void *b, Oid collation)
 }
 
 static int32
-gbt_textcmp(const void *a, const void *b, Oid collation)
+gbt_textcmp(const void *a, const void *b, FmgrInfo *flinfo, Oid collation)
 {
 	return DatumGetInt32(DirectFunctionCall2Coll(bttextcmp,
 												 collation,
@@ -161,7 +161,7 @@ gbt_text_consistent(PG_FUNCTION_ARGS)
 	}
 
 	retval = gbt_var_consistent(&r, query, strategy, PG_GET_COLLATION(),
-								GIST_LEAF(entry), &tinfo);
+								GIST_LEAF(entry), &tinfo, fcinfo->flinfo);
 
 	PG_RETURN_BOOL(retval);
 }
@@ -190,7 +190,7 @@ gbt_bpchar_consistent(PG_FUNCTION_ARGS)
 	}
 
 	retval = gbt_var_consistent(&r, trim, strategy, PG_GET_COLLATION(),
-								GIST_LEAF(entry), &tinfo);
+								GIST_LEAF(entry), &tinfo, fcinfo->flinfo);
 	PG_RETURN_BOOL(retval);
 }
 
@@ -202,7 +202,7 @@ gbt_text_union(PG_FUNCTION_ARGS)
 	int32	   *size = (int *) PG_GETARG_POINTER(1);
 
 	PG_RETURN_POINTER(gbt_var_union(entryvec, size, PG_GET_COLLATION(),
-									&tinfo));
+									&tinfo, fcinfo->flinfo));
 }
 
 
@@ -213,7 +213,7 @@ gbt_text_picksplit(PG_FUNCTION_ARGS)
 	GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
 
 	gbt_var_picksplit(entryvec, v, PG_GET_COLLATION(),
-					  &tinfo);
+					  &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(v);
 }
 
@@ -224,7 +224,7 @@ gbt_text_same(PG_FUNCTION_ARGS)
 	Datum		d2 = PG_GETARG_DATUM(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_var_same(d1, d2, PG_GET_COLLATION(), &tinfo);
+	*result = gbt_var_same(d1, d2, PG_GET_COLLATION(), &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
 
@@ -237,5 +237,5 @@ gbt_text_penalty(PG_FUNCTION_ARGS)
 	float	   *result = (float *) PG_GETARG_POINTER(2);
 
 	PG_RETURN_POINTER(gbt_var_penalty(result, o, n, PG_GET_COLLATION(),
-									  &tinfo));
+									  &tinfo, fcinfo->flinfo));
 }
diff --git a/contrib/btree_gist/btree_utils_var.c b/contrib/btree_gist/btree_utils_var.c
index 70b3794..16de893 100644
--- a/contrib/btree_gist/btree_utils_var.c
+++ b/contrib/btree_gist/btree_utils_var.c
@@ -25,6 +25,7 @@ typedef struct
 {
 	const gbtree_vinfo *tinfo;
 	Oid			collation;
+	FmgrInfo *flinfo;
 } gbt_vsrt_arg;
 
 
@@ -103,12 +104,12 @@ gbt_var_key_copy(const GBT_VARKEY_R *u)
 
 
 static GBT_VARKEY *
-gbt_var_leaf2node(GBT_VARKEY *leaf, const gbtree_vinfo *tinfo)
+gbt_var_leaf2node(GBT_VARKEY *leaf, const gbtree_vinfo *tinfo, FmgrInfo *flinfo)
 {
 	GBT_VARKEY *out = leaf;
 
 	if (tinfo->f_l2n)
-		out = (*tinfo->f_l2n) (leaf);
+		out = (*tinfo->f_l2n) (leaf, flinfo);
 
 	return out;
 }
@@ -232,7 +233,7 @@ gbt_var_node_truncate(const GBT_VARKEY *node, int32 cpf_length, const gbtree_vin
 
 void
 gbt_var_bin_union(Datum *u, GBT_VARKEY *e, Oid collation,
-				  const gbtree_vinfo *tinfo)
+				  const gbtree_vinfo *tinfo, FmgrInfo *flinfo)
 {
 	GBT_VARKEY_R eo = gbt_var_key_readable(e);
 	GBT_VARKEY_R nr;
@@ -241,7 +242,7 @@ gbt_var_bin_union(Datum *u, GBT_VARKEY *e, Oid collation,
 	{
 		GBT_VARKEY *tmp;
 
-		tmp = gbt_var_leaf2node(e, tinfo);
+		tmp = gbt_var_leaf2node(e, tinfo, flinfo);
 		if (tmp != e)
 			eo = gbt_var_key_readable(tmp);
 	}
@@ -254,13 +255,13 @@ gbt_var_bin_union(Datum *u, GBT_VARKEY *e, Oid collation,
 		nr.lower = ro.lower;
 		nr.upper = ro.upper;
 
-		if ((*tinfo->f_cmp) (ro.lower, eo.lower, collation) > 0)
+		if ((*tinfo->f_cmp) (ro.lower, eo.lower, flinfo, collation) > 0)
 		{
 			nr.lower = eo.lower;
 			update = true;
 		}
 
-		if ((*tinfo->f_cmp) (ro.upper, eo.upper, collation) < 0)
+		if ((*tinfo->f_cmp) (ro.upper, eo.upper, flinfo, collation) < 0)
 		{
 			nr.upper = eo.upper;
 			update = true;
@@ -321,7 +322,7 @@ gbt_var_fetch(PG_FUNCTION_ARGS)
 
 GBT_VARKEY *
 gbt_var_union(const GistEntryVector *entryvec, int32 *size, Oid collation,
-			  const gbtree_vinfo *tinfo)
+			  const gbtree_vinfo *tinfo, FmgrInfo *flinfo)
 {
 	int			i = 0,
 				numranges = entryvec->n;
@@ -338,7 +339,7 @@ gbt_var_union(const GistEntryVector *entryvec, int32 *size, Oid collation,
 	for (i = 1; i < numranges; i++)
 	{
 		cur = (GBT_VARKEY *) DatumGetPointer(entryvec->vector[i].key);
-		gbt_var_bin_union(&out, cur, collation, tinfo);
+		gbt_var_bin_union(&out, cur, collation, tinfo, flinfo);
 	}
 
 
@@ -360,7 +361,7 @@ gbt_var_union(const GistEntryVector *entryvec, int32 *size, Oid collation,
 
 bool
 gbt_var_same(Datum d1, Datum d2, Oid collation,
-			 const gbtree_vinfo *tinfo)
+			 const gbtree_vinfo *tinfo, FmgrInfo *flinfo)
 {
 	GBT_VARKEY *t1 = (GBT_VARKEY *) DatumGetPointer(d1);
 	GBT_VARKEY *t2 = (GBT_VARKEY *) DatumGetPointer(d2);
@@ -370,14 +371,14 @@ gbt_var_same(Datum d1, Datum d2, Oid collation,
 	r1 = gbt_var_key_readable(t1);
 	r2 = gbt_var_key_readable(t2);
 
-	return ((*tinfo->f_cmp) (r1.lower, r2.lower, collation) == 0 &&
-			(*tinfo->f_cmp) (r1.upper, r2.upper, collation) == 0);
+	return ((*tinfo->f_cmp) (r1.lower, r2.lower, flinfo, collation) == 0 &&
+			(*tinfo->f_cmp) (r1.upper, r2.upper, flinfo, collation) == 0);
 }
 
 
 float *
 gbt_var_penalty(float *res, const GISTENTRY *o, const GISTENTRY *n,
-				Oid collation, const gbtree_vinfo *tinfo)
+				Oid collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo)
 {
 	GBT_VARKEY *orge = (GBT_VARKEY *) DatumGetPointer(o->key);
 	GBT_VARKEY *newe = (GBT_VARKEY *) DatumGetPointer(n->key);
@@ -391,7 +392,7 @@ gbt_var_penalty(float *res, const GISTENTRY *o, const GISTENTRY *n,
 	{
 		GBT_VARKEY *tmp;
 
-		tmp = gbt_var_leaf2node(newe, tinfo);
+		tmp = gbt_var_leaf2node(newe, tinfo, flinfo);
 		if (tmp != newe)
 			nk = gbt_var_key_readable(tmp);
 	}
@@ -399,9 +400,9 @@ gbt_var_penalty(float *res, const GISTENTRY *o, const GISTENTRY *n,
 
 	if ((VARSIZE(ok.lower) - VARHDRSZ) == 0 && (VARSIZE(ok.upper) - VARHDRSZ) == 0)
 		*res = 0.0;
-	else if (!(((*tinfo->f_cmp) (nk.lower, ok.lower, collation) >= 0 ||
+	else if (!(((*tinfo->f_cmp) (nk.lower, ok.lower, flinfo, collation) >= 0 ||
 				gbt_bytea_pf_match(ok.lower, nk.lower, tinfo)) &&
-			   ((*tinfo->f_cmp) (nk.upper, ok.upper, collation) <= 0 ||
+			   ((*tinfo->f_cmp) (nk.upper, ok.upper, flinfo, collation) <= 0 ||
 				gbt_bytea_pf_match(ok.upper, nk.upper, tinfo))))
 	{
 		Datum		d = PointerGetDatum(0);
@@ -409,9 +410,9 @@ gbt_var_penalty(float *res, const GISTENTRY *o, const GISTENTRY *n,
 		int32		ol,
 					ul;
 
-		gbt_var_bin_union(&d, orge, collation, tinfo);
+		gbt_var_bin_union(&d, orge, collation, tinfo, flinfo);
 		ol = gbt_var_node_cp_len((GBT_VARKEY *) DatumGetPointer(d), tinfo);
-		gbt_var_bin_union(&d, newe, collation, tinfo);
+		gbt_var_bin_union(&d, newe, collation, tinfo, flinfo);
 		ul = gbt_var_node_cp_len((GBT_VARKEY *) DatumGetPointer(d), tinfo);
 
 		if (ul < ol)
@@ -448,16 +449,16 @@ gbt_vsrt_cmp(const void *a, const void *b, void *arg)
 	const gbt_vsrt_arg *varg = (const gbt_vsrt_arg *) arg;
 	int			res;
 
-	res = (*varg->tinfo->f_cmp) (ar.lower, br.lower, varg->collation);
+	res = (*varg->tinfo->f_cmp) (ar.lower, br.lower, varg->flinfo, varg->collation);
 	if (res == 0)
-		return (*varg->tinfo->f_cmp) (ar.upper, br.upper, varg->collation);
+		return (*varg->tinfo->f_cmp) (ar.upper, br.upper, varg->flinfo, varg->collation);
 
 	return res;
 }
 
 GIST_SPLITVEC *
 gbt_var_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
-				  Oid collation, const gbtree_vinfo *tinfo)
+				  Oid collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo)
 {
 	OffsetNumber i,
 				maxoff = entryvec->n - 1;
@@ -489,7 +490,7 @@ gbt_var_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
 		ro = gbt_var_key_readable((GBT_VARKEY *) cur);
 		if (ro.lower == ro.upper)		/* leaf */
 		{
-			sv[svcntr] = gbt_var_leaf2node((GBT_VARKEY *) cur, tinfo);
+			sv[svcntr] = gbt_var_leaf2node((GBT_VARKEY *) cur, tinfo, flinfo);
 			arr[i].t = sv[svcntr];
 			if (sv[svcntr] != (GBT_VARKEY *) cur)
 				svcntr++;
@@ -502,6 +503,7 @@ gbt_var_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
 	/* sort */
 	varg.tinfo = tinfo;
 	varg.collation = collation;
+	varg.flinfo = flinfo;
 	qsort_arg((void *) &arr[FirstOffsetNumber],
 			  maxoff - FirstOffsetNumber + 1,
 			  sizeof(Vsrt),
@@ -514,13 +516,13 @@ gbt_var_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
 	{
 		if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
 		{
-			gbt_var_bin_union(&v->spl_ldatum, arr[i].t, collation, tinfo);
+			gbt_var_bin_union(&v->spl_ldatum, arr[i].t, collation, tinfo, flinfo);
 			v->spl_left[v->spl_nleft] = arr[i].i;
 			v->spl_nleft++;
 		}
 		else
 		{
-			gbt_var_bin_union(&v->spl_rdatum, arr[i].t, collation, tinfo);
+			gbt_var_bin_union(&v->spl_rdatum, arr[i].t, collation, tinfo, flinfo);
 			v->spl_right[v->spl_nright] = arr[i].i;
 			v->spl_nright++;
 		}
@@ -556,7 +558,8 @@ gbt_var_consistent(GBT_VARKEY_R *key,
 				   StrategyNumber strategy,
 				   Oid collation,
 				   bool is_leaf,
-				   const gbtree_vinfo *tinfo)
+				   const gbtree_vinfo *tinfo,
+				   FmgrInfo *flinfo)
 {
 	bool		retval = FALSE;
 
@@ -564,44 +567,44 @@ gbt_var_consistent(GBT_VARKEY_R *key,
 	{
 		case BTLessEqualStrategyNumber:
 			if (is_leaf)
-				retval = (*tinfo->f_ge) (query, key->lower, collation);
+				retval = (*tinfo->f_ge) (query, key->lower, flinfo, collation);
 			else
-				retval = (*tinfo->f_cmp) (query, key->lower, collation) >= 0
+				retval = (*tinfo->f_cmp) (query, key->lower, flinfo, collation) >= 0
 					|| gbt_var_node_pf_match(key, query, tinfo);
 			break;
 		case BTLessStrategyNumber:
 			if (is_leaf)
-				retval = (*tinfo->f_gt) (query, key->lower, collation);
+				retval = (*tinfo->f_gt) (query, key->lower, flinfo, collation);
 			else
-				retval = (*tinfo->f_cmp) (query, key->lower, collation) >= 0
+				retval = (*tinfo->f_cmp) (query, key->lower, flinfo, collation) >= 0
 					|| gbt_var_node_pf_match(key, query, tinfo);
 			break;
 		case BTEqualStrategyNumber:
 			if (is_leaf)
-				retval = (*tinfo->f_eq) (query, key->lower, collation);
+				retval = (*tinfo->f_eq) (query, key->lower, flinfo, collation);
 			else
 				retval =
-					((*tinfo->f_cmp) (key->lower, query, collation) <= 0 &&
-					 (*tinfo->f_cmp) (query, key->upper, collation) <= 0) ||
+					((*tinfo->f_cmp) (key->lower, query, flinfo, collation) <= 0 &&
+					 (*tinfo->f_cmp) (query, key->upper, flinfo, collation) <= 0) ||
 					gbt_var_node_pf_match(key, query, tinfo);
 			break;
 		case BTGreaterStrategyNumber:
 			if (is_leaf)
-				retval = (*tinfo->f_lt) (query, key->upper, collation);
+				retval = (*tinfo->f_lt) (query, key->upper, flinfo, collation);
 			else
-				retval = (*tinfo->f_cmp) (query, key->upper, collation) <= 0
+				retval = (*tinfo->f_cmp) (query, key->upper, flinfo, collation) <= 0
 					|| gbt_var_node_pf_match(key, query, tinfo);
 			break;
 		case BTGreaterEqualStrategyNumber:
 			if (is_leaf)
-				retval = (*tinfo->f_le) (query, key->upper, collation);
+				retval = (*tinfo->f_le) (query, key->upper, flinfo, collation);
 			else
-				retval = (*tinfo->f_cmp) (query, key->upper, collation) <= 0
+				retval = (*tinfo->f_cmp) (query, key->upper, flinfo, collation) <= 0
 					|| gbt_var_node_pf_match(key, query, tinfo);
 			break;
 		case BtreeGistNotEqualStrategyNumber:
-			retval = !((*tinfo->f_eq) (query, key->lower, collation) &&
-					   (*tinfo->f_eq) (query, key->upper, collation));
+			retval = !((*tinfo->f_eq) (query, key->lower, flinfo, collation) &&
+					   (*tinfo->f_eq) (query, key->upper, flinfo, collation));
 			break;
 		default:
 			retval = FALSE;
diff --git a/contrib/btree_gist/btree_utils_var.h b/contrib/btree_gist/btree_utils_var.h
index 9a7c4d1..7c9ffaf 100644
--- a/contrib/btree_gist/btree_utils_var.h
+++ b/contrib/btree_gist/btree_utils_var.h
@@ -34,13 +34,13 @@ typedef struct
 
 	/* Methods */
 
-	bool		(*f_gt) (const void *, const void *, Oid);		/* greater than */
-	bool		(*f_ge) (const void *, const void *, Oid);		/* greater equal */
-	bool		(*f_eq) (const void *, const void *, Oid);		/* equal */
-	bool		(*f_le) (const void *, const void *, Oid);		/* less equal */
-	bool		(*f_lt) (const void *, const void *, Oid);		/* less than */
-	int32		(*f_cmp) (const void *, const void *, Oid);		/* compare */
-	GBT_VARKEY *(*f_l2n) (GBT_VARKEY *);		/* convert leaf to node */
+	bool		(*f_gt) (const void *, const void *, FmgrInfo *flinfo, Oid);		/* greater than */
+	bool		(*f_ge) (const void *, const void *, FmgrInfo *flinfo, Oid);		/* greater equal */
+	bool		(*f_eq) (const void *, const void *, FmgrInfo *flinfo, Oid);		/* equal */
+	bool		(*f_le) (const void *, const void *, FmgrInfo *flinfo, Oid);		/* less equal */
+	bool		(*f_lt) (const void *, const void *, FmgrInfo *flinfo, Oid);		/* less than */
+	int32		(*f_cmp) (const void *, const void *, FmgrInfo *flinfo, Oid);		/* compare */
+	GBT_VARKEY *(*f_l2n) (GBT_VARKEY *, FmgrInfo *flinfo);		/* convert leaf to node */
 } gbtree_vinfo;
 
 
@@ -52,22 +52,22 @@ extern GBT_VARKEY *gbt_var_key_copy(const GBT_VARKEY_R *u);
 extern GISTENTRY *gbt_var_compress(GISTENTRY *entry, const gbtree_vinfo *tinfo);
 
 extern GBT_VARKEY *gbt_var_union(const GistEntryVector *entryvec, int32 *size,
-			  Oid collation, const gbtree_vinfo *tinfo);
+			  Oid collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo);
 
 extern bool gbt_var_same(Datum d1, Datum d2, Oid collation,
-			 const gbtree_vinfo *tinfo);
+			 const gbtree_vinfo *tinfo, FmgrInfo *flinfo);
 
 extern float *gbt_var_penalty(float *res, const GISTENTRY *o, const GISTENTRY *n,
-				Oid collation, const gbtree_vinfo *tinfo);
+				Oid collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo);
 
 extern bool gbt_var_consistent(GBT_VARKEY_R *key, const void *query,
 				   StrategyNumber strategy, Oid collation, bool is_leaf,
-				   const gbtree_vinfo *tinfo);
+				   const gbtree_vinfo *tinfo, FmgrInfo *flinfo);
 
 extern GIST_SPLITVEC *gbt_var_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
-				  Oid collation, const gbtree_vinfo *tinfo);
+				  Oid collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo);
 
 extern void gbt_var_bin_union(Datum *u, GBT_VARKEY *e, Oid collation,
-				  const gbtree_vinfo *tinfo);
+				  const gbtree_vinfo *tinfo, FmgrInfo *flinfo);
 
 #endif
-- 
2.4.11

>From 0926e40bea4e6b5b4f07578f38f6c5026887f28f Mon Sep 17 00:00:00 2001
From: Andrew Dunstan <and...@dunslane.net>
Date: Sun, 26 Feb 2017 16:58:01 -0500
Subject: [PATCH 2/4] Allow use of CallerFInfoFunctionCall with btree_gist for
 numeric types

None of the existing types actually need to use this mechanism, but this
will allow support for enum types which will need it. A separate patch
will adjust the varlena types support for consistency.
---
 contrib/btree_gist/btree_cash.c      | 24 +++++++--------
 contrib/btree_gist/btree_date.c      | 24 +++++++--------
 contrib/btree_gist/btree_float4.c    | 24 +++++++--------
 contrib/btree_gist/btree_float8.c    | 24 +++++++--------
 contrib/btree_gist/btree_inet.c      | 20 ++++++------
 contrib/btree_gist/btree_int2.c      | 24 +++++++--------
 contrib/btree_gist/btree_int4.c      | 24 +++++++--------
 contrib/btree_gist/btree_int8.c      | 24 +++++++--------
 contrib/btree_gist/btree_interval.c  | 24 +++++++--------
 contrib/btree_gist/btree_macaddr.c   | 20 ++++++------
 contrib/btree_gist/btree_oid.c       | 24 +++++++--------
 contrib/btree_gist/btree_time.c      | 26 ++++++++--------
 contrib/btree_gist/btree_ts.c        | 28 ++++++++---------
 contrib/btree_gist/btree_utils_num.c | 60 +++++++++++++++++++-----------------
 contrib/btree_gist/btree_utils_num.h | 26 ++++++++--------
 contrib/btree_gist/btree_uuid.c      | 20 ++++++------
 16 files changed, 209 insertions(+), 207 deletions(-)

diff --git a/contrib/btree_gist/btree_cash.c b/contrib/btree_gist/btree_cash.c
index aa14735..ca0c86b 100644
--- a/contrib/btree_gist/btree_cash.c
+++ b/contrib/btree_gist/btree_cash.c
@@ -26,33 +26,33 @@ PG_FUNCTION_INFO_V1(gbt_cash_penalty);
 PG_FUNCTION_INFO_V1(gbt_cash_same);
 
 static bool
-gbt_cashgt(const void *a, const void *b)
+gbt_cashgt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const Cash *) a) > *((const Cash *) b));
 }
 static bool
-gbt_cashge(const void *a, const void *b)
+gbt_cashge(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const Cash *) a) >= *((const Cash *) b));
 }
 static bool
-gbt_casheq(const void *a, const void *b)
+gbt_casheq(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const Cash *) a) == *((const Cash *) b));
 }
 static bool
-gbt_cashle(const void *a, const void *b)
+gbt_cashle(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const Cash *) a) <= *((const Cash *) b));
 }
 static bool
-gbt_cashlt(const void *a, const void *b)
+gbt_cashlt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const Cash *) a) < *((const Cash *) b));
 }
 
 static int
-gbt_cashkey_cmp(const void *a, const void *b)
+gbt_cashkey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	cashKEY    *ia = (cashKEY *) (((const Nsrt *) a)->t);
 	cashKEY    *ib = (cashKEY *) (((const Nsrt *) b)->t);
@@ -69,7 +69,7 @@ gbt_cashkey_cmp(const void *a, const void *b)
 }
 
 static float8
-gbt_cash_dist(const void *a, const void *b)
+gbt_cash_dist(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return GET_FLOAT_DISTANCE(Cash, a, b);
 }
@@ -151,7 +151,7 @@ gbt_cash_consistent(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_BOOL(
-				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo)
+				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -170,7 +170,7 @@ gbt_cash_distance(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_FLOAT8(
-			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -182,7 +182,7 @@ gbt_cash_union(PG_FUNCTION_ARGS)
 	void	   *out = palloc(sizeof(cashKEY));
 
 	*(int *) PG_GETARG_POINTER(1) = sizeof(cashKEY);
-	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
 }
 
 
@@ -205,7 +205,7 @@ gbt_cash_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_num_picksplit(
 									(GistEntryVector *) PG_GETARG_POINTER(0),
 									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
-										&tinfo
+										&tinfo, fcinfo->flinfo
 										));
 }
 
@@ -216,6 +216,6 @@ gbt_cash_same(PG_FUNCTION_ARGS)
 	cashKEY    *b2 = (cashKEY *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
diff --git a/contrib/btree_gist/btree_date.c b/contrib/btree_gist/btree_date.c
index 56031d4..c9daf34 100644
--- a/contrib/btree_gist/btree_date.c
+++ b/contrib/btree_gist/btree_date.c
@@ -27,7 +27,7 @@ PG_FUNCTION_INFO_V1(gbt_date_penalty);
 PG_FUNCTION_INFO_V1(gbt_date_same);
 
 static bool
-gbt_dategt(const void *a, const void *b)
+gbt_dategt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(
 						DirectFunctionCall2(date_gt, DateADTGetDatum(*((const DateADT *) a)), DateADTGetDatum(*((const DateADT *) b)))
@@ -35,7 +35,7 @@ gbt_dategt(const void *a, const void *b)
 }
 
 static bool
-gbt_datege(const void *a, const void *b)
+gbt_datege(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(
 						DirectFunctionCall2(date_ge, DateADTGetDatum(*((const DateADT *) a)), DateADTGetDatum(*((const DateADT *) b)))
@@ -43,7 +43,7 @@ gbt_datege(const void *a, const void *b)
 }
 
 static bool
-gbt_dateeq(const void *a, const void *b)
+gbt_dateeq(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(
 						DirectFunctionCall2(date_eq, DateADTGetDatum(*((const DateADT *) a)), DateADTGetDatum(*((const DateADT *) b)))
@@ -51,7 +51,7 @@ gbt_dateeq(const void *a, const void *b)
 }
 
 static bool
-gbt_datele(const void *a, const void *b)
+gbt_datele(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(
 						DirectFunctionCall2(date_le, DateADTGetDatum(*((const DateADT *) a)), DateADTGetDatum(*((const DateADT *) b)))
@@ -59,7 +59,7 @@ gbt_datele(const void *a, const void *b)
 }
 
 static bool
-gbt_datelt(const void *a, const void *b)
+gbt_datelt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(
 						DirectFunctionCall2(date_lt, DateADTGetDatum(*((const DateADT *) a)), DateADTGetDatum(*((const DateADT *) b)))
@@ -69,7 +69,7 @@ gbt_datelt(const void *a, const void *b)
 
 
 static int
-gbt_datekey_cmp(const void *a, const void *b)
+gbt_datekey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	dateKEY    *ia = (dateKEY *) (((const Nsrt *) a)->t);
 	dateKEY    *ib = (dateKEY *) (((const Nsrt *) b)->t);
@@ -83,7 +83,7 @@ gbt_datekey_cmp(const void *a, const void *b)
 }
 
 static float8
-gdb_date_dist(const void *a, const void *b)
+gdb_date_dist(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	/* we assume the difference can't overflow */
 	Datum		diff = DirectFunctionCall2(date_mi,
@@ -163,7 +163,7 @@ gbt_date_consistent(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_BOOL(
-				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo)
+				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -182,7 +182,7 @@ gbt_date_distance(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_FLOAT8(
-			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -194,7 +194,7 @@ gbt_date_union(PG_FUNCTION_ARGS)
 	void	   *out = palloc(sizeof(dateKEY));
 
 	*(int *) PG_GETARG_POINTER(1) = sizeof(dateKEY);
-	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
 }
 
 
@@ -244,7 +244,7 @@ gbt_date_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_num_picksplit(
 									(GistEntryVector *) PG_GETARG_POINTER(0),
 									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
-										&tinfo
+										&tinfo, fcinfo->flinfo
 										));
 }
 
@@ -255,6 +255,6 @@ gbt_date_same(PG_FUNCTION_ARGS)
 	dateKEY    *b2 = (dateKEY *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
diff --git a/contrib/btree_gist/btree_float4.c b/contrib/btree_gist/btree_float4.c
index 13dc4a5..46b3edb 100644
--- a/contrib/btree_gist/btree_float4.c
+++ b/contrib/btree_gist/btree_float4.c
@@ -25,33 +25,33 @@ PG_FUNCTION_INFO_V1(gbt_float4_penalty);
 PG_FUNCTION_INFO_V1(gbt_float4_same);
 
 static bool
-gbt_float4gt(const void *a, const void *b)
+gbt_float4gt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const float4 *) a) > *((const float4 *) b));
 }
 static bool
-gbt_float4ge(const void *a, const void *b)
+gbt_float4ge(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const float4 *) a) >= *((const float4 *) b));
 }
 static bool
-gbt_float4eq(const void *a, const void *b)
+gbt_float4eq(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const float4 *) a) == *((const float4 *) b));
 }
 static bool
-gbt_float4le(const void *a, const void *b)
+gbt_float4le(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const float4 *) a) <= *((const float4 *) b));
 }
 static bool
-gbt_float4lt(const void *a, const void *b)
+gbt_float4lt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const float4 *) a) < *((const float4 *) b));
 }
 
 static int
-gbt_float4key_cmp(const void *a, const void *b)
+gbt_float4key_cmp(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	float4KEY  *ia = (float4KEY *) (((const Nsrt *) a)->t);
 	float4KEY  *ib = (float4KEY *) (((const Nsrt *) b)->t);
@@ -68,7 +68,7 @@ gbt_float4key_cmp(const void *a, const void *b)
 }
 
 static float8
-gbt_float4_dist(const void *a, const void *b)
+gbt_float4_dist(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return GET_FLOAT_DISTANCE(float4, a, b);
 }
@@ -144,7 +144,7 @@ gbt_float4_consistent(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_BOOL(
-				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo)
+				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -163,7 +163,7 @@ gbt_float4_distance(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_FLOAT8(
-			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -175,7 +175,7 @@ gbt_float4_union(PG_FUNCTION_ARGS)
 	void	   *out = palloc(sizeof(float4KEY));
 
 	*(int *) PG_GETARG_POINTER(1) = sizeof(float4KEY);
-	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
 }
 
 
@@ -198,7 +198,7 @@ gbt_float4_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_num_picksplit(
 									(GistEntryVector *) PG_GETARG_POINTER(0),
 									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
-										&tinfo
+										&tinfo, fcinfo->flinfo
 										));
 }
 
@@ -209,6 +209,6 @@ gbt_float4_same(PG_FUNCTION_ARGS)
 	float4KEY  *b2 = (float4KEY *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
diff --git a/contrib/btree_gist/btree_float8.c b/contrib/btree_gist/btree_float8.c
index c3a2415..7d65307 100644
--- a/contrib/btree_gist/btree_float8.c
+++ b/contrib/btree_gist/btree_float8.c
@@ -26,33 +26,33 @@ PG_FUNCTION_INFO_V1(gbt_float8_same);
 
 
 static bool
-gbt_float8gt(const void *a, const void *b)
+gbt_float8gt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const float8 *) a) > *((const float8 *) b));
 }
 static bool
-gbt_float8ge(const void *a, const void *b)
+gbt_float8ge(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const float8 *) a) >= *((const float8 *) b));
 }
 static bool
-gbt_float8eq(const void *a, const void *b)
+gbt_float8eq(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const float8 *) a) == *((const float8 *) b));
 }
 static bool
-gbt_float8le(const void *a, const void *b)
+gbt_float8le(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const float8 *) a) <= *((const float8 *) b));
 }
 static bool
-gbt_float8lt(const void *a, const void *b)
+gbt_float8lt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const float8 *) a) < *((const float8 *) b));
 }
 
 static int
-gbt_float8key_cmp(const void *a, const void *b)
+gbt_float8key_cmp(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	float8KEY  *ia = (float8KEY *) (((const Nsrt *) a)->t);
 	float8KEY  *ib = (float8KEY *) (((const Nsrt *) b)->t);
@@ -69,7 +69,7 @@ gbt_float8key_cmp(const void *a, const void *b)
 }
 
 static float8
-gbt_float8_dist(const void *a, const void *b)
+gbt_float8_dist(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	float8		arg1 = *(const float8 *) a;
 	float8		arg2 = *(const float8 *) b;
@@ -151,7 +151,7 @@ gbt_float8_consistent(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_BOOL(
-				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo)
+				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -170,7 +170,7 @@ gbt_float8_distance(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_FLOAT8(
-			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -182,7 +182,7 @@ gbt_float8_union(PG_FUNCTION_ARGS)
 	void	   *out = palloc(sizeof(float8KEY));
 
 	*(int *) PG_GETARG_POINTER(1) = sizeof(float8KEY);
-	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
 }
 
 
@@ -205,7 +205,7 @@ gbt_float8_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_num_picksplit(
 									(GistEntryVector *) PG_GETARG_POINTER(0),
 									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
-										&tinfo
+										&tinfo, fcinfo->flinfo
 										));
 }
 
@@ -216,6 +216,6 @@ gbt_float8_same(PG_FUNCTION_ARGS)
 	float8KEY  *b2 = (float8KEY *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
diff --git a/contrib/btree_gist/btree_inet.c b/contrib/btree_gist/btree_inet.c
index 8227861..7c95ee6 100644
--- a/contrib/btree_gist/btree_inet.c
+++ b/contrib/btree_gist/btree_inet.c
@@ -27,33 +27,33 @@ PG_FUNCTION_INFO_V1(gbt_inet_same);
 
 
 static bool
-gbt_inetgt(const void *a, const void *b)
+gbt_inetgt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const double *) a) > *((const double *) b));
 }
 static bool
-gbt_inetge(const void *a, const void *b)
+gbt_inetge(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const double *) a) >= *((const double *) b));
 }
 static bool
-gbt_ineteq(const void *a, const void *b)
+gbt_ineteq(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const double *) a) == *((const double *) b));
 }
 static bool
-gbt_inetle(const void *a, const void *b)
+gbt_inetle(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const double *) a) <= *((const double *) b));
 }
 static bool
-gbt_inetlt(const void *a, const void *b)
+gbt_inetlt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const double *) a) < *((const double *) b));
 }
 
 static int
-gbt_inetkey_cmp(const void *a, const void *b)
+gbt_inetkey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	inetKEY    *ia = (inetKEY *) (((const Nsrt *) a)->t);
 	inetKEY    *ib = (inetKEY *) (((const Nsrt *) b)->t);
@@ -133,7 +133,7 @@ gbt_inet_consistent(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_BOOL(gbt_num_consistent(&key, (void *) &query,
-									  &strategy, GIST_LEAF(entry), &tinfo));
+									  &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo));
 }
 
 
@@ -144,7 +144,7 @@ gbt_inet_union(PG_FUNCTION_ARGS)
 	void	   *out = palloc(sizeof(inetKEY));
 
 	*(int *) PG_GETARG_POINTER(1) = sizeof(inetKEY);
-	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
 }
 
 
@@ -167,7 +167,7 @@ gbt_inet_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_num_picksplit(
 									(GistEntryVector *) PG_GETARG_POINTER(0),
 									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
-										&tinfo
+										&tinfo, fcinfo->flinfo
 										));
 }
 
@@ -178,6 +178,6 @@ gbt_inet_same(PG_FUNCTION_ARGS)
 	inetKEY    *b2 = (inetKEY *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
diff --git a/contrib/btree_gist/btree_int2.c b/contrib/btree_gist/btree_int2.c
index 54dc1cc..3dae5e7 100644
--- a/contrib/btree_gist/btree_int2.c
+++ b/contrib/btree_gist/btree_int2.c
@@ -25,33 +25,33 @@ PG_FUNCTION_INFO_V1(gbt_int2_penalty);
 PG_FUNCTION_INFO_V1(gbt_int2_same);
 
 static bool
-gbt_int2gt(const void *a, const void *b)
+gbt_int2gt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int16 *) a) > *((const int16 *) b));
 }
 static bool
-gbt_int2ge(const void *a, const void *b)
+gbt_int2ge(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int16 *) a) >= *((const int16 *) b));
 }
 static bool
-gbt_int2eq(const void *a, const void *b)
+gbt_int2eq(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int16 *) a) == *((const int16 *) b));
 }
 static bool
-gbt_int2le(const void *a, const void *b)
+gbt_int2le(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int16 *) a) <= *((const int16 *) b));
 }
 static bool
-gbt_int2lt(const void *a, const void *b)
+gbt_int2lt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int16 *) a) < *((const int16 *) b));
 }
 
 static int
-gbt_int2key_cmp(const void *a, const void *b)
+gbt_int2key_cmp(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	int16KEY   *ia = (int16KEY *) (((const Nsrt *) a)->t);
 	int16KEY   *ib = (int16KEY *) (((const Nsrt *) b)->t);
@@ -68,7 +68,7 @@ gbt_int2key_cmp(const void *a, const void *b)
 }
 
 static float8
-gbt_int2_dist(const void *a, const void *b)
+gbt_int2_dist(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return GET_FLOAT_DISTANCE(int16, a, b);
 }
@@ -151,7 +151,7 @@ gbt_int2_consistent(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_BOOL(
-				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo)
+				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -170,7 +170,7 @@ gbt_int2_distance(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_FLOAT8(
-			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -182,7 +182,7 @@ gbt_int2_union(PG_FUNCTION_ARGS)
 	void	   *out = palloc(sizeof(int16KEY));
 
 	*(int *) PG_GETARG_POINTER(1) = sizeof(int16KEY);
-	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
 }
 
 
@@ -204,7 +204,7 @@ gbt_int2_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_num_picksplit(
 									(GistEntryVector *) PG_GETARG_POINTER(0),
 									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
-										&tinfo
+										&tinfo, fcinfo->flinfo
 										));
 }
 
@@ -215,6 +215,6 @@ gbt_int2_same(PG_FUNCTION_ARGS)
 	int16KEY   *b2 = (int16KEY *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
diff --git a/contrib/btree_gist/btree_int4.c b/contrib/btree_gist/btree_int4.c
index ddbcf52..213bfa3 100644
--- a/contrib/btree_gist/btree_int4.c
+++ b/contrib/btree_gist/btree_int4.c
@@ -26,33 +26,33 @@ PG_FUNCTION_INFO_V1(gbt_int4_same);
 
 
 static bool
-gbt_int4gt(const void *a, const void *b)
+gbt_int4gt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int32 *) a) > *((const int32 *) b));
 }
 static bool
-gbt_int4ge(const void *a, const void *b)
+gbt_int4ge(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int32 *) a) >= *((const int32 *) b));
 }
 static bool
-gbt_int4eq(const void *a, const void *b)
+gbt_int4eq(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int32 *) a) == *((const int32 *) b));
 }
 static bool
-gbt_int4le(const void *a, const void *b)
+gbt_int4le(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int32 *) a) <= *((const int32 *) b));
 }
 static bool
-gbt_int4lt(const void *a, const void *b)
+gbt_int4lt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int32 *) a) < *((const int32 *) b));
 }
 
 static int
-gbt_int4key_cmp(const void *a, const void *b)
+gbt_int4key_cmp(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	int32KEY   *ia = (int32KEY *) (((const Nsrt *) a)->t);
 	int32KEY   *ib = (int32KEY *) (((const Nsrt *) b)->t);
@@ -69,7 +69,7 @@ gbt_int4key_cmp(const void *a, const void *b)
 }
 
 static float8
-gbt_int4_dist(const void *a, const void *b)
+gbt_int4_dist(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return GET_FLOAT_DISTANCE(int32, a, b);
 }
@@ -152,7 +152,7 @@ gbt_int4_consistent(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_BOOL(
-				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo)
+				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -171,7 +171,7 @@ gbt_int4_distance(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_FLOAT8(
-			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -183,7 +183,7 @@ gbt_int4_union(PG_FUNCTION_ARGS)
 	void	   *out = palloc(sizeof(int32KEY));
 
 	*(int *) PG_GETARG_POINTER(1) = sizeof(int32KEY);
-	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
 }
 
 
@@ -205,7 +205,7 @@ gbt_int4_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_num_picksplit(
 									(GistEntryVector *) PG_GETARG_POINTER(0),
 									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
-										&tinfo
+										&tinfo, fcinfo->flinfo
 										));
 }
 
@@ -216,6 +216,6 @@ gbt_int4_same(PG_FUNCTION_ARGS)
 	int32KEY   *b2 = (int32KEY *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
diff --git a/contrib/btree_gist/btree_int8.c b/contrib/btree_gist/btree_int8.c
index 44bf69a..62b079b 100644
--- a/contrib/btree_gist/btree_int8.c
+++ b/contrib/btree_gist/btree_int8.c
@@ -26,33 +26,33 @@ PG_FUNCTION_INFO_V1(gbt_int8_same);
 
 
 static bool
-gbt_int8gt(const void *a, const void *b)
+gbt_int8gt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int64 *) a) > *((const int64 *) b));
 }
 static bool
-gbt_int8ge(const void *a, const void *b)
+gbt_int8ge(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int64 *) a) >= *((const int64 *) b));
 }
 static bool
-gbt_int8eq(const void *a, const void *b)
+gbt_int8eq(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int64 *) a) == *((const int64 *) b));
 }
 static bool
-gbt_int8le(const void *a, const void *b)
+gbt_int8le(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int64 *) a) <= *((const int64 *) b));
 }
 static bool
-gbt_int8lt(const void *a, const void *b)
+gbt_int8lt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const int64 *) a) < *((const int64 *) b));
 }
 
 static int
-gbt_int8key_cmp(const void *a, const void *b)
+gbt_int8key_cmp(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	int64KEY   *ia = (int64KEY *) (((const Nsrt *) a)->t);
 	int64KEY   *ib = (int64KEY *) (((const Nsrt *) b)->t);
@@ -69,7 +69,7 @@ gbt_int8key_cmp(const void *a, const void *b)
 }
 
 static float8
-gbt_int8_dist(const void *a, const void *b)
+gbt_int8_dist(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return GET_FLOAT_DISTANCE(int64, a, b);
 }
@@ -152,7 +152,7 @@ gbt_int8_consistent(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_BOOL(
-				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo)
+				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -171,7 +171,7 @@ gbt_int8_distance(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_FLOAT8(
-			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -183,7 +183,7 @@ gbt_int8_union(PG_FUNCTION_ARGS)
 	void	   *out = palloc(sizeof(int64KEY));
 
 	*(int *) PG_GETARG_POINTER(1) = sizeof(int64KEY);
-	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
 }
 
 
@@ -205,7 +205,7 @@ gbt_int8_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_num_picksplit(
 									(GistEntryVector *) PG_GETARG_POINTER(0),
 									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
-										&tinfo
+										&tinfo, fcinfo->flinfo
 										));
 }
 
@@ -216,6 +216,6 @@ gbt_int8_same(PG_FUNCTION_ARGS)
 	int64KEY   *b2 = (int64KEY *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
diff --git a/contrib/btree_gist/btree_interval.c b/contrib/btree_gist/btree_interval.c
index e5cd0a2..f41f471 100644
--- a/contrib/btree_gist/btree_interval.c
+++ b/contrib/btree_gist/btree_interval.c
@@ -30,37 +30,37 @@ PG_FUNCTION_INFO_V1(gbt_intv_same);
 
 
 static bool
-gbt_intvgt(const void *a, const void *b)
+gbt_intvgt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(DirectFunctionCall2(interval_gt, IntervalPGetDatum(a), IntervalPGetDatum(b)));
 }
 
 static bool
-gbt_intvge(const void *a, const void *b)
+gbt_intvge(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(DirectFunctionCall2(interval_ge, IntervalPGetDatum(a), IntervalPGetDatum(b)));
 }
 
 static bool
-gbt_intveq(const void *a, const void *b)
+gbt_intveq(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(DirectFunctionCall2(interval_eq, IntervalPGetDatum(a), IntervalPGetDatum(b)));
 }
 
 static bool
-gbt_intvle(const void *a, const void *b)
+gbt_intvle(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(DirectFunctionCall2(interval_le, IntervalPGetDatum(a), IntervalPGetDatum(b)));
 }
 
 static bool
-gbt_intvlt(const void *a, const void *b)
+gbt_intvlt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(DirectFunctionCall2(interval_lt, IntervalPGetDatum(a), IntervalPGetDatum(b)));
 }
 
 static int
-gbt_intvkey_cmp(const void *a, const void *b)
+gbt_intvkey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	intvKEY    *ia = (intvKEY *) (((const Nsrt *) a)->t);
 	intvKEY    *ib = (intvKEY *) (((const Nsrt *) b)->t);
@@ -81,7 +81,7 @@ intr2num(const Interval *i)
 }
 
 static float8
-gbt_intv_dist(const void *a, const void *b)
+gbt_intv_dist(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (float8) Abs(intr2num((const Interval *) a) - intr2num((const Interval *) b));
 }
@@ -226,7 +226,7 @@ gbt_intv_consistent(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_BOOL(
-				   gbt_num_consistent(&key, (void *) query, &strategy, GIST_LEAF(entry), &tinfo)
+				   gbt_num_consistent(&key, (void *) query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -245,7 +245,7 @@ gbt_intv_distance(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_FLOAT8(
-			 gbt_num_distance(&key, (void *) query, GIST_LEAF(entry), &tinfo)
+			 gbt_num_distance(&key, (void *) query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -257,7 +257,7 @@ gbt_intv_union(PG_FUNCTION_ARGS)
 	void	   *out = palloc(sizeof(intvKEY));
 
 	*(int *) PG_GETARG_POINTER(1) = sizeof(intvKEY);
-	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
 }
 
 
@@ -287,7 +287,7 @@ gbt_intv_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_num_picksplit(
 									(GistEntryVector *) PG_GETARG_POINTER(0),
 									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
-										&tinfo
+										&tinfo, fcinfo->flinfo
 										));
 }
 
@@ -298,6 +298,6 @@ gbt_intv_same(PG_FUNCTION_ARGS)
 	intvKEY    *b2 = (intvKEY *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
diff --git a/contrib/btree_gist/btree_macaddr.c b/contrib/btree_gist/btree_macaddr.c
index 87d96c0..d530b4e 100644
--- a/contrib/btree_gist/btree_macaddr.c
+++ b/contrib/btree_gist/btree_macaddr.c
@@ -28,37 +28,37 @@ PG_FUNCTION_INFO_V1(gbt_macad_same);
 
 
 static bool
-gbt_macadgt(const void *a, const void *b)
+gbt_macadgt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(DirectFunctionCall2(macaddr_gt, PointerGetDatum(a), PointerGetDatum(b)));
 }
 static bool
-gbt_macadge(const void *a, const void *b)
+gbt_macadge(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(DirectFunctionCall2(macaddr_ge, PointerGetDatum(a), PointerGetDatum(b)));
 }
 
 static bool
-gbt_macadeq(const void *a, const void *b)
+gbt_macadeq(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(DirectFunctionCall2(macaddr_eq, PointerGetDatum(a), PointerGetDatum(b)));
 }
 
 static bool
-gbt_macadle(const void *a, const void *b)
+gbt_macadle(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(DirectFunctionCall2(macaddr_le, PointerGetDatum(a), PointerGetDatum(b)));
 }
 
 static bool
-gbt_macadlt(const void *a, const void *b)
+gbt_macadlt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return DatumGetBool(DirectFunctionCall2(macaddr_lt, PointerGetDatum(a), PointerGetDatum(b)));
 }
 
 
 static int
-gbt_macadkey_cmp(const void *a, const void *b)
+gbt_macadkey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	macKEY	   *ia = (macKEY *) (((const Nsrt *) a)->t);
 	macKEY	   *ib = (macKEY *) (((const Nsrt *) b)->t);
@@ -142,7 +142,7 @@ gbt_macad_consistent(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_BOOL(
-				   gbt_num_consistent(&key, (void *) query, &strategy, GIST_LEAF(entry), &tinfo)
+				   gbt_num_consistent(&key, (void *) query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -154,7 +154,7 @@ gbt_macad_union(PG_FUNCTION_ARGS)
 	void	   *out = palloc0(sizeof(macKEY));
 
 	*(int *) PG_GETARG_POINTER(1) = sizeof(macKEY);
-	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
 }
 
 
@@ -184,7 +184,7 @@ gbt_macad_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_num_picksplit(
 									(GistEntryVector *) PG_GETARG_POINTER(0),
 									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
-										&tinfo
+										&tinfo, fcinfo->flinfo
 										));
 }
 
@@ -195,6 +195,6 @@ gbt_macad_same(PG_FUNCTION_ARGS)
 	macKEY	   *b2 = (macKEY *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
diff --git a/contrib/btree_gist/btree_oid.c b/contrib/btree_gist/btree_oid.c
index ac61a76..e588faa 100644
--- a/contrib/btree_gist/btree_oid.c
+++ b/contrib/btree_gist/btree_oid.c
@@ -26,33 +26,33 @@ PG_FUNCTION_INFO_V1(gbt_oid_same);
 
 
 static bool
-gbt_oidgt(const void *a, const void *b)
+gbt_oidgt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const Oid *) a) > *((const Oid *) b));
 }
 static bool
-gbt_oidge(const void *a, const void *b)
+gbt_oidge(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const Oid *) a) >= *((const Oid *) b));
 }
 static bool
-gbt_oideq(const void *a, const void *b)
+gbt_oideq(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const Oid *) a) == *((const Oid *) b));
 }
 static bool
-gbt_oidle(const void *a, const void *b)
+gbt_oidle(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const Oid *) a) <= *((const Oid *) b));
 }
 static bool
-gbt_oidlt(const void *a, const void *b)
+gbt_oidlt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return (*((const Oid *) a) < *((const Oid *) b));
 }
 
 static int
-gbt_oidkey_cmp(const void *a, const void *b)
+gbt_oidkey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	oidKEY	   *ia = (oidKEY *) (((const Nsrt *) a)->t);
 	oidKEY	   *ib = (oidKEY *) (((const Nsrt *) b)->t);
@@ -69,7 +69,7 @@ gbt_oidkey_cmp(const void *a, const void *b)
 }
 
 static float8
-gbt_oid_dist(const void *a, const void *b)
+gbt_oid_dist(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	Oid			aa = *(const Oid *) a;
 	Oid			bb = *(const Oid *) b;
@@ -152,7 +152,7 @@ gbt_oid_consistent(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_BOOL(
-				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo)
+				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -171,7 +171,7 @@ gbt_oid_distance(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_FLOAT8(
-			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -183,7 +183,7 @@ gbt_oid_union(PG_FUNCTION_ARGS)
 	void	   *out = palloc(sizeof(oidKEY));
 
 	*(int *) PG_GETARG_POINTER(1) = sizeof(oidKEY);
-	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
 }
 
 
@@ -205,7 +205,7 @@ gbt_oid_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_num_picksplit(
 									(GistEntryVector *) PG_GETARG_POINTER(0),
 									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
-										&tinfo
+										&tinfo, fcinfo->flinfo
 										));
 }
 
@@ -216,6 +216,6 @@ gbt_oid_same(PG_FUNCTION_ARGS)
 	oidKEY	   *b2 = (oidKEY *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
diff --git a/contrib/btree_gist/btree_time.c b/contrib/btree_gist/btree_time.c
index 959b282..a4a1ad5 100644
--- a/contrib/btree_gist/btree_time.c
+++ b/contrib/btree_gist/btree_time.c
@@ -38,7 +38,7 @@ PG_FUNCTION_INFO_V1(gbt_time_same);
 
 
 static bool
-gbt_timegt(const void *a, const void *b)
+gbt_timegt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	const TimeADT *aa = (const TimeADT *) a;
 	const TimeADT *bb = (const TimeADT *) b;
@@ -49,7 +49,7 @@ gbt_timegt(const void *a, const void *b)
 }
 
 static bool
-gbt_timege(const void *a, const void *b)
+gbt_timege(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	const TimeADT *aa = (const TimeADT *) a;
 	const TimeADT *bb = (const TimeADT *) b;
@@ -60,7 +60,7 @@ gbt_timege(const void *a, const void *b)
 }
 
 static bool
-gbt_timeeq(const void *a, const void *b)
+gbt_timeeq(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	const TimeADT *aa = (const TimeADT *) a;
 	const TimeADT *bb = (const TimeADT *) b;
@@ -71,7 +71,7 @@ gbt_timeeq(const void *a, const void *b)
 }
 
 static bool
-gbt_timele(const void *a, const void *b)
+gbt_timele(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	const TimeADT *aa = (const TimeADT *) a;
 	const TimeADT *bb = (const TimeADT *) b;
@@ -82,7 +82,7 @@ gbt_timele(const void *a, const void *b)
 }
 
 static bool
-gbt_timelt(const void *a, const void *b)
+gbt_timelt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	const TimeADT *aa = (const TimeADT *) a;
 	const TimeADT *bb = (const TimeADT *) b;
@@ -95,7 +95,7 @@ gbt_timelt(const void *a, const void *b)
 
 
 static int
-gbt_timekey_cmp(const void *a, const void *b)
+gbt_timekey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	timeKEY    *ia = (timeKEY *) (((const Nsrt *) a)->t);
 	timeKEY    *ib = (timeKEY *) (((const Nsrt *) b)->t);
@@ -109,7 +109,7 @@ gbt_timekey_cmp(const void *a, const void *b)
 }
 
 static float8
-gbt_time_dist(const void *a, const void *b)
+gbt_time_dist(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	const TimeADT *aa = (const TimeADT *) a;
 	const TimeADT *bb = (const TimeADT *) b;
@@ -217,7 +217,7 @@ gbt_time_consistent(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_BOOL(
-				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo)
+				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -235,7 +235,7 @@ gbt_time_distance(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_FLOAT8(
-			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -261,7 +261,7 @@ gbt_timetz_consistent(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_BOOL(
-				   gbt_num_consistent(&key, (void *) &qqq, &strategy, GIST_LEAF(entry), &tinfo)
+				   gbt_num_consistent(&key, (void *) &qqq, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -273,7 +273,7 @@ gbt_time_union(PG_FUNCTION_ARGS)
 	void	   *out = palloc(sizeof(timeKEY));
 
 	*(int *) PG_GETARG_POINTER(1) = sizeof(timeKEY);
-	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
 }
 
 
@@ -326,7 +326,7 @@ gbt_time_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_num_picksplit(
 									(GistEntryVector *) PG_GETARG_POINTER(0),
 									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
-										&tinfo
+										&tinfo, fcinfo->flinfo
 										));
 }
 
@@ -337,6 +337,6 @@ gbt_time_same(PG_FUNCTION_ARGS)
 	timeKEY    *b2 = (timeKEY *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 97408f5..13bc394 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -40,7 +40,7 @@ PG_FUNCTION_INFO_V1(gbt_ts_same);
 
 
 static bool
-gbt_tsgt(const void *a, const void *b)
+gbt_tsgt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	const Timestamp *aa = (const Timestamp *) a;
 	const Timestamp *bb = (const Timestamp *) b;
@@ -51,7 +51,7 @@ gbt_tsgt(const void *a, const void *b)
 }
 
 static bool
-gbt_tsge(const void *a, const void *b)
+gbt_tsge(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	const Timestamp *aa = (const Timestamp *) a;
 	const Timestamp *bb = (const Timestamp *) b;
@@ -62,7 +62,7 @@ gbt_tsge(const void *a, const void *b)
 }
 
 static bool
-gbt_tseq(const void *a, const void *b)
+gbt_tseq(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	const Timestamp *aa = (const Timestamp *) a;
 	const Timestamp *bb = (const Timestamp *) b;
@@ -73,7 +73,7 @@ gbt_tseq(const void *a, const void *b)
 }
 
 static bool
-gbt_tsle(const void *a, const void *b)
+gbt_tsle(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	const Timestamp *aa = (const Timestamp *) a;
 	const Timestamp *bb = (const Timestamp *) b;
@@ -84,7 +84,7 @@ gbt_tsle(const void *a, const void *b)
 }
 
 static bool
-gbt_tslt(const void *a, const void *b)
+gbt_tslt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	const Timestamp *aa = (const Timestamp *) a;
 	const Timestamp *bb = (const Timestamp *) b;
@@ -96,7 +96,7 @@ gbt_tslt(const void *a, const void *b)
 
 
 static int
-gbt_tskey_cmp(const void *a, const void *b)
+gbt_tskey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	tsKEY	   *ia = (tsKEY *) (((const Nsrt *) a)->t);
 	tsKEY	   *ib = (tsKEY *) (((const Nsrt *) b)->t);
@@ -110,7 +110,7 @@ gbt_tskey_cmp(const void *a, const void *b)
 }
 
 static float8
-gbt_ts_dist(const void *a, const void *b)
+gbt_ts_dist(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	const Timestamp *aa = (const Timestamp *) a;
 	const Timestamp *bb = (const Timestamp *) b;
@@ -265,7 +265,7 @@ gbt_ts_consistent(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_BOOL(
-				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo)
+				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -283,7 +283,7 @@ gbt_ts_distance(PG_FUNCTION_ARGS)
 	key.upper = (GBT_NUMKEY *) &kkk->upper;
 
 	PG_RETURN_FLOAT8(
-			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -308,7 +308,7 @@ gbt_tstz_consistent(PG_FUNCTION_ARGS)
 	qqq = tstz_to_ts_gmt(query);
 
 	PG_RETURN_BOOL(
-				   gbt_num_consistent(&key, (void *) &qqq, &strategy, GIST_LEAF(entry), &tinfo)
+				   gbt_num_consistent(&key, (void *) &qqq, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -328,7 +328,7 @@ gbt_tstz_distance(PG_FUNCTION_ARGS)
 	qqq = tstz_to_ts_gmt(query);
 
 	PG_RETURN_FLOAT8(
-			  gbt_num_distance(&key, (void *) &qqq, GIST_LEAF(entry), &tinfo)
+			  gbt_num_distance(&key, (void *) &qqq, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -340,7 +340,7 @@ gbt_ts_union(PG_FUNCTION_ARGS)
 	void	   *out = palloc(sizeof(tsKEY));
 
 	*(int *) PG_GETARG_POINTER(1) = sizeof(tsKEY);
-	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
 }
 
 
@@ -389,7 +389,7 @@ gbt_ts_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_num_picksplit(
 									(GistEntryVector *) PG_GETARG_POINTER(0),
 									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
-										&tinfo
+										&tinfo, fcinfo->flinfo
 										));
 }
 
@@ -400,6 +400,6 @@ gbt_ts_same(PG_FUNCTION_ARGS)
 	tsKEY	   *b2 = (tsKEY *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
diff --git a/contrib/btree_gist/btree_utils_num.c b/contrib/btree_gist/btree_utils_num.c
index 99cb41f..e30924b 100644
--- a/contrib/btree_gist/btree_utils_num.c
+++ b/contrib/btree_gist/btree_utils_num.c
@@ -159,7 +159,7 @@ gbt_num_fetch(GISTENTRY *entry, const gbtree_ninfo *tinfo)
 */
 
 void *
-gbt_num_union(GBT_NUMKEY *out, const GistEntryVector *entryvec, const gbtree_ninfo *tinfo)
+gbt_num_union(GBT_NUMKEY *out, const GistEntryVector *entryvec, const gbtree_ninfo *tinfo, FmgrInfo *flinfo)
 {
 	int			i,
 				numranges;
@@ -181,9 +181,9 @@ gbt_num_union(GBT_NUMKEY *out, const GistEntryVector *entryvec, const gbtree_nin
 		cur = (GBT_NUMKEY *) DatumGetPointer((entryvec->vector[i].key));
 		c.lower = &cur[0];
 		c.upper = &cur[tinfo->size];
-		if ((*tinfo->f_gt) (o.lower, c.lower))	/* out->lower > cur->lower */
+		if ((*tinfo->f_gt) (o.lower, c.lower, flinfo))	/* out->lower > cur->lower */
 			memcpy((void *) o.lower, (void *) c.lower, tinfo->size);
-		if ((*tinfo->f_lt) (o.upper, c.upper))	/* out->upper < cur->upper */
+		if ((*tinfo->f_lt) (o.upper, c.upper, flinfo))	/* out->upper < cur->upper */
 			memcpy((void *) o.upper, (void *) c.upper, tinfo->size);
 	}
 
@@ -197,7 +197,7 @@ gbt_num_union(GBT_NUMKEY *out, const GistEntryVector *entryvec, const gbtree_nin
 */
 
 bool
-gbt_num_same(const GBT_NUMKEY *a, const GBT_NUMKEY *b, const gbtree_ninfo *tinfo)
+gbt_num_same(const GBT_NUMKEY *a, const GBT_NUMKEY *b, const gbtree_ninfo *tinfo, FmgrInfo *flinfo)
 {
 	GBT_NUMKEY_R b1,
 				b2;
@@ -207,13 +207,13 @@ gbt_num_same(const GBT_NUMKEY *a, const GBT_NUMKEY *b, const gbtree_ninfo *tinfo
 	b2.lower = &(((GBT_NUMKEY *) b)[0]);
 	b2.upper = &(((GBT_NUMKEY *) b)[tinfo->size]);
 
-	return ((*tinfo->f_eq) (b1.lower, b2.lower) &&
-			(*tinfo->f_eq) (b1.upper, b2.upper));
+	return ((*tinfo->f_eq) (b1.lower, b2.lower, flinfo) &&
+			(*tinfo->f_eq) (b1.upper, b2.upper, flinfo));
 }
 
 
 void
-gbt_num_bin_union(Datum *u, GBT_NUMKEY *e, const gbtree_ninfo *tinfo)
+gbt_num_bin_union(Datum *u, GBT_NUMKEY *e, const gbtree_ninfo *tinfo, FmgrInfo *flinfo)
 {
 	GBT_NUMKEY_R rd;
 
@@ -232,9 +232,9 @@ gbt_num_bin_union(Datum *u, GBT_NUMKEY *e, const gbtree_ninfo *tinfo)
 
 		ur.lower = &(((GBT_NUMKEY *) DatumGetPointer(*u))[0]);
 		ur.upper = &(((GBT_NUMKEY *) DatumGetPointer(*u))[tinfo->size]);
-		if ((*tinfo->f_gt) ((void *) ur.lower, (void *) rd.lower))
+		if ((*tinfo->f_gt) ((void *) ur.lower, (void *) rd.lower, flinfo))
 			memcpy((void *) ur.lower, (void *) rd.lower, tinfo->size);
-		if ((*tinfo->f_lt) ((void *) ur.upper, (void *) rd.upper))
+		if ((*tinfo->f_lt) ((void *) ur.upper, (void *) rd.upper, flinfo))
 			memcpy((void *) ur.upper, (void *) rd.upper, tinfo->size);
 	}
 }
@@ -252,39 +252,40 @@ gbt_num_consistent(const GBT_NUMKEY_R *key,
 				   const void *query,
 				   const StrategyNumber *strategy,
 				   bool is_leaf,
-				   const gbtree_ninfo *tinfo)
+				   const gbtree_ninfo *tinfo,
+				   FmgrInfo *flinfo)
 {
 	bool		retval;
 
 	switch (*strategy)
 	{
 		case BTLessEqualStrategyNumber:
-			retval = (*tinfo->f_ge) (query, key->lower);
+			retval = (*tinfo->f_ge) (query, key->lower, flinfo);
 			break;
 		case BTLessStrategyNumber:
 			if (is_leaf)
-				retval = (*tinfo->f_gt) (query, key->lower);
+				retval = (*tinfo->f_gt) (query, key->lower, flinfo);
 			else
-				retval = (*tinfo->f_ge) (query, key->lower);
+				retval = (*tinfo->f_ge) (query, key->lower, flinfo);
 			break;
 		case BTEqualStrategyNumber:
 			if (is_leaf)
-				retval = (*tinfo->f_eq) (query, key->lower);
+				retval = (*tinfo->f_eq) (query, key->lower, flinfo);
 			else
-				retval = ((*tinfo->f_le) (key->lower, query) && (*tinfo->f_le) (query, key->upper)) ? true : false;
+				retval = ((*tinfo->f_le) (key->lower, query, flinfo) && (*tinfo->f_le) (query, key->upper, flinfo)) ? true : false;
 			break;
 		case BTGreaterStrategyNumber:
 			if (is_leaf)
-				retval = (*tinfo->f_lt) (query, key->upper);
+				retval = (*tinfo->f_lt) (query, key->upper, flinfo);
 			else
-				retval = (*tinfo->f_le) (query, key->upper);
+				retval = (*tinfo->f_le) (query, key->upper, flinfo);
 			break;
 		case BTGreaterEqualStrategyNumber:
-			retval = (*tinfo->f_le) (query, key->upper);
+			retval = (*tinfo->f_le) (query, key->upper, flinfo);
 			break;
 		case BtreeGistNotEqualStrategyNumber:
-			retval = (!((*tinfo->f_eq) (query, key->lower) &&
-						(*tinfo->f_eq) (query, key->upper))) ? true : false;
+			retval = (!((*tinfo->f_eq) (query, key->lower, flinfo) &&
+						(*tinfo->f_eq) (query, key->upper, flinfo))) ? true : false;
 			break;
 		default:
 			retval = false;
@@ -302,17 +303,18 @@ float8
 gbt_num_distance(const GBT_NUMKEY_R *key,
 				 const void *query,
 				 bool is_leaf,
-				 const gbtree_ninfo *tinfo)
+				 const gbtree_ninfo *tinfo,
+				 FmgrInfo *flinfo)
 {
 	float8		retval;
 
 	if (tinfo->f_dist == NULL)
 		elog(ERROR, "KNN search is not supported for btree_gist type %d",
 			 (int) tinfo->t);
-	if (tinfo->f_le(query, key->lower))
-		retval = tinfo->f_dist(query, key->lower);
-	else if (tinfo->f_ge(query, key->upper))
-		retval = tinfo->f_dist(query, key->upper);
+	if (tinfo->f_le(query, key->lower, flinfo))
+		retval = tinfo->f_dist(query, key->lower, flinfo);
+	else if (tinfo->f_ge(query, key->upper, flinfo))
+		retval = tinfo->f_dist(query, key->upper, flinfo);
 	else
 		retval = 0.0;
 
@@ -322,7 +324,7 @@ gbt_num_distance(const GBT_NUMKEY_R *key,
 
 GIST_SPLITVEC *
 gbt_num_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
-				  const gbtree_ninfo *tinfo)
+				  const gbtree_ninfo *tinfo, FmgrInfo *flinfo)
 {
 	OffsetNumber i,
 				maxoff = entryvec->n - 1;
@@ -345,7 +347,7 @@ gbt_num_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
 		arr[i].t = (GBT_NUMKEY *) DatumGetPointer((entryvec->vector[i].key));
 		arr[i].i = i;
 	}
-	qsort((void *) &arr[FirstOffsetNumber], maxoff - FirstOffsetNumber + 1, sizeof(Nsrt), tinfo->f_cmp);
+	qsort_arg((void *) &arr[FirstOffsetNumber], maxoff - FirstOffsetNumber + 1, sizeof(Nsrt), (qsort_arg_comparator) tinfo->f_cmp, (void *) flinfo);
 
 	/* We do simply create two parts */
 
@@ -353,13 +355,13 @@ gbt_num_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
 	{
 		if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
 		{
-			gbt_num_bin_union(&v->spl_ldatum, arr[i].t, tinfo);
+			gbt_num_bin_union(&v->spl_ldatum, arr[i].t, tinfo, flinfo);
 			v->spl_left[v->spl_nleft] = arr[i].i;
 			v->spl_nleft++;
 		}
 		else
 		{
-			gbt_num_bin_union(&v->spl_rdatum, arr[i].t, tinfo);
+			gbt_num_bin_union(&v->spl_rdatum, arr[i].t, tinfo, flinfo);
 			v->spl_right[v->spl_nright] = arr[i].i;
 			v->spl_nright++;
 		}
diff --git a/contrib/btree_gist/btree_utils_num.h b/contrib/btree_gist/btree_utils_num.h
index 67d4968..17561fa 100644
--- a/contrib/btree_gist/btree_utils_num.h
+++ b/contrib/btree_gist/btree_utils_num.h
@@ -42,13 +42,13 @@ typedef struct
 
 	/* Methods */
 
-	bool		(*f_gt) (const void *, const void *);	/* greater than */
-	bool		(*f_ge) (const void *, const void *);	/* greater or equal */
-	bool		(*f_eq) (const void *, const void *);	/* equal */
-	bool		(*f_le) (const void *, const void *);	/* less or equal */
-	bool		(*f_lt) (const void *, const void *);	/* less than */
-	int			(*f_cmp) (const void *, const void *);	/* key compare function */
-	float8		(*f_dist) (const void *, const void *); /* key distance function */
+	bool		(*f_gt) (const void *, const void *, FmgrInfo *);	/* greater than */
+	bool		(*f_ge) (const void *, const void *, FmgrInfo *);	/* greater or equal */
+	bool		(*f_eq) (const void *, const void *, FmgrInfo *);	/* equal */
+	bool		(*f_le) (const void *, const void *, FmgrInfo *);	/* less or equal */
+	bool		(*f_lt) (const void *, const void *, FmgrInfo *);	/* less than */
+	int			(*f_cmp) (const void *, const void *, FmgrInfo *);	/* key compare function */
+	float8		(*f_dist) (const void *, const void *, FmgrInfo *); /* key distance function */
 } gbtree_ninfo;
 
 
@@ -113,25 +113,25 @@ extern Interval *abs_interval(Interval *a);
 
 extern bool gbt_num_consistent(const GBT_NUMKEY_R *key, const void *query,
 				   const StrategyNumber *strategy, bool is_leaf,
-				   const gbtree_ninfo *tinfo);
+				   const gbtree_ninfo *tinfo, FmgrInfo *flinfo);
 
 extern float8 gbt_num_distance(const GBT_NUMKEY_R *key, const void *query,
-				 bool is_leaf, const gbtree_ninfo *tinfo);
+				 bool is_leaf, const gbtree_ninfo *tinfo, FmgrInfo *flinfo);
 
 extern GIST_SPLITVEC *gbt_num_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
-				  const gbtree_ninfo *tinfo);
+				  const gbtree_ninfo *tinfo, FmgrInfo *flinfo);
 
 extern GISTENTRY *gbt_num_compress(GISTENTRY *entry, const gbtree_ninfo *tinfo);
 
 extern GISTENTRY *gbt_num_fetch(GISTENTRY *entry, const gbtree_ninfo *tinfo);
 
 extern void *gbt_num_union(GBT_NUMKEY *out, const GistEntryVector *entryvec,
-			  const gbtree_ninfo *tinfo);
+			  const gbtree_ninfo *tinfo, FmgrInfo *flinfo);
 
 extern bool gbt_num_same(const GBT_NUMKEY *a, const GBT_NUMKEY *b,
-			 const gbtree_ninfo *tinfo);
+			 const gbtree_ninfo *tinfo, FmgrInfo *flinfo);
 
 extern void gbt_num_bin_union(Datum *u, GBT_NUMKEY *e,
-				  const gbtree_ninfo *tinfo);
+				  const gbtree_ninfo *tinfo, FmgrInfo *flinfo);
 
 #endif
diff --git a/contrib/btree_gist/btree_uuid.c b/contrib/btree_gist/btree_uuid.c
index 44cef64..5ed8092 100644
--- a/contrib/btree_gist/btree_uuid.c
+++ b/contrib/btree_gist/btree_uuid.c
@@ -34,37 +34,37 @@ uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2)
 }
 
 static bool
-gbt_uuidgt(const void *a, const void *b)
+gbt_uuidgt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) > 0;
 }
 
 static bool
-gbt_uuidge(const void *a, const void *b)
+gbt_uuidge(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) >= 0;
 }
 
 static bool
-gbt_uuideq(const void *a, const void *b)
+gbt_uuideq(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) == 0;
 }
 
 static bool
-gbt_uuidle(const void *a, const void *b)
+gbt_uuidle(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) <= 0;
 }
 
 static bool
-gbt_uuidlt(const void *a, const void *b)
+gbt_uuidlt(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) < 0;
 }
 
 static int
-gbt_uuidkey_cmp(const void *a, const void *b)
+gbt_uuidkey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
 {
 	uuidKEY    *ia = (uuidKEY *) (((const Nsrt *) a)->t);
 	uuidKEY    *ib = (uuidKEY *) (((const Nsrt *) b)->t);
@@ -150,7 +150,7 @@ gbt_uuid_consistent(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(
 				   gbt_num_consistent(&key, (void *) query, &strategy,
-									  GIST_LEAF(entry), &tinfo)
+									  GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
 		);
 }
 
@@ -161,7 +161,7 @@ gbt_uuid_union(PG_FUNCTION_ARGS)
 	void	   *out = palloc(sizeof(uuidKEY));
 
 	*(int *) PG_GETARG_POINTER(1) = sizeof(uuidKEY);
-	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
 }
 
 /*
@@ -222,7 +222,7 @@ gbt_uuid_picksplit(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(gbt_num_picksplit(
 									(GistEntryVector *) PG_GETARG_POINTER(0),
 									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
-										&tinfo
+										&tinfo, fcinfo->flinfo
 										));
 }
 
@@ -233,6 +233,6 @@ gbt_uuid_same(PG_FUNCTION_ARGS)
 	uuidKEY    *b2 = (uuidKEY *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
 	PG_RETURN_POINTER(result);
 }
-- 
2.4.11

>From 4f13d88c2b14d736360830eab865e17b62e29d8f Mon Sep 17 00:00:00 2001
From: Andrew Dunstan <and...@dunslane.net>
Date: Sun, 26 Feb 2017 09:38:07 -0500
Subject: [PATCH 1/4] Provide a direct function call mechanism that uses the
 caller's context.

The current DirectFunctionCall functions use NULL as the flinfo in
initializing the FunctionCallInfoData for the call. That means the
called function has no fn_mcxt or fn_extra to work with, and attempting
to do so will result in an access violation. These functions instead use
the provided flinfo, which will usually be the caller's own flinfo. The
caller needs to ensure that it doesn't use the fn_extra in way that is
incompatible with the way the called function will use it. The called
function should not rely on anything else in the provided context, as it
will be relevant to the caller, not the callee.

Original code from Tom Lane.

Discussion: https://postgr.es/m/db2b70a4-78d7-294a-a315-8e7f506c5...@2ndquadrant.com
---
 src/backend/utils/fmgr/fmgr.c | 50 +++++++++++++++++++++++++++++++++++++++++++
 src/include/fmgr.h            | 15 +++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 3976496..93dc229 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -1276,6 +1276,56 @@ DirectFunctionCall9Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
 	return result;
 }
 
+/*
+ * These functions work like the DirectFunctionCall functions except that
+ * they use the flinfo parameter to initialise the fcinfo for the call.
+ * It's recommended that the callee only use the fn_extra and fn_mcxt
+ * fields, as other fields will typically describe the calling function
+ * not the callee.  Conversely, the calling function should not have
+ * used fn_extra, unless its use is known to be compatible with the callee's.
+ */
+
+Datum
+CallerFInfoFunctionCall1(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum arg1)
+{
+	FunctionCallInfoData fcinfo;
+	Datum		result;
+
+	InitFunctionCallInfoData(fcinfo, flinfo, 1, collation, NULL, NULL);
+
+	fcinfo.arg[0] = arg1;
+	fcinfo.argnull[0] = false;
+
+	result = (*func) (&fcinfo);
+
+	/* Check for null result, since caller is clearly not expecting one */
+	if (fcinfo.isnull)
+		elog(ERROR, "function %p returned NULL", (void *) func);
+
+	return result;
+}
+
+Datum
+CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
+{
+	FunctionCallInfoData fcinfo;
+	Datum		result;
+
+	InitFunctionCallInfoData(fcinfo, flinfo, 2, collation, NULL, NULL);
+
+	fcinfo.arg[0] = arg1;
+	fcinfo.arg[1] = arg2;
+	fcinfo.argnull[0] = false;
+	fcinfo.argnull[1] = false;
+
+	result = (*func) (&fcinfo);
+
+	/* Check for null result, since caller is clearly not expecting one */
+	if (fcinfo.isnull)
+		elog(ERROR, "function %p returned NULL", (void *) func);
+
+	return result;
+}
 
 /*
  * These are for invocation of a previously-looked-up function with a
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index a671480..0bac91a 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -475,7 +475,21 @@ extern Datum DirectFunctionCall9Coll(PGFunction func, Oid collation,
 						Datum arg6, Datum arg7, Datum arg8,
 						Datum arg9);
 
+/*
+ * These functions work like the DirectFunctionCall functions except that
+ * they use the flinfo parameter to initialise the fcinfo for the call.
+ * It's recommended that the callee only use the fn_extra and fn_mcxt
+ * fields, as other fields will typically describe the calling function
+ * not the callee.  Conversely, the calling function should not have
+ * used fn_extra, unless its use is known to be compatible with the callee's.
+ */
+
+extern Datum CallerFInfoFunctionCall1(PGFunction func, FmgrInfo *flinfo,
+						 Oid collation, Datum arg1);
+extern Datum CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo,
+						 Oid collation, Datum arg1, Datum arg2);
+
+
 /* These are for invocation of a previously-looked-up function with a
  * directly-computed parameter list.  Note that neither arguments nor result
  * are allowed to be NULL.
-- 
2.4.11

>From dcf73b5f94c2729167c2659dcab2fe5e1e292792 Mon Sep 17 00:00:00 2001
From: Andrew Dunstan <and...@dunslane.net>
Date: Mon, 27 Feb 2017 16:10:41 -0500
Subject: [PATCH] Add btree_gin support for enum types

---
 contrib/btree_gin/Makefile                |  4 +-
 contrib/btree_gin/btree_gin--1.0--1.1.sql | 47 ++++++++++++++++++++++
 contrib/btree_gin/btree_gin.c             | 67 +++++++++++++++++++++++++++----
 contrib/btree_gin/btree_gin.control       |  2 +-
 contrib/btree_gin/expected/enum.out       | 63 +++++++++++++++++++++++++++++
 doc/src/sgml/btree-gin.sgml               |  3 +-
 6 files changed, 174 insertions(+), 12 deletions(-)
 create mode 100644 contrib/btree_gin/btree_gin--1.0--1.1.sql
 create mode 100644 contrib/btree_gin/expected/enum.out

diff --git a/contrib/btree_gin/Makefile b/contrib/btree_gin/Makefile
index 0492091..c6aae26 100644
--- a/contrib/btree_gin/Makefile
+++ b/contrib/btree_gin/Makefile
@@ -4,13 +4,13 @@ MODULE_big = btree_gin
 OBJS = btree_gin.o $(WIN32RES)
 
 EXTENSION = btree_gin
-DATA = btree_gin--1.0.sql btree_gin--unpackaged--1.0.sql
+DATA = btree_gin--1.0.sql btree_gin--unpackaged--1.0.sql btree_gin--1.0--1.1.sql
 PGFILEDESC = "btree_gin - B-tree equivalent GIN operator classes"
 
 REGRESS = install_btree_gin int2 int4 int8 float4 float8 money oid \
 	timestamp timestamptz time timetz date interval \
 	macaddr inet cidr text varchar char bytea bit varbit \
-	numeric
+	numeric enum
 
 ifdef USE_PGXS
 PG_CONFIG = pg_config
diff --git a/contrib/btree_gin/btree_gin--1.0--1.1.sql b/contrib/btree_gin/btree_gin--1.0--1.1.sql
new file mode 100644
index 0000000..3c40ccd
--- /dev/null
+++ b/contrib/btree_gin/btree_gin--1.0--1.1.sql
@@ -0,0 +1,47 @@
+/* contrib/btree_gin/btree_gin--1.0--1.1.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION btree_gin UPDATE TO '1.1'" to load this file. \quit
+
+--
+--
+--
+-- enum ops
+--
+--
+
+
+CREATE FUNCTION gin_extract_value_anyenum(anyenum, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_compare_prefix_anyenum(anyenum, anyenum, int2, internal)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_extract_query_anyenum(anyenum, internal, int2, internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_enum_cmp(anyenum, anyenum)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR CLASS enum_ops
+DEFAULT FOR TYPE anyenum USING gin
+AS
+    OPERATOR        1       <,
+    OPERATOR        2       <=,
+    OPERATOR        3       =,
+    OPERATOR        4       >=,
+    OPERATOR        5       >,
+    FUNCTION        1       gin_enum_cmp(anyenum,anyenum),
+    FUNCTION        2       gin_extract_value_anyenum(anyenum, internal),
+    FUNCTION        3       gin_extract_query_anyenum(anyenum, internal, int2, internal, internal),
+    FUNCTION        4       gin_btree_consistent(internal, int2, anyelement, int4, internal, internal),
+    FUNCTION        5       gin_compare_prefix_anyenum(anyenum,anyenum,int2, internal),
+STORAGE         anyenum;
diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 030b610..840b8e2 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -25,7 +25,6 @@ typedef struct QueryInfo
 	Datum		(*typecmp) (FunctionCallInfo);
 } QueryInfo;
 
-
 /*** GIN support functions shared by all datatypes ***/
 
 static Datum
@@ -112,13 +111,14 @@ gin_btree_compare_prefix(FunctionCallInfo fcinfo)
 	int32		res,
 				cmp;
 
-	cmp = DatumGetInt32(DirectFunctionCall2Coll(
-												data->typecmp,
-												PG_GET_COLLATION(),
-								   (data->strategy == BTLessStrategyNumber ||
-								 data->strategy == BTLessEqualStrategyNumber)
-												? data->datum : a,
-												b));
+	cmp = DatumGetInt32(CallerFInfoFunctionCall2(
+							data->typecmp,
+							fcinfo->flinfo,
+							PG_GET_COLLATION(),
+							(data->strategy == BTLessStrategyNumber ||
+							 data->strategy == BTLessEqualStrategyNumber)
+							? data->datum : a,
+							b));
 
 	switch (data->strategy)
 	{
@@ -416,3 +416,54 @@ leftmostvalue_numeric(void)
 }
 
 GIN_SUPPORT(numeric, true, leftmostvalue_numeric, gin_numeric_cmp)
+
+/*
+ * Use a similar trick to that used for numeric for enums, since we don't
+ * actually know the leftmost value of any enum without knowing the concrete
+ * type, so we use a dummy leftmost value of InvalidOid.
+ *
+ * Note that we use CallerFInfoFunctionCall2 here so that enum_cmp
+ * gets a valid fn_extra to work with. Unlike most other type comparison
+ * routines it needs it, so we can't use DirectFunctionCall2.
+ */
+
+
+#define ENUM_IS_LEFTMOST(x)	((x) == InvalidOid)
+
+PG_FUNCTION_INFO_V1(gin_enum_cmp);
+
+Datum
+gin_enum_cmp(PG_FUNCTION_ARGS)
+{
+	Oid		a = PG_GETARG_OID(0);
+	Oid		b = PG_GETARG_OID(1);
+	int		res = 0;
+
+	if (ENUM_IS_LEFTMOST(a))
+	{
+		res = (ENUM_IS_LEFTMOST(b)) ? 0 : -1;
+	}
+	else if (ENUM_IS_LEFTMOST(b))
+	{
+		res = 1;
+	}
+	else
+	{
+		res = DatumGetInt32(CallerFInfoFunctionCall2(
+								enum_cmp,
+								fcinfo->flinfo,
+								PG_GET_COLLATION(),
+								ObjectIdGetDatum(a),
+								ObjectIdGetDatum(b)));
+	}
+
+	PG_RETURN_INT32(res);
+}
+
+static Datum
+leftmostvalue_enum(void)
+{
+	return ObjectIdGetDatum(InvalidOid);
+}
+
+GIN_SUPPORT(anyenum, false, leftmostvalue_enum, gin_enum_cmp)
diff --git a/contrib/btree_gin/btree_gin.control b/contrib/btree_gin/btree_gin.control
index 3b2cb2d..d96436e 100644
--- a/contrib/btree_gin/btree_gin.control
+++ b/contrib/btree_gin/btree_gin.control
@@ -1,5 +1,5 @@
 # btree_gin extension
 comment = 'support for indexing common datatypes in GIN'
-default_version = '1.0'
+default_version = '1.1'
 module_pathname = '$libdir/btree_gin'
 relocatable = true
diff --git a/contrib/btree_gin/expected/enum.out b/contrib/btree_gin/expected/enum.out
new file mode 100644
index 0000000..bad1cc0
--- /dev/null
+++ b/contrib/btree_gin/expected/enum.out
@@ -0,0 +1,63 @@
+set enable_seqscan=off;
+CREATE TYPE rainbow AS ENUM ('r','o','y','g','b','i','v');
+CREATE TABLE test_enum (
+	i rainbow
+);
+INSERT INTO test_enum VALUES ('v'),('y'),('r'),('g'),('o'),('i'),('b');
+CREATE INDEX idx_enum ON test_enum USING gin (i);
+SELECT * FROM test_enum WHERE i<'g'::rainbow ORDER BY i;
+ i 
+---
+ r
+ o
+ y
+(3 rows)
+
+SELECT * FROM test_enum WHERE i<='g'::rainbow ORDER BY i;
+ i 
+---
+ r
+ o
+ y
+ g
+(4 rows)
+
+SELECT * FROM test_enum WHERE i='g'::rainbow ORDER BY i;
+ i 
+---
+ g
+(1 row)
+
+SELECT * FROM test_enum WHERE i>='g'::rainbow ORDER BY i;
+ i 
+---
+ g
+ b
+ i
+ v
+(4 rows)
+
+SELECT * FROM test_enum WHERE i>'g'::rainbow ORDER BY i;
+ i 
+---
+ b
+ i
+ v
+(3 rows)
+
+explain (costs off) SELECT * FROM test_enum WHERE i>='g'::rainbow ORDER BY i;
+                  QUERY PLAN                   
+-----------------------------------------------
+ Sort
+   Sort Key: i
+   ->  Bitmap Heap Scan on test_enum
+         Recheck Cond: (i >= 'g'::rainbow)
+         ->  Bitmap Index Scan on idx_enum
+               Index Cond: (i >= 'g'::rainbow)
+(6 rows)
+
+-- make sure we handle the non-evenly-numbered oid case for enums
+create type e as enum ('0', '2', '3');
+alter type e add value '1' after '0';
+create table t as select (i % 4)::text::e from generate_series(0, 100000) as i;
+create index on t using gin (e);
diff --git a/doc/src/sgml/btree-gin.sgml b/doc/src/sgml/btree-gin.sgml
index 2b081db..f407e92 100644
--- a/doc/src/sgml/btree-gin.sgml
+++ b/doc/src/sgml/btree-gin.sgml
@@ -16,7 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>"char"</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, and <type>cidr</>.
+  <type>varbit</>, <type>macaddr</>, <type>inet</>, <type>cidr</>,
+  and all <type>enum</> types.
  </para>
 
  <para>
-- 
2.4.11

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to