From 74ebe1490de916409458e3d1adf47dfa20b1fefb Mon Sep 17 00:00:00 2001
From: Andrew Dunstan <andrew@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

