]> granicus.if.org Git - postgresql/commitdiff
Adjust the APIs for GIN opclass support functions to allow the extractQuery()
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 25 Mar 2009 22:19:02 +0000 (22:19 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 25 Mar 2009 22:19:02 +0000 (22:19 +0000)
method to pass extra data to the consistent() and comparePartial() methods.
This is the core infrastructure needed to support the soon-to-appear
contrib/btree_gin module.  The APIs are still upward compatible with the
definitions used in 8.3 and before, although *not* with the previous 8.4devel
function definitions.

catversion bump for changes in pg_proc entries (although these are just
cosmetic, since GIN doesn't actually look at the function signature before
calling it...)

Teodor Sigaev and Oleg Bartunov

18 files changed:
contrib/hstore/hstore.sql.in
contrib/hstore/hstore_gin.c
contrib/hstore/uninstall_hstore.sql
contrib/intarray/_int.sql.in
contrib/intarray/_int_gin.c
contrib/intarray/uninstall__int.sql
contrib/pg_trgm/pg_trgm.sql.in
contrib/pg_trgm/trgm_gin.c
contrib/pg_trgm/uninstall_pg_trgm.sql
contrib/tsearch2/tsearch2.sql.in
doc/src/sgml/gin.sgml
src/backend/access/gin/ginarrayproc.c
src/backend/access/gin/ginget.c
src/backend/access/gin/ginscan.c
src/backend/utils/adt/tsginidx.c
src/include/access/gin.h
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h

index 1b22ff63c560f53d222cc72a4b9a6951bb1a5964..3487a48459aac8c6f81277d1a6536c8617fbd56a 100644 (file)
@@ -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;
index d40b2e5bb8febda0d32ba89664e1ebf35c20f89a..01d7258f8f9cec20413887cf333f4284353512ac 100644 (file)
@@ -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)
index 84d567fcadf87496e71a11a8cc47d428909a8288..17782d5c058f4048d518cc94d7e9ff57e0f89553 100644 (file)
@@ -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;
index c681626dc9b57d496562b8bf8e33e528c0585c5e..9f91a65eec717435e7c9c1853c4ba2bfa6c50211 100644 (file)
@@ -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;
index 0edb686df2ec83b9a0dc1ea1ebaf1ef9d39cdc95..598cdeca5709fbda4d1acce42f6b6646ce49be8f 100644 (file)
@@ -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;
 
        /*
index 59ef2afc0f09d115684a8732cfe5649125ce24d5..5346bddc7528920de582b4d2242b45c5dfadce93 100644 (file)
@@ -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;
 
index d65a9cf6b2ec1d6aa11f5632930fb91ba32ecc20..f59ea1ba854a9f336148f7629f04df112ba4b293 100644 (file)
@@ -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;
index 7a64764fb8880a6c17cd657c1ea8e74f2c9d7800..1a53d1d3583c1adbee87670a67e27055cbbb2bfa 100644 (file)
@@ -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])
index 094dfcddc733e2487c7ef1ee605814c4e4d1be72..42c1d741f93d2812e21846f59e484bfa0a76cddd 100644 (file)
@@ -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);
 
index 4bf0d9ace655905ef72100f7a73c874ed324bdaf..fc1903757854e0d827b0c81226601e3bcfcc024d 100644 (file)
@@ -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
index 9cdc4ed528131695750875e18ca865c6c757e012..4c0438f910441d0cf3214a617d7026bf13dc368c 100644 (file)
@@ -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,
        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
        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.
   <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
        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>
  </para>
 
  <variablelist>
+  <varlistentry>
+   <term>btree-gin</term>
+   <listitem>
+    <para>B-Tree equivalent functionality for several data types</para>
+   </listitem>
+  </varlistentry>
+
   <varlistentry>
    <term>hstore</term>
    <listitem>
index 3b2e43318f8e2ecbdbca2439db920b37afe06527..717caaad8b5f0d317da13b1d1be802ace2694dbd 100644 (file)
@@ -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;
index 7f9f123660519827728b01ae67ef68a249092425..55ed9f335ae7665f7e0b6a2cbd0b2cde57a27467 100644 (file)
@@ -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;
index ba3774192229fd3ae3f1f638f30c9bc90dd115af..486adb6d7e818e7a63e6b8fae6adb2134115e668 100644 (file)
@@ -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);
 }
index b5b28f13afd104bfc54a2829718fd3dbbca3bd0c..262a604ded1efada9ab8579b763f2427ffd59e96 100644 (file)
@@ -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,
index c591c53638c7215dbdc9ee8838057a0208fc24c9..4a4abc1cd21506161d29c18130d1d5ec7b446f6d 100644 (file)
@@ -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;
index 3d4fdc33bd3f8627dc0174b790c92225e43c0157..e012b1046f2ca264689f7941d5bd27536c1d7fa9 100644 (file)
@@ -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
index 2f0dbeb2656bdde06a3fddb5fc71e1353a736354..475a3339a601163dc07e796b107bc81c5bda066b 100644 (file)
@@ -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_ ));