Skip to content

Commit 5320c6c

Browse files
committed
Make GIN opclass worked with intarray extensions
1 parent 2a58f3b commit 5320c6c

File tree

8 files changed

+258
-16
lines changed

8 files changed

+258
-16
lines changed

contrib/intarray/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
# $PostgreSQL: pgsql/contrib/intarray/Makefile,v 1.13 2006/02/27 12:54:39 petere Exp $
1+
# $PostgreSQL: pgsql/contrib/intarray/Makefile,v 1.14 2006/05/03 16:31:07 teodor Exp $
22

33
MODULE_big = _int
4-
OBJS = _int_bool.o _int_gist.o _int_op.o _int_tool.o _intbig_gist.o
4+
OBJS = _int_bool.o _int_gist.o _int_op.o _int_tool.o _intbig_gist.o _int_gin.o
55
DATA_built = _int.sql
66
DATA = uninstall__int.sql
77
DOCS = README.intarray

contrib/intarray/_int.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,17 @@ typedef struct
151151
#define COMPUTESIZE(size) ( HDRSIZEQT + size * sizeof(ITEM) )
152152
#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT )
153153

154+
#define END 0
155+
#define ERR 1
156+
#define VAL 2
157+
#define OPR 3
158+
#define OPEN 4
159+
#define CLOSE 5
160+
154161
bool signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot);
155162
bool execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot);
156-
157-
163+
bool ginconsistent(QUERYTYPE * query, bool *check);
164+
int4 shorterquery(ITEM * q, int4 len);
158165

159166
int compASC(const void *a, const void *b);
160167

contrib/intarray/_int.sql.in

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
-- opclasses get created.
77
SET search_path = public;
88

9+
BEGIN;
10+
911
-- Query type
1012
CREATE FUNCTION bqarr_in(cstring)
1113
RETURNS query_int
@@ -431,3 +433,35 @@ AS
431433
FUNCTION 6 g_intbig_picksplit (internal, internal),
432434
FUNCTION 7 g_intbig_same (internal, internal, internal),
433435
STORAGE intbig_gkey;
436+
437+
--GIN
438+
--mark built-in gin's _int4_ops as non default
439+
update pg_opclass set opcdefault = 'f' where
440+
pg_opclass.opcamid = (select pg_am.oid from pg_am where amname='gin') and
441+
opcname = '_int4_ops';
442+
443+
CREATE FUNCTION ginint4_queryextract(internal, internal, int2)
444+
RETURNS internal
445+
AS 'MODULE_PATHNAME'
446+
LANGUAGE C;
447+
448+
CREATE FUNCTION ginint4_consistent(internal, int2, internal)
449+
RETURNS internal
450+
AS 'MODULE_PATHNAME'
451+
LANGUAGE C;
452+
453+
CREATE OPERATOR CLASS gin__int_ops
454+
DEFAULT FOR TYPE _int4 USING gin
455+
AS
456+
OPERATOR 3 &&,
457+
OPERATOR 6 = (anyarray, anyarray) RECHECK,
458+
OPERATOR 7 @,
459+
OPERATOR 8 ~ RECHECK,
460+
OPERATOR 20 @@ (_int4, query_int),
461+
FUNCTION 1 btint4cmp (int4, int4),
462+
FUNCTION 2 ginarrayextract (anyarray, internal),
463+
FUNCTION 3 ginint4_queryextract (internal, internal, int2),
464+
FUNCTION 4 ginint4_consistent (internal, int2, internal),
465+
STORAGE int4;
466+
467+
COMMIT;

contrib/intarray/_int_bool.c

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ typedef struct
232232
* is there value 'val' in array or not ?
233233
*/
234234
static bool
235-
checkcondition_arr(void *checkval, int4 val)
235+
checkcondition_arr(void *checkval, ITEM *item)
236236
{
237237
int4 *StopLow = ((CHKVAL *) checkval)->arrb;
238238
int4 *StopHigh = ((CHKVAL *) checkval)->arre;
@@ -243,9 +243,9 @@ checkcondition_arr(void *checkval, int4 val)
243243
while (StopLow < StopHigh)
244244
{
245245
StopMiddle = StopLow + (StopHigh - StopLow) / 2;
246-
if (*StopMiddle == val)
246+
if (*StopMiddle == item->val)
247247
return (true);
248-
else if (*StopMiddle < val)
248+
else if (*StopMiddle < item->val)
249249
StopLow = StopMiddle + 1;
250250
else
251251
StopHigh = StopMiddle;
@@ -254,20 +254,20 @@ checkcondition_arr(void *checkval, int4 val)
254254
}
255255

256256
static bool
257-
checkcondition_bit(void *checkval, int4 val)
257+
checkcondition_bit(void *checkval, ITEM *item)
258258
{
259-
return GETBIT(checkval, HASHVAL(val));
259+
return GETBIT(checkval, HASHVAL(item->val));
260260
}
261261

262262
/*
263263
* check for boolean condition
264264
*/
265265
static bool
266-
execute(ITEM * curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, int4 val))
266+
execute(ITEM * curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, ITEM *item))
267267
{
268268

269269
if (curitem->type == VAL)
270-
return (*chkcond) (checkval, curitem->val);
270+
return (*chkcond) (checkval, curitem);
271271
else if (curitem->val == (int4) '!')
272272
{
273273
return (calcnot) ?
@@ -319,6 +319,40 @@ execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot)
319319
);
320320
}
321321

