diff options
-rw-r--r-- | contrib/hstore/hstore.sql.in | 10 | ||||
-rw-r--r-- | contrib/hstore/hstore_gin.c | 6 | ||||
-rw-r--r-- | contrib/hstore/uninstall_hstore.sql | 6 | ||||
-rw-r--r-- | contrib/intarray/_int.sql.in | 12 | ||||
-rw-r--r-- | contrib/intarray/_int_gin.c | 6 | ||||
-rw-r--r-- | contrib/intarray/uninstall__int.sql | 6 | ||||
-rw-r--r-- | contrib/pg_trgm/pg_trgm.sql.in | 12 | ||||
-rw-r--r-- | contrib/pg_trgm/trgm_gin.c | 47 | ||||
-rw-r--r-- | contrib/pg_trgm/uninstall_pg_trgm.sql | 6 | ||||
-rw-r--r-- | contrib/tsearch2/tsearch2.sql.in | 7 | ||||
-rw-r--r-- | doc/src/sgml/gin.sgml | 43 | ||||
-rw-r--r-- | src/backend/access/gin/ginarrayproc.c | 6 | ||||
-rw-r--r-- | src/backend/access/gin/ginget.c | 52 | ||||
-rw-r--r-- | src/backend/access/gin/ginscan.c | 66 | ||||
-rw-r--r-- | src/backend/utils/adt/tsginidx.c | 55 | ||||
-rw-r--r-- | src/include/access/gin.h | 4 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 4 | ||||
-rw-r--r-- | src/include/catalog/pg_proc.h | 12 |
18 files changed, 211 insertions, 149 deletions
diff --git a/contrib/hstore/hstore.sql.in b/contrib/hstore/hstore.sql.in index 1b22ff63c56..3487a48459a 100644 --- a/contrib/hstore/hstore.sql.in +++ b/contrib/hstore/hstore.sql.in @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/contrib/hstore/hstore.sql.in,v 1.9 2008/04/14 17:05:32 tgl Exp $ */ +/* $PostgreSQL: pgsql/contrib/hstore/hstore.sql.in,v 1.10 2009/03/25 22:19:01 tgl Exp $ */ -- Adjust this setting to control where the objects get created. SET search_path = public; @@ -244,12 +244,12 @@ RETURNS internal AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE; -CREATE OR REPLACE FUNCTION gin_extract_hstore_query(internal, internal, int2) +CREATE OR REPLACE FUNCTION gin_extract_hstore_query(internal, internal, int2, internal, internal) RETURNS internal AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE; -CREATE OR REPLACE FUNCTION gin_consistent_hstore(internal, int2, internal, internal) +CREATE OR REPLACE FUNCTION gin_consistent_hstore(internal, int2, internal, int4, internal, internal) RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE; @@ -261,6 +261,6 @@ AS OPERATOR 9 ?(hstore,text), FUNCTION 1 bttextcmp(text,text), FUNCTION 2 gin_extract_hstore(internal, internal), - FUNCTION 3 gin_extract_hstore_query(internal, internal, int2), - FUNCTION 4 gin_consistent_hstore(internal, int2, internal, internal), + FUNCTION 3 gin_extract_hstore_query(internal, internal, int2, internal, internal), + FUNCTION 4 gin_consistent_hstore(internal, int2, internal, int4, internal, internal), STORAGE text; diff --git a/contrib/hstore/hstore_gin.c b/contrib/hstore/hstore_gin.c index d40b2e5bb8f..01d7258f8f9 100644 --- a/contrib/hstore/hstore_gin.c +++ b/contrib/hstore/hstore_gin.c @@ -1,5 +1,5 @@ /* - * $PostgreSQL: pgsql/contrib/hstore/hstore_gin.c,v 1.4 2008/05/12 00:00:42 alvherre Exp $ + * $PostgreSQL: pgsql/contrib/hstore/hstore_gin.c,v 1.5 2009/03/25 22:19:01 tgl Exp $ */ #include "postgres.h" @@ -122,7 +122,9 @@ gin_consistent_hstore(PG_FUNCTION_ARGS) bool *check = (bool *) PG_GETARG_POINTER(0); StrategyNumber strategy = PG_GETARG_UINT16(1); HStore *query = PG_GETARG_HS(2); - bool *recheck = (bool *) PG_GETARG_POINTER(3); + /* int32 nkeys = PG_GETARG_INT32(3); */ + /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */ + bool *recheck = (bool *) PG_GETARG_POINTER(5); bool res = true; if (strategy == HStoreContainsStrategyNumber) diff --git a/contrib/hstore/uninstall_hstore.sql b/contrib/hstore/uninstall_hstore.sql index 84d567fcadf..17782d5c058 100644 --- a/contrib/hstore/uninstall_hstore.sql +++ b/contrib/hstore/uninstall_hstore.sql @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/contrib/hstore/uninstall_hstore.sql,v 1.7 2008/04/14 17:05:32 tgl Exp $ */ +/* $PostgreSQL: pgsql/contrib/hstore/uninstall_hstore.sql,v 1.8 2009/03/25 22:19:01 tgl Exp $ */ -- Adjust this setting to control where the objects get dropped. SET search_path = public; @@ -38,9 +38,9 @@ DROP FUNCTION ghstore_picksplit(internal, internal); DROP FUNCTION ghstore_union(internal, internal); DROP FUNCTION ghstore_same(internal, internal, internal); DROP FUNCTION ghstore_consistent(internal,internal,int,oid,internal); -DROP FUNCTION gin_consistent_hstore(internal, int2, internal, internal); +DROP FUNCTION gin_consistent_hstore(internal, int2, internal, int4, internal, internal); DROP FUNCTION gin_extract_hstore(internal, internal); -DROP FUNCTION gin_extract_hstore_query(internal, internal, smallint); +DROP FUNCTION gin_extract_hstore_query(internal, internal, smallint, internal, internal); DROP TYPE hstore CASCADE; DROP TYPE ghstore CASCADE; diff --git a/contrib/intarray/_int.sql.in b/contrib/intarray/_int.sql.in index c681626dc9b..9f91a65eec7 100644 --- a/contrib/intarray/_int.sql.in +++ b/contrib/intarray/_int.sql.in @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/contrib/intarray/_int.sql.in,v 1.28 2008/04/14 17:05:32 tgl Exp $ */ +/* $PostgreSQL: pgsql/contrib/intarray/_int.sql.in,v 1.29 2009/03/25 22:19:01 tgl Exp $ */ -- Adjust this setting to control where the objects get created. SET search_path = public; @@ -458,13 +458,13 @@ AS --GIN -CREATE OR REPLACE FUNCTION ginint4_queryextract(internal, internal, int2) +CREATE OR REPLACE FUNCTION ginint4_queryextract(internal, internal, int2, internal, internal) RETURNS internal AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE; -CREATE OR REPLACE FUNCTION ginint4_consistent(internal, int2, internal, internal) -RETURNS internal +CREATE OR REPLACE FUNCTION ginint4_consistent(internal, int2, internal, int4, internal, internal) +RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE; @@ -480,6 +480,6 @@ AS OPERATOR 20 @@ (_int4, query_int), FUNCTION 1 btint4cmp (int4, int4), FUNCTION 2 ginarrayextract (anyarray, internal), - FUNCTION 3 ginint4_queryextract (internal, internal, int2), - FUNCTION 4 ginint4_consistent (internal, int2, internal, internal), + FUNCTION 3 ginint4_queryextract (internal, internal, int2, internal, internal), + FUNCTION 4 ginint4_consistent (internal, int2, internal, int4, internal, internal), STORAGE int4; diff --git a/contrib/intarray/_int_gin.c b/contrib/intarray/_int_gin.c index 0edb686df2e..598cdeca570 100644 --- a/contrib/intarray/_int_gin.c +++ b/contrib/intarray/_int_gin.c @@ -1,5 +1,5 @@ /* - * $PostgreSQL: pgsql/contrib/intarray/_int_gin.c,v 1.8 2008/05/17 01:28:19 adunstan Exp $ + * $PostgreSQL: pgsql/contrib/intarray/_int_gin.c,v 1.9 2009/03/25 22:19:01 tgl Exp $ */ #include "postgres.h" @@ -90,7 +90,9 @@ ginint4_consistent(PG_FUNCTION_ARGS) { bool *check = (bool *) PG_GETARG_POINTER(0); StrategyNumber strategy = PG_GETARG_UINT16(1); - bool *recheck = (bool *) PG_GETARG_POINTER(3); + /* int32 nkeys = PG_GETARG_INT32(3); */ + /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */ + bool *recheck = (bool *) PG_GETARG_POINTER(5); bool res = FALSE; /* diff --git a/contrib/intarray/uninstall__int.sql b/contrib/intarray/uninstall__int.sql index 59ef2afc0f0..5346bddc752 100644 --- a/contrib/intarray/uninstall__int.sql +++ b/contrib/intarray/uninstall__int.sql @@ -1,13 +1,13 @@ -/* $PostgreSQL: pgsql/contrib/intarray/uninstall__int.sql,v 1.9 2008/04/14 17:05:32 tgl Exp $ */ +/* $PostgreSQL: pgsql/contrib/intarray/uninstall__int.sql,v 1.10 2009/03/25 22:19:01 tgl Exp $ */ -- Adjust this setting to control where the objects get created. SET search_path = public; DROP OPERATOR CLASS gin__int_ops USING gin; -DROP FUNCTION ginint4_queryextract(internal, internal, int2); +DROP FUNCTION ginint4_queryextract(internal, internal, int2, internal, internal); -DROP FUNCTION ginint4_consistent(internal, int2, internal, internal); +DROP FUNCTION ginint4_consistent(internal, int2, internal, int4, internal, internal); DROP OPERATOR CLASS gist__intbig_ops USING gist; diff --git a/contrib/pg_trgm/pg_trgm.sql.in b/contrib/pg_trgm/pg_trgm.sql.in index d65a9cf6b2e..f59ea1ba854 100644 --- a/contrib/pg_trgm/pg_trgm.sql.in +++ b/contrib/pg_trgm/pg_trgm.sql.in @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/contrib/pg_trgm/pg_trgm.sql.in,v 1.8 2008/04/14 17:05:32 tgl Exp $ */ +/* $PostgreSQL: pgsql/contrib/pg_trgm/pg_trgm.sql.in,v 1.9 2009/03/25 22:19:01 tgl Exp $ */ -- Adjust this setting to control where the objects get created. SET search_path = public; @@ -110,13 +110,13 @@ RETURNS internal AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE; -CREATE OR REPLACE FUNCTION gin_extract_trgm(text, internal, internal) +CREATE OR REPLACE FUNCTION gin_extract_trgm(text, internal, int2, internal, internal) RETURNS internal AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE; -CREATE OR REPLACE FUNCTION gin_trgm_consistent(internal, int2, text, internal) -RETURNS internal +CREATE OR REPLACE FUNCTION gin_trgm_consistent(internal, int2, text, int4, internal, internal) +RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE; @@ -127,6 +127,6 @@ AS OPERATOR 1 % (text, text), FUNCTION 1 btint4cmp (int4, int4), FUNCTION 2 gin_extract_trgm (text, internal), - FUNCTION 3 gin_extract_trgm (text, internal, internal), - FUNCTION 4 gin_trgm_consistent (internal, int2, text, internal), + FUNCTION 3 gin_extract_trgm (text, internal, int2, internal, internal), + FUNCTION 4 gin_trgm_consistent (internal, int2, text, int4, internal, internal), STORAGE int4; diff --git a/contrib/pg_trgm/trgm_gin.c b/contrib/pg_trgm/trgm_gin.c index 7a64764fb88..1a53d1d3583 100644 --- a/contrib/pg_trgm/trgm_gin.c +++ b/contrib/pg_trgm/trgm_gin.c @@ -1,5 +1,5 @@ /* - * $PostgreSQL: pgsql/contrib/pg_trgm/trgm_gin.c,v 1.6 2008/11/12 13:43:54 teodor Exp $ + * $PostgreSQL: pgsql/contrib/pg_trgm/trgm_gin.c,v 1.7 2009/03/25 22:19:01 tgl Exp $ */ #include "trgm.h" @@ -47,53 +47,40 @@ gin_extract_trgm(PG_FUNCTION_ARGS) ptr++; } + if (PG_NARGS() > 4) + { + /* + * Function called from query extracting + */ + Pointer **extra_data = (Pointer **) PG_GETARG_POINTER(4); + + *extra_data = (Pointer*) palloc0(sizeof(Pointer)*(*nentries)); + + *(int32*)(*extra_data) = trglen; + } } PG_RETURN_POINTER(entries); } -/* - * Per call strage for consistent functions to - * cache computed value from query - */ -typedef struct PerCallConsistentStorage { - int trglen; - text data[1]; /* query */ -} PerCallConsistentStorage; -#define PCCSHDR_SZ offsetof(PerCallConsistentStorage, data) - Datum gin_trgm_consistent(PG_FUNCTION_ARGS) { bool *check = (bool *) PG_GETARG_POINTER(0); /* StrategyNumber strategy = PG_GETARG_UINT16(1); */ - text *query = PG_GETARG_TEXT_P(2); - bool *recheck = (bool *) PG_GETARG_POINTER(3); + /* text *query = PG_GETARG_TEXT_P(2); */ + /* int32 nkeys = PG_GETARG_INT32(3); */ + Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); + bool *recheck = (bool *) PG_GETARG_POINTER(5); bool res = FALSE; int4 i, trglen, ntrue = 0; - PerCallConsistentStorage *pccs = (PerCallConsistentStorage*) fcinfo->flinfo->fn_extra; /* All cases served by this function are inexact */ *recheck = true; - if ( pccs == NULL || VARSIZE(pccs->data) != VARSIZE(query) || memcmp( pccs->data, query, VARSIZE(query) ) !=0 ) - { - TRGM *trg = generate_trgm(VARDATA(query), VARSIZE(query) - VARHDRSZ); - - if ( pccs ) - pfree(pccs); - - fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - VARSIZE(query) + PCCSHDR_SZ); - pccs = (PerCallConsistentStorage*) fcinfo->flinfo->fn_extra; - - pccs->trglen = ARRNELEM(trg); - memcpy( pccs->data, query, VARSIZE(query) ); - } - - trglen = pccs->trglen; + trglen = *(int32*)extra_data; for (i = 0; i < trglen; i++) if (check[i]) diff --git a/contrib/pg_trgm/uninstall_pg_trgm.sql b/contrib/pg_trgm/uninstall_pg_trgm.sql index 094dfcddc73..42c1d741f93 100644 --- a/contrib/pg_trgm/uninstall_pg_trgm.sql +++ b/contrib/pg_trgm/uninstall_pg_trgm.sql @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/contrib/pg_trgm/uninstall_pg_trgm.sql,v 1.6 2008/04/14 17:05:32 tgl Exp $ */ +/* $PostgreSQL: pgsql/contrib/pg_trgm/uninstall_pg_trgm.sql,v 1.7 2009/03/25 22:19:01 tgl Exp $ */ -- Adjust this setting to control where the objects get dropped. SET search_path = public; @@ -25,9 +25,9 @@ DROP OPERATOR CLASS gin_trgm_ops USING gin; DROP FUNCTION gin_extract_trgm(text, internal); -DROP FUNCTION gin_extract_trgm(text, internal, internal); +DROP FUNCTION gin_extract_trgm(text, internal, int2, internal, internal); -DROP FUNCTION gin_trgm_consistent(internal, int2, text, internal); +DROP FUNCTION gin_trgm_consistent(internal, int2, text, int4, internal, internal); DROP OPERATOR % (text, text); diff --git a/contrib/tsearch2/tsearch2.sql.in b/contrib/tsearch2/tsearch2.sql.in index 4bf0d9ace65..fc190375785 100644 --- a/contrib/tsearch2/tsearch2.sql.in +++ b/contrib/tsearch2/tsearch2.sql.in @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/contrib/tsearch2/tsearch2.sql.in,v 1.6 2008/05/16 17:26:07 tgl Exp $ */ +/* $PostgreSQL: pgsql/contrib/tsearch2/tsearch2.sql.in,v 1.7 2009/03/25 22:19:01 tgl Exp $ */ -- Adjust this setting to control where the objects get created. SET search_path = public; @@ -552,8 +552,9 @@ AS OPERATOR 2 @@@ (tsvector, tsquery), FUNCTION 1 bttextcmp(text, text), FUNCTION 2 gin_extract_tsvector(tsvector,internal), - FUNCTION 3 gin_extract_tsquery(tsquery,internal,smallint,internal), - FUNCTION 4 gin_tsquery_consistent(internal,smallint,tsquery,internal), + FUNCTION 3 gin_extract_tsquery(tsquery,internal,smallint,internal,internal), + FUNCTION 4 gin_tsquery_consistent(internal,smallint,tsquery,int,internal,internal), + FUNCTION 5 gin_cmp_prefix(text,text,smallint,internal), STORAGE text; CREATE OPERATOR CLASS tsvector_ops diff --git a/doc/src/sgml/gin.sgml b/doc/src/sgml/gin.sgml index 9cdc4ed5281..4c0438f9104 100644 --- a/doc/src/sgml/gin.sgml +++ b/doc/src/sgml/gin.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/gin.sgml,v 2.17 2009/03/24 20:17:07 tgl Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/gin.sgml,v 2.18 2009/03/25 22:19:01 tgl Exp $ --> <chapter id="GIN"> <title>GIN Indexes</title> @@ -88,7 +88,7 @@ <varlistentry> <term>Datum *extractQuery(Datum query, int32 *nkeys, - StrategyNumber n, bool **pmatch)</term> + StrategyNumber n, bool **pmatch, Pointer **extra_data)</term> <listitem> <para> Returns an array of keys given a value to be queried; that is, @@ -104,7 +104,7 @@ should store 0 or -1 into <literal>*nkeys</>, depending on the semantics of the operator. 0 means that every value matches the <literal>query</> and a sequential scan should be - produced. -1 means nothing can match the <literal>query</>. + performed. -1 means nothing can match the <literal>query</>. <literal>pmatch</> is an output argument for use when partial match is supported. To use it, <function>extractQuery</> must allocate an array of <literal>*nkeys</> booleans and store its address at @@ -114,25 +114,40 @@ is not required. The variable is initialized to NULL before call, so this argument can simply be ignored by operator classes that do not support partial match. + <literal>extra_data</> is an output argument that allows + <function>extractQuery</> to pass additional data to the + <function>consistent</> and <function>comparePartial</> methods. + To use it, <function>extractQuery</> must allocate + an array of <literal>*nkeys</> Pointers and store its address at + <literal>*extra_data</>, then store whatever it wants to into the + individual pointers. The variable is initialized to NULL before + call, so this argument can simply be ignored by operator classes that + do not require extra data. If <literal>*extra_data</> is set, the + whole array is passed to the <function>consistent</> method, and + the appropriate element to the <function>comparePartial</> method. </para> </listitem> </varlistentry> <varlistentry> - <term>bool consistent(bool check[], StrategyNumber n, Datum query, bool *recheck)</term> + <term>bool consistent(bool check[], StrategyNumber n, Datum query, + int32 nkeys, Pointer extra_data[], bool *recheck)</term> <listitem> <para> Returns TRUE if the indexed value satisfies the query operator with strategy number <literal>n</> (or might satisfy, if the recheck - indication is returned). The <literal>check</> array has - the same length as the number of keys previously returned by - <function>extractQuery</> for this query. Each element of the + indication is returned). The <literal>check</> array has length + <literal>nkeys</>, which is the same as the number of keys previously + returned by <function>extractQuery</> for this <literal>query</> datum. + Each element of the <literal>check</> array is TRUE if the indexed value contains the corresponding query key, ie, if (check[i] == TRUE) the i-th key of the <function>extractQuery</> result array is present in the indexed value. The original <literal>query</> datum (not the extracted key array!) is passed in case the <function>consistent</> method needs to consult it. + <literal>extra_data</> is the extra-data array returned by + <function>extractQuery</>, or NULL if none. On success, <literal>*recheck</> should be set to TRUE if the heap tuple needs to be rechecked against the query operator, or FALSE if the index test is exact. @@ -150,7 +165,8 @@ <variablelist> <varlistentry> - <term>int comparePartial(Datum partial_key, Datum key, StrategyNumber n)</term> + <term>int comparePartial(Datum partial_key, Datum key, StrategyNumber n, + Pointer extra_data)</term> <listitem> <para> Compare a partial-match query to an index key. Returns an integer @@ -160,7 +176,9 @@ indicates that the index scan should stop because no more matches are possible. The strategy number <literal>n</> of the operator that generated the partial match query is provided, in case its - semantics are needed to determine when to end the scan. + semantics are needed to determine when to end the scan. Also, + <literal>extra_data</> is the corresponding element of the extra-data + array made by <function>extractQuery</>, or NULL if none. </para> </listitem> </varlistentry> @@ -384,6 +402,13 @@ <variablelist> <varlistentry> + <term>btree-gin</term> + <listitem> + <para>B-Tree equivalent functionality for several data types</para> + </listitem> + </varlistentry> + + <varlistentry> <term>hstore</term> <listitem> <para>Module for storing (key, value) pairs</para> diff --git a/src/backend/access/gin/ginarrayproc.c b/src/backend/access/gin/ginarrayproc.c index 3b2e43318f8..717caaad8b5 100644 --- a/src/backend/access/gin/ginarrayproc.c +++ b/src/backend/access/gin/ginarrayproc.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/gin/ginarrayproc.c,v 1.14 2009/01/01 17:23:34 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/access/gin/ginarrayproc.c,v 1.15 2009/03/25 22:19:01 tgl Exp $ *------------------------------------------------------------------------- */ #include "postgres.h" @@ -95,7 +95,9 @@ ginarrayconsistent(PG_FUNCTION_ARGS) bool *check = (bool *) PG_GETARG_POINTER(0); StrategyNumber strategy = PG_GETARG_UINT16(1); ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); - bool *recheck = (bool *) PG_GETARG_POINTER(3); + /* int32 nkeys = PG_GETARG_INT32(3); */ + /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */ + bool *recheck = (bool *) PG_GETARG_POINTER(5); bool res; int i, nentries; diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c index 7f9f1236605..55ed9f335ae 100644 --- a/src/backend/access/gin/ginget.c +++ b/src/backend/access/gin/ginget.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.23 2009/03/24 20:17:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.24 2009/03/25 22:19:01 tgl Exp $ *------------------------------------------------------------------------- */ @@ -178,10 +178,11 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry * case cmp < 0 => not match and continue scan *---------- */ - cmp = DatumGetInt32(FunctionCall3(&btree->ginstate->comparePartialFn[scanEntry->attnum-1], + cmp = DatumGetInt32(FunctionCall4(&btree->ginstate->comparePartialFn[scanEntry->attnum-1], scanEntry->entry, idatum, - UInt16GetDatum(scanEntry->strategy))); + UInt16GetDatum(scanEntry->strategy), + PointerGetDatum(scanEntry->extra_data))); if ( cmp > 0 ) return true; @@ -695,16 +696,18 @@ keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx, /* * If one of the entry's scans returns lossy result, return it without - * checking - we can't suggest anything helpful to consistentFn. + * further checking - we can't call consistentFn for lack of data. */ if (ItemPointerIsLossyPage(&key->curItem)) return FALSE; oldCtx = MemoryContextSwitchTo(tempCtx); - res = DatumGetBool(FunctionCall4(&ginstate->consistentFn[key->attnum-1], + res = DatumGetBool(FunctionCall6(&ginstate->consistentFn[key->attnum-1], PointerGetDatum(key->entryRes), UInt16GetDatum(key->strategy), key->query, + UInt32GetDatum(key->nentries), + PointerGetDatum(key->extra_data), PointerGetDatum(keyrecheck))); MemoryContextSwitchTo(oldCtx); MemoryContextReset(tempCtx); @@ -796,10 +799,11 @@ matchPartialInPendingList(GinState *ginstate, Page page, OffsetNumber off, OffsetNumber maxoff, Datum value, OffsetNumber attrnum, Datum *datum, bool *datumExtracted, - StrategyNumber strategy) + StrategyNumber strategy, + Pointer extra_data) { IndexTuple itup; - int res; + int32 cmp; while ( off < maxoff ) { @@ -813,13 +817,14 @@ matchPartialInPendingList(GinState *ginstate, Page page, datumExtracted[ off-1 ] = true; } - res = DatumGetInt32(FunctionCall3(&ginstate->comparePartialFn[attrnum], - value, - datum[ off-1 ], - UInt16GetDatum(strategy))); - if ( res == 0 ) + cmp = DatumGetInt32(FunctionCall4(&ginstate->comparePartialFn[attrnum], + value, + datum[off-1], + UInt16GetDatum(strategy), + PointerGetDatum(extra_data))); + if (cmp == 0) return true; - else if (res>0) + else if (cmp > 0) return false; } @@ -912,7 +917,8 @@ collectDatumForItem(IndexScanDesc scan, pendingPosition *pos) entry->attnum, datum, datumExtracted, - entry->strategy); + entry->strategy, + entry->extra_data); else key->entryRes[j] = true; break; @@ -933,7 +939,8 @@ collectDatumForItem(IndexScanDesc scan, pendingPosition *pos) entry->attnum, datum, datumExtracted, - entry->strategy); + entry->strategy, + entry->extra_data); hasMatch |= key->entryRes[j]; } @@ -1015,19 +1022,22 @@ scanPendingInsert(IndexScanDesc scan, TIDBitmap *tbm, int64 *ntids) recheck = false; match = true; - for (i = 0; match && i < so->nkeys; i++) + for (i = 0; i < so->nkeys; i++) { GinScanKey key = so->keys + i; keyrecheck = true; - if ( DatumGetBool(FunctionCall4(&so->ginstate.consistentFn[ key->attnum-1 ], - PointerGetDatum(key->entryRes), - UInt16GetDatum(key->strategy), - key->query, - PointerGetDatum(&keyrecheck))) == false ) + if (!DatumGetBool(FunctionCall6(&so->ginstate.consistentFn[key->attnum-1], + PointerGetDatum(key->entryRes), + UInt16GetDatum(key->strategy), + key->query, + UInt32GetDatum(key->nentries), + PointerGetDatum(key->extra_data), + PointerGetDatum(&keyrecheck)))) { match = false; + break; } recheck |= keyrecheck; diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c index ba377419222..486adb6d7e8 100644 --- a/src/backend/access/gin/ginscan.c +++ b/src/backend/access/gin/ginscan.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/gin/ginscan.c,v 1.21 2009/01/10 21:08:36 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/gin/ginscan.c,v 1.22 2009/03/25 22:19:01 tgl Exp $ *------------------------------------------------------------------------- */ @@ -38,7 +38,7 @@ ginbeginscan(PG_FUNCTION_ARGS) static void fillScanKey(GinState *ginstate, GinScanKey key, OffsetNumber attnum, Datum query, Datum *entryValues, bool *partial_matches, uint32 nEntryValues, - StrategyNumber strategy) + StrategyNumber strategy, Pointer *extra_data) { uint32 i, j; @@ -48,6 +48,7 @@ fillScanKey(GinState *ginstate, GinScanKey key, OffsetNumber attnum, Datum query key->scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData) * nEntryValues); key->strategy = strategy; key->attnum = attnum; + key->extra_data = extra_data; key->query = query; key->firstCall = TRUE; ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber); @@ -57,6 +58,7 @@ fillScanKey(GinState *ginstate, GinScanKey key, OffsetNumber attnum, Datum query key->scanEntry[i].pval = key->entryRes + i; key->scanEntry[i].entry = entryValues[i]; key->scanEntry[i].attnum = attnum; + key->scanEntry[i].extra_data = (extra_data) ? extra_data[i] : NULL; ItemPointerSet(&(key->scanEntry[i].curItem), InvalidBlockNumber, InvalidOffsetNumber); key->scanEntry[i].offset = InvalidOffsetNumber; key->scanEntry[i].buffer = InvalidBuffer; @@ -156,60 +158,72 @@ newScanKey(IndexScanDesc scan) int i; uint32 nkeys = 0; - so->keys = (GinScanKey) palloc(scan->numberOfKeys * sizeof(GinScanKeyData)); - if (scan->numberOfKeys < 1) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("GIN indexes do not support whole-index scans"))); + so->keys = (GinScanKey) palloc(scan->numberOfKeys * sizeof(GinScanKeyData)); + so->isVoidRes = false; for (i = 0; i < scan->numberOfKeys; i++) { + ScanKey skey = &scankey[i]; Datum *entryValues; - int32 nEntryValues; + int32 nEntryValues = 0; bool *partial_matches = NULL; + Pointer *extra_data = NULL; /* XXX can't we treat nulls by just setting isVoidRes? */ /* This would amount to assuming that all GIN operators are strict */ - if (scankey[i].sk_flags & SK_ISNULL) - elog(ERROR, "GIN doesn't support NULL as scan key"); - - entryValues = (Datum *) DatumGetPointer(FunctionCall4( - &so->ginstate.extractQueryFn[scankey[i].sk_attno - 1], - scankey[i].sk_argument, - PointerGetDatum(&nEntryValues), - UInt16GetDatum(scankey[i].sk_strategy), - PointerGetDatum(&partial_matches))); + if (skey->sk_flags & SK_ISNULL) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("GIN indexes do not support NULL scan keys"))); + + entryValues = (Datum *) + DatumGetPointer(FunctionCall5(&so->ginstate.extractQueryFn[skey->sk_attno - 1], + skey->sk_argument, + PointerGetDatum(&nEntryValues), + UInt16GetDatum(skey->sk_strategy), + PointerGetDatum(&partial_matches), + PointerGetDatum(&extra_data))); + if (nEntryValues < 0) { /* - * extractQueryFn signals that nothing will be found, so we can - * just set isVoidRes flag... + * extractQueryFn signals that nothing can match, so we can + * just set isVoidRes flag. No need to examine any more keys. */ so->isVoidRes = true; break; } - /* - * extractQueryFn signals that everything matches - */ if (entryValues == NULL || nEntryValues == 0) - /* full scan... */ + { + /* + * extractQueryFn signals that everything matches. This would + * require a full scan, which we can't do, but perhaps there + * is another scankey that provides a restriction to use. So + * we keep going and check only at the end. + */ continue; + } - fillScanKey(&so->ginstate, &(so->keys[nkeys]), scankey[i].sk_attno, scankey[i].sk_argument, - entryValues, partial_matches, nEntryValues, scankey[i].sk_strategy); + fillScanKey(&so->ginstate, &(so->keys[nkeys]), + skey->sk_attno, skey->sk_argument, + entryValues, partial_matches, nEntryValues, + skey->sk_strategy, extra_data); nkeys++; } - so->nkeys = nkeys; - - if (so->nkeys == 0 && !so->isVoidRes) + if (nkeys == 0 && !so->isVoidRes) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("GIN index does not support search with void query"))); + errmsg("GIN indexes do not support whole-index scans"))); + + so->nkeys = nkeys; pgstat_count_index_scan(scan->indexRelation); } diff --git a/src/backend/utils/adt/tsginidx.c b/src/backend/utils/adt/tsginidx.c index b5b28f13afd..262a604ded1 100644 --- a/src/backend/utils/adt/tsginidx.c +++ b/src/backend/utils/adt/tsginidx.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/tsginidx.c,v 1.14 2009/01/01 17:23:50 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/tsginidx.c,v 1.15 2009/03/25 22:19:01 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -43,8 +43,9 @@ gin_cmp_prefix(PG_FUNCTION_ARGS) text *b = PG_GETARG_TEXT_PP(1); #ifdef NOT_USED StrategyNumber strategy = PG_GETARG_UINT16(2); + Pointer extra_data = PG_GETARG_POINTER(3); #endif - int cmp; + int cmp; cmp = tsCompareString( VARDATA_ANY(a), VARSIZE_ANY_EXHDR(a), @@ -96,6 +97,7 @@ gin_extract_tsquery(PG_FUNCTION_ARGS) int32 *nentries = (int32 *) PG_GETARG_POINTER(1); /* StrategyNumber strategy = PG_GETARG_UINT16(2); */ bool **ptr_partialmatch = (bool**) PG_GETARG_POINTER(3); + Pointer **extra_data = (Pointer **) PG_GETARG_POINTER(4); Datum *entries = NULL; bool *partialmatch; @@ -108,6 +110,7 @@ gin_extract_tsquery(PG_FUNCTION_ARGS) len; QueryItem *item; bool use_fullscan=false; + int *map_item_operand; item = clean_NOT(GETQUERY(query), &len); if (!item) @@ -125,6 +128,15 @@ gin_extract_tsquery(PG_FUNCTION_ARGS) entries = (Datum *) palloc(sizeof(Datum) * (*nentries)); partialmatch = *ptr_partialmatch = (bool*) palloc(sizeof(bool) * (*nentries)); + /* + * Make map to convert item's number to corresponding + * operand's (the same, entry's) number. Entry's number + * is used in check array in consistent method. We use + * the same map for each entry. + */ + *extra_data = (Pointer*) palloc0(sizeof(Pointer)*(*nentries)); + map_item_operand = palloc0(sizeof(int) * (query->size + 1)); + for (i = 0; i < query->size; i++) if (item[i].type == QI_VAL) { @@ -133,12 +145,18 @@ gin_extract_tsquery(PG_FUNCTION_ARGS) txt = cstring_to_text_with_len(GETOPERAND(query) + val->distance, val->length); + (*extra_data)[j] = (Pointer)map_item_operand; + map_item_operand[i] = j; partialmatch[j] = val->prefix; entries[j++] = PointerGetDatum(txt); } if ( use_fullscan ) + { + (*extra_data)[j] = (Pointer)map_item_operand; + map_item_operand[i] = j; entries[j++] = PointerGetDatum(cstring_to_text_with_len("", 0)); + } } else *nentries = -1; /* nothing can be found */ @@ -150,8 +168,9 @@ gin_extract_tsquery(PG_FUNCTION_ARGS) typedef struct { - QueryItem *frst; - bool *mapped_check; + QueryItem *first_item; + bool *check; + int *map_item_operand; bool *need_recheck; } GinChkVal; @@ -159,12 +178,17 @@ static bool checkcondition_gin(void *checkval, QueryOperand *val) { GinChkVal *gcv = (GinChkVal *) checkval; + int j; /* if any val requiring a weight is used, set recheck flag */ if (val->weight != 0) *(gcv->need_recheck) = true; - return gcv->mapped_check[((QueryItem *) val) - gcv->frst]; + /* convert item's number to corresponding entry's (operand's) number */ + j = gcv->map_item_operand[ ((QueryItem *) val) - gcv->first_item ]; + + /* return presence of current entry in indexed value */ + return gcv->check[j]; } Datum @@ -173,7 +197,9 @@ gin_tsquery_consistent(PG_FUNCTION_ARGS) bool *check = (bool *) PG_GETARG_POINTER(0); /* StrategyNumber strategy = PG_GETARG_UINT16(1); */ TSQuery query = PG_GETARG_TSQUERY(2); - bool *recheck = (bool *) PG_GETARG_POINTER(3); + /* int32 nkeys = PG_GETARG_INT32(3); */ + Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); + bool *recheck = (bool *) PG_GETARG_POINTER(5); bool res = FALSE; /* The query requires recheck only if it involves weights */ @@ -181,27 +207,18 @@ gin_tsquery_consistent(PG_FUNCTION_ARGS) if (query->size > 0) { - int i, - j = 0; QueryItem *item; GinChkVal gcv; /* * check-parameter array has one entry for each value (operand) in the - * query. We expand that array into mapped_check, so that there's one - * entry in mapped_check for every node in the query, including - * operators, to allow quick lookups in checkcondition_gin. Only the - * entries corresponding operands are actually used. + * query. */ - - gcv.frst = item = GETQUERY(query); - gcv.mapped_check = (bool *) palloc(sizeof(bool) * query->size); + gcv.first_item = item = GETQUERY(query); + gcv.check = check; + gcv.map_item_operand = (int*)(extra_data[0]); gcv.need_recheck = recheck; - for (i = 0; i < query->size; i++) - if (item[i].type == QI_VAL) - gcv.mapped_check[i] = check[j++]; - res = TS_execute( GETQUERY(query), &gcv, diff --git a/src/include/access/gin.h b/src/include/access/gin.h index c591c53638c..4a4abc1cd21 100644 --- a/src/include/access/gin.h +++ b/src/include/access/gin.h @@ -4,7 +4,7 @@ * * Copyright (c) 2006-2009, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/include/access/gin.h,v 1.30 2009/03/24 22:06:03 tgl Exp $ + * $PostgreSQL: pgsql/src/include/access/gin.h,v 1.31 2009/03/25 22:19:01 tgl Exp $ *-------------------------------------------------------------------------- */ #ifndef GIN_H @@ -481,6 +481,7 @@ typedef struct GinScanEntryData /* entry, got from extractQueryFn */ Datum entry; OffsetNumber attnum; + Pointer extra_data; /* Current page in posting tree */ Buffer buffer; @@ -515,6 +516,7 @@ typedef struct GinScanKeyData /* array of scans per entry */ GinScanEntry scanEntry; + Pointer *extra_data; /* for calling consistentFn(GinScanKey->entryRes, strategy, query) */ StrategyNumber strategy; diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 3d4fdc33bd3..e012b1046f2 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.525 2009/03/24 20:17:15 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.526 2009/03/25 22:19:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200903241 +#define CATALOG_VERSION_NO 200903251 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 2f0dbeb2656..475a3339a60 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.538 2009/03/24 20:17:15 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.539 2009/03/25 22:19:02 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -4212,9 +4212,9 @@ DESCR("gin(internal)"); /* GIN array support */ DATA(insert OID = 2743 ( ginarrayextract PGNSP PGUID 12 1 0 0 f f f t f i 2 0 2281 "2277 2281" _null_ _null_ _null_ _null_ ginarrayextract _null_ _null_ _null_ )); DESCR("GIN array support"); -DATA(insert OID = 2774 ( ginqueryarrayextract PGNSP PGUID 12 1 0 0 f f f t f i 4 0 2281 "2277 2281 21 2281" _null_ _null_ _null_ _null_ ginqueryarrayextract _null_ _null_ _null_ )); +DATA(insert OID = 2774 ( ginqueryarrayextract PGNSP PGUID 12 1 0 0 f f f t f i 5 0 2281 "2277 2281 21 2281 2281" _null_ _null_ _null_ _null_ ginqueryarrayextract _null_ _null_ _null_ )); DESCR("GIN array support"); -DATA(insert OID = 2744 ( ginarrayconsistent PGNSP PGUID 12 1 0 0 f f f t f i 4 0 16 "2281 21 2281 2281" _null_ _null_ _null_ _null_ ginarrayconsistent _null_ _null_ _null_ )); +DATA(insert OID = 2744 ( ginarrayconsistent PGNSP PGUID 12 1 0 0 f f f t f i 6 0 16 "2281 21 2277 23 2281 2281" _null_ _null_ _null_ _null_ ginarrayconsistent _null_ _null_ _null_ )); DESCR("GIN array support"); /* overlap/contains/contained */ @@ -4453,13 +4453,13 @@ DESCR("GiST tsvector support"); DATA(insert OID = 3656 ( gin_extract_tsvector PGNSP PGUID 12 1 0 0 f f f t f i 2 0 2281 "3614 2281" _null_ _null_ _null_ _null_ gin_extract_tsvector _null_ _null_ _null_ )); DESCR("GIN tsvector support"); -DATA(insert OID = 3657 ( gin_extract_tsquery PGNSP PGUID 12 1 0 0 f f f t f i 4 0 2281 "3615 2281 21 2281" _null_ _null_ _null_ _null_ gin_extract_tsquery _null_ _null_ _null_ )); +DATA(insert OID = 3657 ( gin_extract_tsquery PGNSP PGUID 12 1 0 0 f f f t f i 5 0 2281 "3615 2281 21 2281 2281" _null_ _null_ _null_ _null_ gin_extract_tsquery _null_ _null_ _null_ )); DESCR("GIN tsvector support"); -DATA(insert OID = 3658 ( gin_tsquery_consistent PGNSP PGUID 12 1 0 0 f f f t f i 4 0 16 "2281 21 3615 2281" _null_ _null_ _null_ _null_ gin_tsquery_consistent _null_ _null_ _null_ )); +DATA(insert OID = 3658 ( gin_tsquery_consistent PGNSP PGUID 12 1 0 0 f f f t f i 6 0 16 "2281 21 3615 23 2281 2281" _null_ _null_ _null_ _null_ gin_tsquery_consistent _null_ _null_ _null_ )); DESCR("GIN tsvector support"); DATA(insert OID = 3724 ( gin_cmp_tslexeme PGNSP PGUID 12 1 0 0 f f f t f i 2 0 23 "25 25" _null_ _null_ _null_ _null_ gin_cmp_tslexeme _null_ _null_ _null_ )); DESCR("GIN tsvector support"); -DATA(insert OID = 2700 ( gin_cmp_prefix PGNSP PGUID 12 1 0 0 f f f t f i 3 0 23 "25 25 21" _null_ _null_ _null_ _null_ gin_cmp_prefix _null_ _null_ _null_ )); +DATA(insert OID = 2700 ( gin_cmp_prefix PGNSP PGUID 12 1 0 0 f f f t f i 4 0 23 "25 25 21 2281" _null_ _null_ _null_ _null_ gin_cmp_prefix _null_ _null_ _null_ )); DESCR("GIN tsvector support"); DATA(insert OID = 3662 ( tsquery_lt PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3615 3615" _null_ _null_ _null_ _null_ tsquery_lt _null_ _null_ _null_ )); |