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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy