Make GIN opclass worked with intarray extensions

This commit is contained in:
Teodor Sigaev 2006-05-03 16:31:07 +00:00
parent 2a58f3bff6
commit 5320c6cf6b
8 changed files with 258 additions and 16 deletions

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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,

100
contrib/intarray/_int_gin.c Normal file
View File

@ -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);
}

View File

@ -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)

View File

@ -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)';

View File

@ -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';