@@ -53,6 +53,7 @@ typedef struct ExtractedNode ExtractedNode;
5353struct ExtractedNode
5454{
5555ExtractedNodeType type ;
56+ bool indirect ;
5657union
5758{
5859struct
@@ -76,15 +77,19 @@ typedef struct
7677{
7778ExtractedNode * root ;
7879uint32 hash ;
80+ bool lossy ;
81+ bool inequality ,leftInclusive ,rightInclusive ;
82+ GINKey * rightBound ;
7983}KeyExtra ;
8084
8185static uint32 get_bloom_value (uint32 hash );
8286static uint32 get_path_bloom (PathHashStack * stack );
8387static GINKey * make_gin_key (JsonbValue * v ,uint32 hash );
8488static GINKey * make_gin_query_key (char * jqBase ,int32 jqPos ,int32 type ,uint32 hash );
89+ static GINKey * make_gin_query_key_minus_inf (uint32 hash );
8590static int32 compare_gin_key_value (GINKey * arg1 ,GINKey * arg2 );
8691static int addEntry (Entries * e ,Datum key ,Pointer extra ,bool pmatch );
87- static ExtractedNode * recursiveExtract (char * jqBase ,int32 jqPos ,uint32 hash ,Entries * e ,bool lossy );
92+ static ExtractedNode * recursiveExtract (char * jqBase ,int32 jqPos ,uint32 hash ,Entries * e ,bool lossy , bool indirect );
8893
8994PG_FUNCTION_INFO_V1 (gin_compare_jsonb_bloom_value );
9095PG_FUNCTION_INFO_V1 (gin_compare_partial_jsonb_bloom_value );
@@ -127,13 +132,13 @@ addEntry(Entries *e, Datum key, Pointer extra, bool pmatch)
127132}
128133
129134static ExtractedNode *
130- recursiveExtract (char * jqBase ,int32 jqPos ,uint32 hash ,Entries * e ,bool lossy )
135+ recursiveExtract (char * jqBase ,int32 jqPos ,uint32 hash ,Entries * e ,bool lossy , bool indirect )
131136{
132- int32 type ;
137+ int32 type , childType ;
133138int32 nextPos ;
134139int32 left ,right ,arg ;
135140ExtractedNode * leftNode ,* rightNode ,* result ;
136- int32 len ;
141+ int32 len , * arrayPos , nelems , i ;
137142KeyExtra * extra ;
138143
139144check_stack_depth ();
@@ -146,8 +151,8 @@ recursiveExtract(char *jqBase, int32 jqPos, uint32 hash, Entries *e, bool lossy)
146151read_int32 (left ,jqBase ,jqPos );
147152read_int32 (right ,jqBase ,jqPos );
148153Assert (nextPos == 0 );
149- leftNode = recursiveExtract (jqBase ,left ,hash ,e ,lossy );
150- rightNode = recursiveExtract (jqBase ,right ,hash ,e ,lossy );
154+ leftNode = recursiveExtract (jqBase ,left ,hash ,e ,lossy , false );
155+ rightNode = recursiveExtract (jqBase ,right ,hash ,e ,lossy , false );
151156if (leftNode )
152157{
153158if (rightNode )
@@ -157,6 +162,7 @@ recursiveExtract(char *jqBase, int32 jqPos, uint32 hash, Entries *e, bool lossy)
157162result -> type = eAnd ;
158163else if (type == jqiOr )
159164result -> type = eOr ;
165+ result -> indirect = indirect ;
160166result -> args .items = (ExtractedNode * * )palloc (2 * sizeof (ExtractedNode * ));
161167result -> args .items [0 ]= leftNode ;
162168result -> args .items [1 ]= rightNode ;
@@ -178,11 +184,12 @@ recursiveExtract(char *jqBase, int32 jqPos, uint32 hash, Entries *e, bool lossy)
178184case jqiNot :
179185read_int32 (arg ,jqBase ,jqPos );
180186Assert (nextPos == 0 );
181- leftNode = recursiveExtract (jqBase ,arg ,hash ,e ,lossy );
187+ leftNode = recursiveExtract (jqBase ,arg ,hash ,e ,lossy , false );
182188if (leftNode )
183189{
184190result = (ExtractedNode * )palloc (sizeof (ExtractedNode ));
185191result -> type = eNot ;
192+ result -> indirect = indirect ;
186193result -> args .items = (ExtractedNode * * )palloc (sizeof (ExtractedNode * ));
187194result -> args .items [0 ]= leftNode ;
188195result -> args .count = 1 ;
@@ -195,32 +202,88 @@ recursiveExtract(char *jqBase, int32 jqPos, uint32 hash, Entries *e, bool lossy)
195202case jqiKey :
196203read_int32 (len ,jqBase ,jqPos );
197204return recursiveExtract (jqBase ,nextPos ,
198- hash |get_bloom_value (hash_any ((unsignedchar * )jqBase + jqPos ,len )),e ,lossy );
205+ hash |get_bloom_value (hash_any ((unsignedchar * )jqBase + jqPos ,len )),e ,lossy , indirect );
199206case jqiAny :
200207Assert (nextPos != 0 );
201- return recursiveExtract (jqBase ,nextPos ,hash ,e , true);
208+ return recursiveExtract (jqBase ,nextPos ,hash ,e , true, true );
202209case jqiAnyArray :
203210Assert (nextPos != 0 );
204- return recursiveExtract (jqBase ,nextPos ,hash ,e ,lossy );
211+ return recursiveExtract (jqBase ,nextPos ,hash ,e ,lossy , true );
205212case jqiEqual :
206213read_int32 (arg ,jqBase ,jqPos );
207214result = (ExtractedNode * )palloc (sizeof (ExtractedNode ));
208- extra = (KeyExtra * )palloc (sizeof (KeyExtra ));
215+ extra = (KeyExtra * )palloc0 (sizeof (KeyExtra ));
209216extra -> hash = hash ;
210217result -> type = eScalar ;
211- arg = readJsQueryHeader (jqBase ,arg ,& type ,& nextPos );
218+ arg = readJsQueryHeader (jqBase ,arg ,& childType ,& nextPos );
212219result -> entryNum = addEntry (e ,
213- PointerGetDatum (make_gin_query_key (jqBase ,arg ,type ,lossy ?0 :hash )),
220+ PointerGetDatum (make_gin_query_key (jqBase ,arg ,childType ,lossy ?0 :hash )),
214221(Pointer )extra ,lossy );
215222return result ;
216223case jqiIn :
224+ case jqiOverlap :
225+ case jqiContains :
226+ read_int32 (arg ,jqBase ,jqPos );
227+ arg = readJsQueryHeader (jqBase ,arg ,& childType ,& nextPos );
228+
229+ read_int32 (nelems ,jqBase ,arg );
230+ arrayPos = (int32 * )(jqBase + arg );
231+
232+ extra = (KeyExtra * )palloc0 (sizeof (KeyExtra ));
233+ extra -> hash = hash ;
234+ result = (ExtractedNode * )palloc (sizeof (ExtractedNode ));
235+ if (type == jqiContains )
236+ result -> type = eAnd ;
237+ else
238+ result -> type = eOr ;
239+ result -> indirect = indirect ;
240+ result -> args .items = (ExtractedNode * * )palloc (nelems * sizeof (ExtractedNode * ));
241+ result -> args .count = 0 ;
242+ for (i = 0 ;i < nelems ;i ++ )
243+ {
244+ ExtractedNode * item ;
245+ item = (ExtractedNode * )palloc (sizeof (ExtractedNode ));
246+ item -> indirect = false;
247+ item -> type = eScalar ;
248+ arg = readJsQueryHeader (jqBase ,arrayPos [i ],& childType ,& nextPos );
249+ item -> entryNum = addEntry (e ,
250+ PointerGetDatum (make_gin_query_key (jqBase ,arg ,childType ,lossy ?0 :hash )),
251+ (Pointer )extra ,lossy );
252+ result -> args .items [result -> args .count ]= item ;
253+ result -> args .count ++ ;
254+ }
255+ return result ;
217256case jqiLess :
218257case jqiGreater :
219258case jqiLessOrEqual :
220259case jqiGreaterOrEqual :
221- case jqiContains :
260+ read_int32 (arg ,jqBase ,jqPos );
261+ result = (ExtractedNode * )palloc (sizeof (ExtractedNode ));
262+ extra = (KeyExtra * )palloc0 (sizeof (KeyExtra ));
263+ extra -> hash = hash ;
264+ extra -> inequality = true;
265+ extra -> lossy = lossy ;
266+ result -> type = eScalar ;
267+ arg = readJsQueryHeader (jqBase ,arg ,& childType ,& nextPos );
268+ if (type == jqiGreater || type == jqiGreaterOrEqual )
269+ {
270+ if (type == jqiGreaterOrEqual )
271+ extra -> leftInclusive = true;
272+ result -> entryNum = addEntry (e ,
273+ PointerGetDatum (make_gin_query_key (jqBase ,arg ,childType ,lossy ?0 :hash )),
274+ (Pointer )extra , true);
275+ }
276+ else
277+ {
278+ if (type == jqiLessOrEqual )
279+ extra -> rightInclusive = true;
280+ result -> entryNum = addEntry (e ,
281+ PointerGetDatum (make_gin_query_key_minus_inf (lossy ?0 :hash )),
282+ (Pointer )extra , true);
283+ extra -> rightBound = make_gin_query_key (jqBase ,arg ,childType ,lossy ?0 :hash );
284+ }
285+ return result ;
222286case jqiContained :
223- case jqiOverlap :
224287return NULL ;
225288default :
226289elog (ERROR ,"Wrong state: %d" ,type );
@@ -354,16 +417,27 @@ make_gin_query_key(char *jqBase, int32 jqPos, int32 type, uint32 hash)
354417return key ;
355418}
356419
420+ static GINKey *
421+ make_gin_query_key_minus_inf (uint32 hash )
422+ {
423+ GINKey * key ;
424+
425+ key = (GINKey * )palloc (GINKEYLEN );
426+ key -> type = jbvNumeric |GINKeyTrue ;
427+ SET_VARSIZE (key ,GINKEYLEN );
428+ return key ;
429+ }
430+
357431static int32
358432compare_gin_key_value (GINKey * arg1 ,GINKey * arg2 )
359433{
360- if (arg1 -> type != arg2 -> type )
434+ if (GINKeyType ( arg1 ) != GINKeyType ( arg2 ) )
361435{
362- return (arg1 -> type > arg2 -> type ) ?1 :-1 ;
436+ return (GINKeyType ( arg1 ) > GINKeyType ( arg2 ) ) ?1 :-1 ;
363437}
364438else
365439{
366- switch (arg1 -> type )
440+ switch (GINKeyType ( arg1 ) )
367441{
368442case jbvNull :
369443return 0 ;
@@ -375,6 +449,18 @@ compare_gin_key_value(GINKey *arg1, GINKey *arg2)
375449else
376450return -1 ;
377451case jbvNumeric :
452+ if (GINKeyIsTrue (arg1 ))
453+ {
454+ if (GINKeyIsTrue (arg2 ))
455+ return 0 ;
456+ else
457+ return -1 ;
458+ }
459+ else
460+ {
461+ if (GINKeyIsTrue (arg2 ))
462+ return 1 ;
463+ }
378464return DatumGetInt32 (DirectFunctionCall2 (numeric_cmp ,
379465PointerGetDatum (GINKeyDataNumeric (arg1 )),
380466PointerGetDatum (GINKeyDataNumeric (arg2 ))));
@@ -400,6 +486,8 @@ gin_compare_jsonb_bloom_value(PG_FUNCTION_ARGS)
400486{
401487result = (arg1 -> hash > arg2 -> hash ) ?1 :-1 ;
402488}
489+ PG_FREE_IF_COPY (arg1 ,0 );
490+ PG_FREE_IF_COPY (arg2 ,1 );
403491PG_RETURN_INT32 (result );
404492}
405493
@@ -410,27 +498,58 @@ gin_compare_partial_jsonb_bloom_value(PG_FUNCTION_ARGS)
410498GINKey * key = (GINKey * )PG_GETARG_VARLENA_P (1 );
411499StrategyNumber strategy = PG_GETARG_UINT16 (2 );
412500int32 result ;
413- uint32 bloom ;
414501
415502if (strategy == JsQueryMatchStrategyNumber )
416503{
417- GINKey * extra_data = (GINKey * )PG_GETARG_POINTER (3 );
418- bloom = extra_data -> hash ;
504+ KeyExtra * extra_data = (KeyExtra * )PG_GETARG_POINTER (3 );
505+
506+ if (extra_data -> inequality )
507+ {
508+ result = 0 ;
509+ if (!extra_data -> leftInclusive && compare_gin_key_value (key ,partial_key ) <=0 )
510+ {
511+ result = -1 ;
512+ }
513+ if (result == 0 && extra_data -> rightBound )
514+ {
515+ result = compare_gin_key_value (key ,extra_data -> rightBound );
516+ if ((extra_data -> rightInclusive && result <=0 )|| result < 0 )
517+ result = 0 ;
518+ else
519+ result = 1 ;
520+ }
521+ if (result == 0 )
522+ {
523+ if ((key -> hash & extra_data -> hash )!= extra_data -> hash )
524+ result = -1 ;
525+ }
526+ }
527+ else
528+ {
529+ result = compare_gin_key_value (key ,partial_key );
530+ if (result == 0 )
531+ {
532+ if ((key -> hash & extra_data -> hash )!= extra_data -> hash )
533+ result = -1 ;
534+ }
535+ }
419536}
420537else
421538{
422539uint32 * extra_data = (uint32 * )PG_GETARG_POINTER (3 );
423- bloom = * extra_data ;
424- }
540+ uint32 bloom = * extra_data ;
425541
426- result = compare_gin_key_value (key ,partial_key );
542+ result = compare_gin_key_value (key ,partial_key );
427543
428- if (result == 0 )
429- {
430- if ((key -> hash & bloom )!= bloom )
431- result = -1 ;
544+ if (result == 0 )
545+ {
546+ if ((key -> hash & bloom )!= bloom )
547+ result = -1 ;
548+ }
432549}
433550
551+ PG_FREE_IF_COPY (partial_key ,0 );
552+ PG_FREE_IF_COPY (key ,1 );
434553PG_RETURN_INT32 (result );
435554}
436555
@@ -563,7 +682,7 @@ gin_extract_jsonb_query_bloom_value(PG_FUNCTION_ARGS)
563682
564683case JsQueryMatchStrategyNumber :
565684jq = PG_GETARG_JSQUERY (0 );
566- root = recursiveExtract (VARDATA (jq ),0 ,0 ,& e , false);
685+ root = recursiveExtract (VARDATA (jq ),0 ,0 ,& e , false, false );
567686
568687* nentries = e .count ;
569688entries = e .entries ;
@@ -741,9 +860,13 @@ gin_triconsistent_jsonb_bloom_value(PG_FUNCTION_ARGS)
741860
742861case JsQueryMatchStrategyNumber :
743862if (nkeys == 0 )
744- res = GIN_TRUE ;
863+ res = GIN_MAYBE ;
745864else
746865res = execRecursiveTristate (((KeyExtra * )extra_data [0 ])-> root ,check );
866+
867+ if (res == GIN_TRUE )
868+ res = GIN_MAYBE ;
869+
747870break ;
748871
749872default :