322+
typedef struct {
323+
ITEM *first;
324+
bool *mapped_check;
325+
} GinChkVal;
326+
327+
static bool
328+
checkcondition_gin(void *checkval, ITEM *item) {
329+
GinChkVal *gcv = (GinChkVal*)checkval;
330+
331+
return gcv->mapped_check[ item - gcv->first ];
332+
}
333+
334+
bool
335+
ginconsistent(QUERYTYPE * query, bool *check) {
336+
GinChkVal gcv;
337+
ITEM *items = GETQUERY(query);
338+
int i, j=0;
339+
340+
if ( query->size < 0 )
341+
return FALSE;
342+
343+
gcv.first = items;
344+
gcv.mapped_check = (bool*)palloc( sizeof(bool)*query->size );
345+
for(i=0; i<query->size; i++)
346+
if ( items[i].type == VAL )
347+
gcv.mapped_check[ i ] = check[ j++ ];
348+
349+
return execute(
350+
GETQUERY(query) + query->size - 1,
351+
(void *) &gcv, true,
352+
checkcondition_gin
353+
);
354+
}
355+
322356
/*
323357
* boolean operations
324358
*/
@@ -588,7 +622,7 @@ countdroptree(ITEM * q, int4 pos)
588622
* result of all '!' will be = 'true', so
589623
* we can modify query tree for clearing
590624
*/
591-
static int4
625+
int4
592626
shorterquery(ITEM * q, int4 len)
593627
{
594628
int4 index,

contrib/intarray/_int_gin.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#include "_int.h"
2+
3+
PG_FUNCTION_INFO_V1(ginint4_queryextract);
4+
Datum ginint4_queryextract(PG_FUNCTION_ARGS);
5+
6+
Datum
7+
ginint4_queryextract(PG_FUNCTION_ARGS) {
8+
uint32 *nentries = (uint32*)PG_GETARG_POINTER(1);
9+
StrategyNumber strategy = PG_GETARG_UINT16(2);
10+
Datum *res = NULL;
11+
12+
*nentries = 0;
13+
14+
if ( strategy == BooleanSearchStrategy ) {
15+
QUERYTYPE *query = (QUERYTYPE*)PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0));
16+
ITEM *items = GETQUERY(query);
17+
int i;
18+
19+
if (query->size == 0)
20+
PG_RETURN_POINTER(NULL);
21+
22+
if ( shorterquery(items, query->size) == 0 )
23+
elog(ERROR,"Query requires full scan, GIN doesn't support it");
24+
25+
pfree( query );
26+
27+
query = (QUERYTYPE*)PG_DETOAST_DATUM(PG_GETARG_POINTER(0));
28+
items = GETQUERY(query);
29+
30+
res = (Datum*)palloc(sizeof(Datum) * query->size);
31+
*nentries = 0;
32+
33+
for(i=0;i<query->size;i++)
34+
if ( items[i].type == VAL ) {
35+
res[*nentries] = Int32GetDatum( items[i].val );
36+
(*nentries)++;
37+
}
38+
} else {
39+
ArrayType *query = PG_GETARG_ARRAYTYPE_P(0);
40+
int4 *arr;
41+
uint32 i;
42+
43+
CHECKARRVALID(query);
44+
*nentries=ARRNELEMS(query);
45+
if ( *nentries > 0 ) {
46+
res = (Datum*)palloc(sizeof(Datum) * (*nentries));
47+
48+
arr=ARRPTR(query);
49+
for(i=0;i<*nentries;i++)
50+
res[i] = Int32GetDatum( arr[i] );
51+
}
52+
}
53+
54+
PG_RETURN_POINTER( res );
55+
}
56+
57+
PG_FUNCTION_INFO_V1(ginint4_consistent);
58+
Datum ginint4_consistent(PG_FUNCTION_ARGS);
59+
60+
Datum
61+
ginint4_consistent(PG_FUNCTION_ARGS) {
62+
bool *check = (bool*)PG_GETARG_POINTER(0);
63+
StrategyNumber strategy = PG_GETARG_UINT16(1);
64+
int res=FALSE;
65+
66+
/* we can do not check array carefully, it's done by previous ginarrayextract call */
67+
68+
switch( strategy ) {
69+
case RTOverlapStrategyNumber:
70+
case RTContainedByStrategyNumber:
71+
/* at least one element in check[] is true, so result = true */
72+
73+
res = TRUE;
74+
break;
75+
case RTSameStrategyNumber:
76+
case RTContainsStrategyNumber:
77+
res = TRUE;
78+
do {
79+
ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
80+
int i, nentries=ARRNELEMS(query);
81+
82+
for(i=0;i<nentries;i++)
83+
if ( !check[i] ) {
84+
res = FALSE;
85+
break;
86+
}
87+
} while(0);
88+
break;
89+
case BooleanSearchStrategy:
90+
do {
91+
QUERYTYPE *query = (QUERYTYPE*)PG_DETOAST_DATUM(PG_GETARG_POINTER(2));
92+
res = ginconsistent( query, check );
93+
} while(0);
94+
break;
95+
default:
96+
elog(ERROR, "ginint4_consistent: unknown strategy number: %d", strategy);
97+
}
98+
99+
PG_RETURN_BOOL(res);
100+
}

