diff options
-rw-r--r-- | contrib/intarray/Makefile | 4 | ||||
-rw-r--r-- | contrib/intarray/_int.h | 11 | ||||
-rw-r--r-- | contrib/intarray/_int.sql.in | 34 | ||||
-rw-r--r-- | contrib/intarray/_int_bool.c | 50 | ||||
-rw-r--r-- | contrib/intarray/_int_gin.c | 100 | ||||
-rw-r--r-- | contrib/intarray/expected/_int.out | 58 | ||||
-rw-r--r-- | contrib/intarray/sql/_int.sql | 12 | ||||
-rw-r--r-- | contrib/intarray/uninstall__int.sql | 5 |
8 files changed, 258 insertions, 16 deletions
diff --git a/contrib/intarray/Makefile b/contrib/intarray/Makefile index b3830a2dde0..2b9a62409cd 100644 --- a/contrib/intarray/Makefile +++ b/contrib/intarray/Makefile @@ -1,7 +1,7 @@ -# $PostgreSQL: pgsql/contrib/intarray/Makefile,v 1.13 2006/02/27 12:54:39 petere Exp $ +# $PostgreSQL: pgsql/contrib/intarray/Makefile,v 1.14 2006/05/03 16:31:07 teodor Exp $ MODULE_big = _int -OBJS = _int_bool.o _int_gist.o _int_op.o _int_tool.o _intbig_gist.o +OBJS = _int_bool.o _int_gist.o _int_op.o _int_tool.o _intbig_gist.o _int_gin.o DATA_built = _int.sql DATA = uninstall__int.sql DOCS = README.intarray diff --git a/contrib/intarray/_int.h b/contrib/intarray/_int.h index af67435309e..6218cbcd20d 100644 --- a/contrib/intarray/_int.h +++ b/contrib/intarray/_int.h @@ -151,10 +151,17 @@ typedef struct #define COMPUTESIZE(size) ( HDRSIZEQT + size * sizeof(ITEM) ) #define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT ) +#define END 0 +#define ERR 1 +#define VAL 2 +#define OPR 3 +#define OPEN 4 +#define CLOSE 5 + bool signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot); bool execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot); - - +bool ginconsistent(QUERYTYPE * query, bool *check); +int4 shorterquery(ITEM * q, int4 len); int compASC(const void *a, const void *b); diff --git a/contrib/intarray/_int.sql.in b/contrib/intarray/_int.sql.in index b9d33a7a43a..31fae745415 100644 --- a/contrib/intarray/_int.sql.in +++ b/contrib/intarray/_int.sql.in @@ -6,6 +6,8 @@ -- opclasses get created. SET search_path = public; +BEGIN; + -- Query type CREATE FUNCTION bqarr_in(cstring) RETURNS query_int @@ -431,3 +433,35 @@ AS FUNCTION 6 g_intbig_picksplit (internal, internal), FUNCTION 7 g_intbig_same (internal, internal, internal), STORAGE intbig_gkey; + +--GIN +--mark built-in gin's _int4_ops as non default +update pg_opclass set opcdefault = 'f' where + pg_opclass.opcamid = (select pg_am.oid from pg_am where amname='gin') and + opcname = '_int4_ops'; + +CREATE FUNCTION ginint4_queryextract(internal, internal, int2) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C; + +CREATE FUNCTION ginint4_consistent(internal, int2, internal) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C; + +CREATE OPERATOR CLASS gin__int_ops +DEFAULT FOR TYPE _int4 USING gin +AS + OPERATOR 3 &&, + OPERATOR 6 = (anyarray, anyarray) RECHECK, + OPERATOR 7 @, + OPERATOR 8 ~ RECHECK, + 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), + STORAGE int4; + +COMMIT; diff --git a/contrib/intarray/_int_bool.c b/contrib/intarray/_int_bool.c index 8e0b913c013..230c412a048 100644 --- a/contrib/intarray/_int_bool.c +++ b/contrib/intarray/_int_bool.c @@ -232,7 +232,7 @@ typedef struct * is there value 'val' in array or not ? */ static bool -checkcondition_arr(void *checkval, int4 val) +checkcondition_arr(void *checkval, ITEM *item) { int4 *StopLow = ((CHKVAL *) checkval)->arrb; int4 *StopHigh = ((CHKVAL *) checkval)->arre; @@ -243,9 +243,9 @@ checkcondition_arr(void *checkval, int4 val) while (StopLow < StopHigh) { StopMiddle = StopLow + (StopHigh - StopLow) / 2; - if (*StopMiddle == val) + if (*StopMiddle == item->val) return (true); - else if (*StopMiddle < val) + else if (*StopMiddle < item->val) StopLow = StopMiddle + 1; else StopHigh = StopMiddle; @@ -254,20 +254,20 @@ checkcondition_arr(void *checkval, int4 val) } static bool -checkcondition_bit(void *checkval, int4 val) +checkcondition_bit(void *checkval, ITEM *item) { - return GETBIT(checkval, HASHVAL(val)); + return GETBIT(checkval, HASHVAL(item->val)); } /* * check for boolean condition */ static bool -execute(ITEM * curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, int4 val)) +execute(ITEM * curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, ITEM *item)) { if (curitem->type == VAL) - return (*chkcond) (checkval, curitem->val); + return (*chkcond) (checkval, curitem); else if (curitem->val == (int4) '!') { return (calcnot) ? @@ -319,6 +319,40 @@ execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot) ); } +typedef struct { + ITEM *first; + bool *mapped_check; +} GinChkVal; + +static bool +checkcondition_gin(void *checkval, ITEM *item) { + GinChkVal *gcv = (GinChkVal*)checkval; + + return gcv->mapped_check[ item - gcv->first ]; +} + +bool +ginconsistent(QUERYTYPE * query, bool *check) { + GinChkVal gcv; + ITEM *items = GETQUERY(query); + int i, j=0; + + if ( query->size < 0 ) + return FALSE; + + gcv.first = items; + gcv.mapped_check = (bool*)palloc( sizeof(bool)*query->size ); + for(i=0; i<query->size; i++) + if ( items[i].type == VAL ) + gcv.mapped_check[ i ] = check[ j++ ]; + + return execute( + GETQUERY(query) + query->size - 1, + (void *) &gcv, true, + checkcondition_gin + ); +} + /* * boolean operations */ @@ -588,7 +622,7 @@ countdroptree(ITEM * q, int4 pos) * result of all '!' will be = 'true', so * we can modify query tree for clearing */ -static int4 +int4 shorterquery(ITEM * q, int4 len) { int4 index, diff --git a/contrib/intarray/_int_gin.c b/contrib/intarray/_int_gin.c new file mode 100644 index 00000000000..dfbb6e2ff1d --- /dev/null +++ b/contrib/intarray/_int_gin.c @@ -0,0 +1,100 @@ +#include "_int.h" + +PG_FUNCTION_INFO_V1(ginint4_queryextract); +Datum ginint4_queryextract(PG_FUNCTION_ARGS); + +Datum +ginint4_queryextract(PG_FUNCTION_ARGS) { + uint32 *nentries = (uint32*)PG_GETARG_POINTER(1); + StrategyNumber strategy = PG_GETARG_UINT16(2); + Datum *res = NULL; + + *nentries = 0; + + if ( strategy == BooleanSearchStrategy ) { + QUERYTYPE *query = (QUERYTYPE*)PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0)); + ITEM *items = GETQUERY(query); + int i; + + if (query->size == 0) + PG_RETURN_POINTER(NULL); + + if ( shorterquery(items, query->size) == 0 ) + elog(ERROR,"Query requires full scan, GIN doesn't support it"); + + pfree( query ); + + query = (QUERYTYPE*)PG_DETOAST_DATUM(PG_GETARG_POINTER(0)); + items = GETQUERY(query); + + res = (Datum*)palloc(sizeof(Datum) * query->size); + *nentries = 0; + + for(i=0;i<query->size;i++) + if ( items[i].type == VAL ) { + res[*nentries] = Int32GetDatum( items[i].val ); + (*nentries)++; + } + } else { + ArrayType *query = PG_GETARG_ARRAYTYPE_P(0); + int4 *arr; + uint32 i; + + CHECKARRVALID(query); + *nentries=ARRNELEMS(query); + if ( *nentries > 0 ) { + res = (Datum*)palloc(sizeof(Datum) * (*nentries)); + + arr=ARRPTR(query); + for(i=0;i<*nentries;i++) + res[i] = Int32GetDatum( arr[i] ); + } + } + + PG_RETURN_POINTER( res ); +} + +PG_FUNCTION_INFO_V1(ginint4_consistent); +Datum ginint4_consistent(PG_FUNCTION_ARGS); + +Datum +ginint4_consistent(PG_FUNCTION_ARGS) { + bool *check = (bool*)PG_GETARG_POINTER(0); + StrategyNumber strategy = PG_GETARG_UINT16(1); + int res=FALSE; + + /* we can do not check array carefully, it's done by previous ginarrayextract call */ + + switch( strategy ) { + case RTOverlapStrategyNumber: + case RTContainedByStrategyNumber: + /* at least one element in check[] is true, so result = true */ + + res = TRUE; + break; + case RTSameStrategyNumber: + case RTContainsStrategyNumber: + res = TRUE; + do { + ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); + int i, nentries=ARRNELEMS(query); + + for(i=0;i<nentries;i++) + if ( !check[i] ) { + res = FALSE; + break; + } + } while(0); + break; + case BooleanSearchStrategy: + do { + QUERYTYPE *query = (QUERYTYPE*)PG_DETOAST_DATUM(PG_GETARG_POINTER(2)); + res = ginconsistent( query, check ); + } while(0); + break; + default: + elog(ERROR, "ginint4_consistent: unknown strategy number: %d", strategy); + } + + PG_RETURN_BOOL(res); +} diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out index 85c8d8bb142..e45ed3cfa83 100644 --- a/contrib/intarray/expected/_int.out +++ b/contrib/intarray/expected/_int.out @@ -3,12 +3,12 @@ -- does not depend on contents of _int.sql. -- \set ECHO none -psql:_int.sql:13: NOTICE: type "query_int" is not yet defined +psql:_int.sql:15: NOTICE: type "query_int" is not yet defined DETAIL: Creating a shell type definition. -psql:_int.sql:18: NOTICE: argument type query_int is only a shell -psql:_int.sql:368: NOTICE: type "intbig_gkey" is not yet defined +psql:_int.sql:20: NOTICE: argument type query_int is only a shell +psql:_int.sql:370: NOTICE: type "intbig_gkey" is not yet defined DETAIL: Creating a shell type definition. -psql:_int.sql:373: NOTICE: argument type intbig_gkey is only a shell +psql:_int.sql:375: NOTICE: argument type intbig_gkey is only a shell SELECT intset(1234); intset -------- @@ -519,3 +519,53 @@ SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)'; 21 (1 row) +DROP INDEX text_idx; +CREATE INDEX text_idx on test__int using gin ( a ); +SELECT count(*) from test__int WHERE a && '{23,50}'; + count +------- + 403 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '23|50'; + count +------- + 403 +(1 row) + +SELECT count(*) from test__int WHERE a @ '{23,50}'; + count +------- + 12 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '23&50'; + count +------- + 12 +(1 row) + +SELECT count(*) from test__int WHERE a @ '{20,23}'; + count +------- + 12 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '50&68'; + count +------- + 9 +(1 row) + +SELECT count(*) from test__int WHERE a @ '{20,23}' or a @ '{50,68}'; + count +------- + 21 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)'; + count +------- + 21 +(1 row) + diff --git a/contrib/intarray/sql/_int.sql b/contrib/intarray/sql/_int.sql index 5c0d00c67ab..e04b88e7512 100644 --- a/contrib/intarray/sql/_int.sql +++ b/contrib/intarray/sql/_int.sql @@ -107,3 +107,15 @@ SELECT count(*) from test__int WHERE a @ '{20,23}'; SELECT count(*) from test__int WHERE a @@ '50&68'; SELECT count(*) from test__int WHERE a @ '{20,23}' or a @ '{50,68}'; SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)'; + +DROP INDEX text_idx; +CREATE INDEX text_idx on test__int using gin ( a ); + +SELECT count(*) from test__int WHERE a && '{23,50}'; +SELECT count(*) from test__int WHERE a @@ '23|50'; +SELECT count(*) from test__int WHERE a @ '{23,50}'; +SELECT count(*) from test__int WHERE a @@ '23&50'; +SELECT count(*) from test__int WHERE a @ '{20,23}'; +SELECT count(*) from test__int WHERE a @@ '50&68'; +SELECT count(*) from test__int WHERE a @ '{20,23}' or a @ '{50,68}'; +SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)'; diff --git a/contrib/intarray/uninstall__int.sql b/contrib/intarray/uninstall__int.sql index 43fd854c7ae..49522b7c6c7 100644 --- a/contrib/intarray/uninstall__int.sql +++ b/contrib/intarray/uninstall__int.sql @@ -113,3 +113,8 @@ DROP FUNCTION boolop(_int4, query_int); DROP FUNCTION querytree(query_int); DROP TYPE query_int CASCADE; + +update pg_opclass set opcdefault = 't' where + pg_opclass.opcamid = (select pg_am.oid from pg_am where amname='gin') and + opcname = '_int4_ops'; + |