Make GIN opclass worked with intarray extensions
This commit is contained in:
parent
2a58f3bff6
commit
5320c6cf6b
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
100
contrib/intarray/_int_gin.c
Normal 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);
|
||||
}
|
@ -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)
|
||||
|
||||
|
@ -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)';
|
||||
|
@ -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';
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user