Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 4ad0f88

Browse files
committed
Add btree_gin support for enum types
Reviewed by Tom Lane and Anastasia Lubennikova Discussion: http://postgr.es/m/56EA8A71.8060107@dunslane.net
1 parent f7946a9 commit 4ad0f88

File tree

6 files changed

+199
-11
lines changed

6 files changed

+199
-11
lines changed

contrib/btree_gin/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ MODULE_big = btree_gin
44
OBJS = btree_gin.o $(WIN32RES)
55

66
EXTENSION = btree_gin
7-
DATA = btree_gin--1.0.sql btree_gin--1.0--1.1.sql btree_gin--unpackaged--1.0.sql
7+
DATA = btree_gin--1.0.sql btree_gin--1.0--1.1.sql btree_gin--1.1--1.2.sql \
8+
btree_gin--unpackaged--1.0.sql
89
PGFILEDESC = "btree_gin - B-tree equivalent GIN operator classes"
910

1011
REGRESS = install_btree_gin int2 int4 int8 float4 float8 money oid \
1112
timestamp timestamptz time timetz date interval \
1213
macaddr macaddr8 inet cidr text varchar char bytea bit varbit \
13-
numeric
14+
numeric enum
1415

1516
ifdef USE_PGXS
1617
PG_CONFIG = pg_config
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/* contrib/btree_gin/btree_gin--1.1--1.2.sql */
2+
3+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
4+
\echo Use "ALTER EXTENSION btree_gin UPDATE TO '1.1'" to load this file. \quit
5+
6+
--
7+
--
8+
--
9+
-- enum ops
10+
--
11+
--
12+
13+
14+
CREATE FUNCTION gin_extract_value_anyenum(anyenum, internal)
15+
RETURNS internal
16+
AS 'MODULE_PATHNAME'
17+
LANGUAGE C STRICT IMMUTABLE;
18+
19+
CREATE FUNCTION gin_compare_prefix_anyenum(anyenum, anyenum, int2, internal)
20+
RETURNS int4
21+
AS 'MODULE_PATHNAME'
22+
LANGUAGE C STRICT IMMUTABLE;
23+
24+
CREATE FUNCTION gin_extract_query_anyenum(anyenum, internal, int2, internal, internal)
25+
RETURNS internal
26+
AS 'MODULE_PATHNAME'
27+
LANGUAGE C STRICT IMMUTABLE;
28+
29+
CREATE FUNCTION gin_enum_cmp(anyenum, anyenum)
30+
RETURNS int4
31+
AS 'MODULE_PATHNAME'
32+
LANGUAGE C STRICT IMMUTABLE;
33+
34+
CREATE OPERATOR CLASS enum_ops
35+
DEFAULT FOR TYPE anyenum USING gin
36+
AS
37+
OPERATOR 1 <,
38+
OPERATOR 2 <=,
39+
OPERATOR 3 =,
40+
OPERATOR 4 >=,
41+
OPERATOR 5 >,
42+
FUNCTION 1 gin_enum_cmp(anyenum,anyenum),
43+
FUNCTION 2 gin_extract_value_anyenum(anyenum, internal),
44+
FUNCTION 3 gin_extract_query_anyenum(anyenum, internal, int2, internal, internal),
45+
FUNCTION 4 gin_btree_consistent(internal, int2, anyelement, int4, internal, internal),
46+
FUNCTION 5 gin_compare_prefix_anyenum(anyenum,anyenum,int2, internal),
47+
STORAGE anyenum;

contrib/btree_gin/btree_gin.c

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ typedef struct QueryInfo
2525
Datum (*typecmp) (FunctionCallInfo);
2626
} QueryInfo;
2727

28-
2928
/*** GIN support functions shared by all datatypes ***/
3029

3130
static Datum
@@ -112,13 +111,14 @@ gin_btree_compare_prefix(FunctionCallInfo fcinfo)
112111
int32 res,
113112
cmp;
114113

115-
cmp = DatumGetInt32(DirectFunctionCall2Coll(
116-
data->typecmp,
117-
PG_GET_COLLATION(),
118-
(data->strategy == BTLessStrategyNumber ||
119-
data->strategy == BTLessEqualStrategyNumber)
120-
? data->datum : a,
121-
b));
114+
cmp = DatumGetInt32(CallerFInfoFunctionCall2(
115+
data->typecmp,
116+
fcinfo->flinfo,
117+
PG_GET_COLLATION(),
118+
(data->strategy == BTLessStrategyNumber ||
119+
data->strategy == BTLessEqualStrategyNumber)
120+
? data->datum : a,
121+
b));
122122

123123
switch (data->strategy)
124124
{
@@ -426,3 +426,54 @@ leftmostvalue_numeric(void)
426426
}
427427

