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
|
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_built = _int.sql
|
||||||
DATA = uninstall__int.sql
|
DATA = uninstall__int.sql
|
||||||
DOCS = README.intarray
|
DOCS = README.intarray
|
||||||
|
@ -151,10 +151,17 @@ typedef struct
|
|||||||
#define COMPUTESIZE(size) ( HDRSIZEQT + size * sizeof(ITEM) )
|
#define COMPUTESIZE(size) ( HDRSIZEQT + size * sizeof(ITEM) )
|
||||||
#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT )
|
#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 signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot);
|
||||||
bool execconsistent(QUERYTYPE * query, ArrayType *array, 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);
|
int compASC(const void *a, const void *b);
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
-- opclasses get created.
|
-- opclasses get created.
|
||||||
SET search_path = public;
|
SET search_path = public;
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
-- Query type
|
-- Query type
|
||||||
CREATE FUNCTION bqarr_in(cstring)
|
CREATE FUNCTION bqarr_in(cstring)
|
||||||
RETURNS query_int
|
RETURNS query_int
|
||||||
@ -431,3 +433,35 @@ AS
|
|||||||
FUNCTION 6 g_intbig_picksplit (internal, internal),
|
FUNCTION 6 g_intbig_picksplit (internal, internal),
|
||||||
FUNCTION 7 g_intbig_same (internal, internal, internal),
|
FUNCTION 7 g_intbig_same (internal, internal, internal),
|
||||||
STORAGE intbig_gkey;
|
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 ?
|
* is there value 'val' in array or not ?
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
checkcondition_arr(void *checkval, int4 val)
|
checkcondition_arr(void *checkval, ITEM *item)
|
||||||
{
|
{
|
||||||
int4 *StopLow = ((CHKVAL *) checkval)->arrb;
|
int4 *StopLow = ((CHKVAL *) checkval)->arrb;
|
||||||
int4 *StopHigh = ((CHKVAL *) checkval)->arre;
|
int4 *StopHigh = ((CHKVAL *) checkval)->arre;
|
||||||
@ -243,9 +243,9 @@ checkcondition_arr(void *checkval, int4 val)
|
|||||||
while (StopLow < StopHigh)
|
while (StopLow < StopHigh)
|
||||||
{
|
{
|
||||||
StopMiddle = StopLow + (StopHigh - StopLow) / 2;
|
StopMiddle = StopLow + (StopHigh - StopLow) / 2;
|
||||||
if (*StopMiddle == val)
|
if (*StopMiddle == item->val)
|
||||||
return (true);
|
return (true);
|
||||||
else if (*StopMiddle < val)
|
else if (*StopMiddle < item->val)
|
||||||
StopLow = StopMiddle + 1;
|
StopLow = StopMiddle + 1;
|
||||||
else
|
else
|
||||||
StopHigh = StopMiddle;
|
StopHigh = StopMiddle;
|
||||||
@ -254,20 +254,20 @@ checkcondition_arr(void *checkval, int4 val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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
|
* check for boolean condition
|
||||||
*/
|
*/
|
||||||
static bool
|
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)
|
if (curitem->type == VAL)
|
||||||
return (*chkcond) (checkval, curitem->val);
|
return (*chkcond) (checkval, curitem);
|
||||||
else if (curitem->val == (int4) '!')
|
else if (curitem->val == (int4) '!')
|
||||||
{
|
{
|
||||||
return (calcnot) ?
|
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
|
* boolean operations
|
||||||
*/
|
*/
|
||||||
@ -588,7 +622,7 @@ countdroptree(ITEM * q, int4 pos)
|
|||||||
* result of all '!' will be = 'true', so
|
* result of all '!' will be = 'true', so
|
||||||
* we can modify query tree for clearing
|
* we can modify query tree for clearing
|
||||||
*/
|
*/
|
||||||
static int4
|
int4
|
||||||
shorterquery(ITEM * q, int4 len)
|
shorterquery(ITEM * q, int4 len)
|
||||||
{
|
{
|
||||||
int4 index,
|
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.
|
-- does not depend on contents of _int.sql.
|
||||||
--
|
--
|
||||||
\set ECHO none
|
\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.
|
DETAIL: Creating a shell type definition.
|
||||||
psql:_int.sql:18: NOTICE: argument type query_int is only a shell
|
psql:_int.sql:20: NOTICE: argument type query_int is only a shell
|
||||||
psql:_int.sql:368: NOTICE: type "intbig_gkey" is not yet defined
|
psql:_int.sql:370: NOTICE: type "intbig_gkey" is not yet defined
|
||||||
DETAIL: Creating a shell type definition.
|
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);
|
SELECT intset(1234);
|
||||||
intset
|
intset
|
||||||
--------
|
--------
|
||||||
@ -519,3 +519,53 @@ SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
|
|||||||
21
|
21
|
||||||
(1 row)
|
(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 @@ '50&68';
|
||||||
SELECT count(*) from test__int WHERE a @ '{20,23}' or 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)';
|
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 FUNCTION querytree(query_int);
|
||||||
|
|
||||||
DROP TYPE query_int CASCADE;
|
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