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_macaddr8.o btree_inet.o btree_text.o btree_bytea.o \
- btree_bit.o btree_numeric.o btree_uuid.o $(WIN32RES)
+ btree_macaddr.o btree_macaddr8.o btree_inet.o btree_text.o \
+ btree_bytea.o btree_bit.o 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.3--1.4.sql
+ btree_gist--1.3--1.4.sql btree_gist--1.4--1.5.sql
PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes"
REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \
time timetz date interval macaddr macaddr8 inet cidr text varchar char \
- bytea bit varbit numeric uuid not_equal
+ bytea bit varbit numeric uuid not_equal enum
SHLIB_LINK += $(filter -lm, $(LIBS))
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/* contrib/btree_gist/btree_gist--1.4--1.5.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.5'" 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) ;
# btree_gist extension
comment = 'support for indexing common datatypes in GiST'
-default_version = '1.4'
+default_version = '1.5'
module_pathname = '$libdir/btree_gist'
relocatable = true
gbt_t_bytea,
gbt_t_bit,
gbt_t_inet,
- gbt_t_uuid
+ gbt_t_uuid,
+ gbt_t_enum
};
#endif
leaf = &v.i8;
break;
case gbt_t_oid:
+ case gbt_t_enum:
v.i4 = DatumGetObjectId(entry->key);
leaf = &v.i4;
break;
datum = Int64GetDatum(*(int64 *) entry->key);
break;
case gbt_t_oid:
+ case gbt_t_enum:
datum = ObjectIdGetDatum(*(Oid *) entry->key);
break;
case gbt_t_float4:
--- /dev/null
+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
--- /dev/null
+-- 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)
+
--- /dev/null
+-- 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;
<type>oid</>, <type>money</>, <type>char</>,
<type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
<type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
- <type>cidr</> and <type>uuid</>.
+ <type>cidr</>, <type>uuid</>, and all <type>enum</> types.
</para>
<para>