428428
GIN_SUPPORT(numeric, true, leftmostvalue_numeric, gin_numeric_cmp)
429+
430+
/*
431+
* Use a similar trick to that used for numeric for enums, since we don't
432+
* actually know the leftmost value of any enum without knowing the concrete
433+
* type, so we use a dummy leftmost value of InvalidOid.
434+
*
435+
* Note that we use CallerFInfoFunctionCall2 here so that enum_cmp
436+
* gets a valid fn_extra to work with. Unlike most other type comparison
437+
* routines it needs it, so we can't use DirectFunctionCall2.
438+
*/
439+
440+
441+
#define ENUM_IS_LEFTMOST(x) ((x) == InvalidOid)
442+
443+
PG_FUNCTION_INFO_V1(gin_enum_cmp);
444+
445+
Datum
446+
gin_enum_cmp(PG_FUNCTION_ARGS)
447+
{
448+
Oid a = PG_GETARG_OID(0);
449+
Oid b = PG_GETARG_OID(1);
450+
int res = 0;
451+
452+
if (ENUM_IS_LEFTMOST(a))
453+
{
454+
res = (ENUM_IS_LEFTMOST(b)) ? 0 : -1;
455+
}
456+
else if (ENUM_IS_LEFTMOST(b))
457+
{
458+
res = 1;
459+
}
460+
else
461+
{
462+
res = DatumGetInt32(CallerFInfoFunctionCall2(
463+
enum_cmp,
464+
fcinfo->flinfo,
465+
PG_GET_COLLATION(),
466+
ObjectIdGetDatum(a),
467+
ObjectIdGetDatum(b)));
468+
}
469+
470+
PG_RETURN_INT32(res);
471+
}
472+
473+
static Datum
474+
leftmostvalue_enum(void)
475+
{
476+
return ObjectIdGetDatum(InvalidOid);
477+
}
478+
479+
GIN_SUPPORT(anyenum, false, leftmostvalue_enum, gin_enum_cmp)

contrib/btree_gin/btree_gin.control

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# btree_gin extension
22
comment = 'support for indexing common datatypes in GIN'
3-
default_version = '1.1'
3+
default_version = '1.2'
44
module_pathname = '$libdir/btree_gin'
55
relocatable = true

contrib/btree_gin/expected/enum.out

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
set enable_seqscan=off;
2+
CREATE TYPE rainbow AS ENUM ('r','o','y','g','b','i','v');
3+
CREATE TABLE test_enum (
4+
i rainbow
5+
);
6+
INSERT INTO test_enum VALUES ('v'),('y'),('r'),('g'),('o'),('i'),('b');
7+
CREATE INDEX idx_enum ON test_enum USING gin (i);
8+
SELECT * FROM test_enum WHERE i<'g'::rainbow ORDER BY i;
9+
i
10+
---
11+
r
12+
o
13+
y
14+
(3 rows)
15+
16+
SELECT * FROM test_enum WHERE i<='g'::rainbow ORDER BY i;
17+
i
18+
---
19+
r
20+
o
21+
y
22+
g
23+
(4 rows)
24+
25+
SELECT * FROM test_enum WHERE i='g'::rainbow ORDER BY i;
26+
i
27+
---
28+
g
29+
(1 row)
30+
31+
SELECT * FROM test_enum WHERE i>='g'::rainbow ORDER BY i;
32+
i
33+
---
34+
g
35+
b
36+
i
37+
v
38+
(4 rows)
39+
40+
SELECT * FROM test_enum WHERE i>'g'::rainbow ORDER BY i;
41+
i
42+
---
43+
b
44+
i
45+
v
46+
(3 rows)
47+
48+
explain (costs off) SELECT * FROM test_enum WHERE i>='g'::rainbow ORDER BY i;
49+
QUERY PLAN
50+
-----------------------------------------------
51+
Sort
52+
Sort Key: i
53+
-> Bitmap Heap Scan on test_enum
54+
Recheck Cond: (i >= 'g'::rainbow)
55+
-> Bitmap Index Scan on idx_enum
56+
Index Cond: (i >= 'g'::rainbow)
57+
(6 rows)
58+
59+
-- make sure we handle the non-evenly-numbered oid case for enums
60+
create type e as enum ('0', '2', '3');
61+
alter type e add value '1' after '0';
62+
create table t as select (i % 4)::text::e from generate_series(0, 100000) as i;
63+
create index on t using gin (e);

contrib/btree_gin/sql/enum.sql

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
set enable_seqscan=off;
2+
3+
CREATE TYPE rainbow AS ENUM ('r','o','y','g','b','i','v');
4+
5+
CREATE TABLE test_enum (
6+
i rainbow
7+
);
8+
9+
INSERT INTO test_enum VALUES ('v'),('y'),('r'),('g'),('o'),('i'),('b');
10+
11+
CREATE INDEX idx_enum ON test_enum USING gin (i);
12+
13+
SELECT * FROM test_enum WHERE i<'g'::rainbow ORDER BY i;
14+
SELECT * FROM test_enum WHERE i<='g'::rainbow ORDER BY i;
15+
SELECT * FROM test_enum WHERE i='g'::rainbow ORDER BY i;
16+
SELECT * FROM test_enum WHERE i>='g'::rainbow ORDER BY i;
17+
SELECT * FROM test_enum WHERE i>'g'::rainbow ORDER BY i;
18+
19+
explain (costs off) SELECT * FROM test_enum WHERE i>='g'::rainbow ORDER BY i;
20+
21+
22+
-- make sure we handle the non-evenly-numbered oid case for enums
23+
create type e as enum ('0', '2', '3');
24+
alter type e add value '1' after '0';
25+
create table t as select (i % 4)::text::e from generate_series(0, 100000) as i;
26+
create index on t using gin (e);

0 commit comments

Comments
 (0)