From: Andrew Dunstan <andrew.dunstan@2ndquadrant.com>
To: Tom Lane <tgl@sss.pgh.pa.us>
Cc: PostgreSQL-development <pgsql-hackers@postgresql.org>
Subject: Re: btree_gin and btree_gist for enums
Date: Thu, 23 Feb 2017 19:20:32 -0500
Message-ID: <7ab7866f-bc40-91de-6da3-ab709a274e58@2ndQuadrant.com> (raw)
In-Reply-To: <8258.1487886101@sss.pgh.pa.us>
References: <56EA8A71.8060107@dunslane.net>
<56EACB8C.1040406@dunslane.net>
<CAE2gYzyB=vyquQ2hEWA9UwNb=zYAKFsNO5vBtbfkV2=PzoPZjg@mail.gmail.com>
<03f7d748-0f89-e8e1-094d-f04e1026b93d@dunslane.net>
<27220.1478360811@sss.pgh.pa.us>
<e60f50c4-899a-d48a-6cb4-4611acf2f73c@dunslane.net>
<31412.1478366009@sss.pgh.pa.us>
<60fb708c-8b3c-1337-934e-c1bfe2afc539@dunslane.net>
<db2b70a4-78d7-294a-a315-8e7f506c5978@2ndQuadrant.com>
<8258.1487886101@sss.pgh.pa.us>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
On 02/23/2017 04:41 PM, Tom Lane wrote:
> Andrew Dunstan <andrew.dunstan@2ndquadrant.com> writes:
>> I'm not entirely sure how I should replace those DirectFunctionCall2 calls.
> Basically what we want is for the called function to be able to use the
> fcinfo->flinfo->fn_extra and fcinfo->flinfo->fn_mcxt fields of the
> FmgrInfo struct that GIN has set up for the btree_gin support function.
>
> The fast but somewhat scary way to do it would just be to pass through
> the flinfo pointer as-is. Imagine that fmgr.c grows a set of functions
> like
>
> [...]
Here's a POC for btree_gin based on my original patch. I just made your
function static in btree_gin.c at least for now. I stayed with the
DirectFunctionCall2 use in the type-specific routines where calling
context wasn't needed (i.e. everything except enums). But it looks more
than ugly and highly invasive for btree_gist, and sadly that's my main
use case, exclusion constraints with enum fields.
cheers
andrew
--
Andrew Dunstan https://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackersAttachments:enum-btree-gin-2.patch (text/x-diff, 8.6K) downloaddiff --git a/contrib/btree_gin/Makefile b/contrib/btree_gin/Makefileindex 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.sqlnew file mode 100644index 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.cindex 030b610..4694275 100644--- a/contrib/btree_gin/btree_gin.c+++ b/contrib/btree_gin/btree_gin.c@@ -25,6 +25,35 @@ typedef struct QueryInfo
Datum (*typecmp) (FunctionCallInfo);
} QueryInfo;
+/*+ * Routine to provide context to a data type comparison call.+ * Needed for enum support.+ */++static Datum+CallerContextFunctionCall2(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;+}+
/*** GIN support functions shared by all datatypes ***/
@@ -112,13 +141,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(CallerContextFunctionCall2(+ data->typecmp,+ fcinfo->flinfo,+ PG_GET_COLLATION(),+ (data->strategy == BTLessStrategyNumber ||+ data->strategy == BTLessEqualStrategyNumber)+ ? data->datum : a,+ b));
switch (data->strategy)
{
@@ -416,3 +446,50 @@ 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.+ */+++#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(CallerContextFunctionCall2(+ 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.controlindex 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.outnew file mode 100644index 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/contrib/btree_gin/sql/enum.sql b/contrib/btree_gin/sql/enum.sqlnew file mode 100644index 0000000..6db2d76--- /dev/null+++ b/contrib/btree_gin/sql/enum.sql@@ -0,0 +1,26 @@+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;+SELECT * FROM test_enum WHERE i<='g'::rainbow ORDER BY i;+SELECT * FROM test_enum WHERE i='g'::rainbow ORDER BY i;+SELECT * FROM test_enum WHERE i>='g'::rainbow ORDER BY i;+SELECT * FROM test_enum WHERE i>'g'::rainbow ORDER BY i;++explain (costs off) SELECT * FROM test_enum WHERE i>='g'::rainbow ORDER BY i;+++-- 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.sgmlindex 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>
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: andrew.dunstan@2ndquadrant.com, tgl@sss.pgh.pa.us
Subject: Re: btree_gin and btree_gist for enums
In-Reply-To: <7ab7866f-bc40-91de-6da3-ab709a274e58@2ndQuadrant.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox