aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/intarray/Makefile4
-rw-r--r--contrib/intarray/_int.h11
-rw-r--r--contrib/intarray/_int.sql.in34
-rw-r--r--contrib/intarray/_int_bool.c50
-rw-r--r--contrib/intarray/_int_gin.c100
-rw-r--r--contrib/intarray/expected/_int.out58
-rw-r--r--contrib/intarray/sql/_int.sql12
-rw-r--r--contrib/intarray/uninstall__int.sql5
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';
+