contrib/intarray/expected/_int.out

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
-- does not depend on contents of _int.sql.
44
--
55
\set ECHO none
6-
psql:_int.sql:13: NOTICE: type "query_int" is not yet defined
6+
psql:_int.sql:15: NOTICE: type "query_int" is not yet defined
77
DETAIL: Creating a shell type definition.
8-
psql:_int.sql:18: NOTICE: argument type query_int is only a shell
9-
psql:_int.sql:368: NOTICE: type "intbig_gkey" is not yet defined
8+
psql:_int.sql:20: NOTICE: argument type query_int is only a shell
9+
psql:_int.sql:370: NOTICE: type "intbig_gkey" is not yet defined
1010
DETAIL: Creating a shell type definition.
11-
psql:_int.sql:373: NOTICE: argument type intbig_gkey is only a shell
11+
psql:_int.sql:375: NOTICE: argument type intbig_gkey is only a shell
1212
SELECT intset(1234);
1313
intset
1414
--------
@@ -519,3 +519,53 @@ SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
519519
21
520520
(1 row)
521521

522+
DROP INDEX text_idx;
523+
CREATE INDEX text_idx on test__int using gin ( a );
524+
SELECT count(*) from test__int WHERE a && '{23,50}';
525+
count
526+
-------
527+
403
528+
(1 row)
529+
530+
SELECT count(*) from test__int WHERE a @@ '23|50';
531+
count
532+
-------
533+
403
534+
(1 row)
535+
536+
SELECT count(*) from test__int WHERE a @ '{23,50}';
537+
count
538+
-------
539+
12
540+
(1 row)
541+
542+
SELECT count(*) from test__int WHERE a @@ '23&50';
543+
count
544+
-------
545+
12
546+
(1 row)
547+
548+
SELECT count(*) from test__int WHERE a @ '{20,23}';
549+
count
550+
-------
551+
12
552+
(1 row)
553+
554+
SELECT count(*) from test__int WHERE a @@ '50&68';
555+
count
556+
-------
557+
9
558+
(1 row)
559+
560+
SELECT count(*) from test__int WHERE a @ '{20,23}' or a @ '{50,68}';
561+
count
562+
-------
563+
21
564+
(1 row)
565+
566+
SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
567+
count
568+
-------
569+
21
570+
(1 row)
571+

contrib/intarray/sql/_int.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,15 @@ SELECT count(*) from test__int WHERE a @ '{20,23}';
107107
SELECT count(*) from test__int WHERE a @@ '50&68';
108108
SELECT count(*) from test__int WHERE a @ '{20,23}' or a @ '{50,68}';
109109
SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
110+
111+
DROP INDEX text_idx;
112+
CREATE INDEX text_idx on test__int using gin ( a );
113+
114+
SELECT count(*) from test__int WHERE a && '{23,50}';
115+
SELECT count(*) from test__int WHERE a @@ '23|50';
116+
SELECT count(*) from test__int WHERE a @ '{23,50}';
117+
SELECT count(*) from test__int WHERE a @@ '23&50';
118+
SELECT count(*) from test__int WHERE a @ '{20,23}';
119+
SELECT count(*) from test__int WHERE a @@ '50&68';
120+
SELECT count(*) from test__int WHERE a @ '{20,23}' or a @ '{50,68}';
121+
SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';

contrib/intarray/uninstall__int.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,8 @@ DROP FUNCTION boolop(_int4, query_int);
113113
DROP FUNCTION querytree(query_int);
114114

115115
DROP TYPE query_int CASCADE;
116+
117+
update pg_opclass set opcdefault = 't' where
118+
pg_opclass.opcamid = (select pg_am.oid from pg_am where amname='gin') and
119+
opcname = '_int4_ops';
120+

0 commit comments

Comments
 (0)