From: Tom Lane Date: Wed, 25 Mar 2009 22:19:02 +0000 (+0000) Subject: Adjust the APIs for GIN opclass support functions to allow the extractQuery() X-Git-Tag: REL8_4_BETA1~136 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=87b8db37740bb044cb3b6a6439e656217869fd57;p=postgresql Adjust the APIs for GIN opclass support functions to allow the extractQuery() 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 --- diff --git a/contrib/hstore/hstore.sql.in b/contrib/hstore/hstore.sql.in index 1b22ff63c5..3487a48459 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 d40b2e5bb8..01d7258f8f 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 84d567fcad..17782d5c05 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 c681626dc9..9f91a65eec 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 0edb686df2..598cdeca57 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 59ef2afc0f..5346bddc75 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 d65a9cf6b2..f59ea1ba85 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 7a64764fb8..1a53d1d358 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 094dfcddc7..42c1d741f9 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 4bf0d9ace6..fc19037578 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 9cdc4ed528..4c0438f910 100644 --- a/doc/src/sgml/gin.sgml +++ b/doc/src/sgml/gin.sgml @@ -1,4 +1,4 @@ - + GIN Indexes @@ -88,7 +88,7 @@ Datum *extractQuery(Datum query, int32 *nkeys, - StrategyNumber n, bool **pmatch) + StrategyNumber n, bool **pmatch, Pointer **extra_data) Returns an array of keys given a value to be queried; that is, @@ -104,7 +104,7 @@ should store 0 or -1 into *nkeys, depending on the semantics of the operator. 0 means that every value matches the query and a sequential scan should be - produced. -1 means nothing can match the query. + performed. -1 means nothing can match the query. pmatch is an output argument for use when partial match is supported. To use it, extractQuery must allocate an array of *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. + extra_data is an output argument that allows + extractQuery to pass additional data to the + consistent and comparePartial methods. + To use it, extractQuery must allocate + an array of *nkeys Pointers and store its address at + *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 *extra_data is set, the + whole array is passed to the consistent method, and + the appropriate element to the comparePartial method. - bool consistent(bool check[], StrategyNumber n, Datum query, bool *recheck) + bool consistent(bool check[], StrategyNumber n, Datum query, + int32 nkeys, Pointer extra_data[], bool *recheck) Returns TRUE if the indexed value satisfies the query operator with strategy number n (or might satisfy, if the recheck - indication is returned). The check array has - the same length as the number of keys previously returned by - extractQuery for this query. Each element of the + indication is returned). The check array has length + nkeys, which is the same as the number of keys previously + returned by extractQuery for this query datum. + Each element of the check array is TRUE if the indexed value contains the corresponding query key, ie, if (check[i] == TRUE) the i-th key of the extractQuery result array is present in the indexed value. The original query datum (not the extracted key array!) is passed in case the consistent method needs to consult it. + extra_data is the extra-data array returned by + extractQuery, or NULL if none. On success, *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 @@ - int comparePartial(Datum partial_key, Datum key, StrategyNumber n) + int comparePartial(Datum partial_key, Datum key, StrategyNumber n, + Pointer extra_data) 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 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, + extra_data is the corresponding element of the extra-data + array made by extractQuery, or NULL if none. @@ -383,6 +401,13 @@ + + btree-gin + + B-Tree equivalent functionality for several data types + + + hstore diff --git a/src/backend/access/gin/ginarrayproc.c b/src/backend/access/gin/ginarrayproc.c index 3b2e43318f..717caaad8b 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 7f9f123660..55ed9f335a 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 ba37741922..486adb6d7e 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 b5b28f13af..262a604ded 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 c591c53638..4a4abc1cd2 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 3d4fdc33bd..e012b1046f 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 2f0dbeb265..475a3339a6 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_ ));