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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy