Skip to content

Commit d9c6f23

Browse files
committed
Fixes and more query support.
1 parent 314abc3 commit d9c6f23

File tree

1 file changed

+153
-30
lines changed

1 file changed

+153
-30
lines changed

jsonb_ops.c

Lines changed: 153 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ typedef struct ExtractedNode ExtractedNode;
5353
struct ExtractedNode
5454
{
5555
ExtractedNodeType type;
56+
bool indirect;
5657
union
5758
{
5859
struct
@@ -76,15 +77,19 @@ typedef struct
7677
{
7778
ExtractedNode *root;
7879
uint32 hash;
80+
bool lossy;
81+
bool inequality, leftInclusive, rightInclusive;
82+
GINKey *rightBound;
7983
} KeyExtra;
8084

8185
static uint32 get_bloom_value(uint32 hash);
8286
static uint32 get_path_bloom(PathHashStack *stack);
8387
static GINKey *make_gin_key(JsonbValue *v, uint32 hash);
8488
static GINKey *make_gin_query_key(char *jqBase, int32 jqPos, int32 type, uint32 hash);
89+
static GINKey *make_gin_query_key_minus_inf(uint32 hash);
8590
static int32 compare_gin_key_value(GINKey *arg1, GINKey *arg2);
8691
static 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

8994
PG_FUNCTION_INFO_V1(gin_compare_jsonb_bloom_value);
9095
PG_FUNCTION_INFO_V1(gin_compare_partial_jsonb_bloom_value);
@@ -127,13 +132,13 @@ addEntry(Entries *e, Datum key, Pointer extra, bool pmatch)
127132
}
128133

129134
static 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;
133138
int32 nextPos;
134139
int32 left, right, arg;
135140
ExtractedNode *leftNode, *rightNode, *result;
136-
int32 len;
141+
int32 len, *arrayPos, nelems, i;
137142
KeyExtra *extra;
138143

139144
check_stack_depth();
@@ -146,8 +151,8 @@ recursiveExtract(char *jqBase, int32 jqPos, uint32 hash, Entries *e, bool lossy)
146151
read_int32(left, jqBase, jqPos);
147152
read_int32(right, jqBase, jqPos);
148153
Assert(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);
151156
if (leftNode)
152157
{
153158
if (rightNode)
@@ -157,6 +162,7 @@ recursiveExtract(char *jqBase, int32 jqPos, uint32 hash, Entries *e, bool lossy)
157162
result->type = eAnd;
158163
else if (type == jqiOr)
159164
result->type = eOr;
165+
result->indirect = indirect;
160166
result->args.items = (ExtractedNode **)palloc(2 * sizeof(ExtractedNode *));
161167
result->args.items[0] = leftNode;
162168
result->args.items[1] = rightNode;
@@ -178,11 +184,12 @@ recursiveExtract(char *jqBase, int32 jqPos, uint32 hash, Entries *e, bool lossy)
178184
case jqiNot:
179185
read_int32(arg, jqBase, jqPos);
180186
Assert(nextPos == 0);
181-
leftNode = recursiveExtract(jqBase, arg, hash, e, lossy);
187+
leftNode = recursiveExtract(jqBase, arg, hash, e, lossy, false);
182188
if (leftNode)
183189
{
184190
result = (ExtractedNode *)palloc(sizeof(ExtractedNode));
185191
result->type = eNot;
192+
result->indirect = indirect;
186193
result->args.items = (ExtractedNode **)palloc(sizeof(ExtractedNode *));
187194
result->args.items[0] = leftNode;
188195
result->args.count = 1;
@@ -195,32 +202,88 @@ recursiveExtract(char *jqBase, int32 jqPos, uint32 hash, Entries *e, bool lossy)
195202
case jqiKey:
196203
read_int32(len, jqBase, jqPos);
197204
return recursiveExtract(jqBase, nextPos,
198-
hash | get_bloom_value(hash_any((unsigned char *)jqBase + jqPos, len)), e, lossy);
205+
hash | get_bloom_value(hash_any((unsigned char *)jqBase + jqPos, len)), e, lossy, indirect);
199206
case jqiAny:
200207
Assert(nextPos != 0);
201-
return recursiveExtract(jqBase, nextPos, hash, e, true);
208+
return recursiveExtract(jqBase, nextPos, hash, e, true, true);
202209
case jqiAnyArray:
203210
Assert(nextPos != 0);
204-
return recursiveExtract(jqBase, nextPos, hash, e, lossy);
211+
return recursiveExtract(jqBase, nextPos, hash, e, lossy, true);
205212
case jqiEqual:
206213
read_int32(arg, jqBase, jqPos);
207214
result = (ExtractedNode *)palloc(sizeof(ExtractedNode));
208-
extra = (KeyExtra *)palloc(sizeof(KeyExtra));
215+
extra = (KeyExtra *)palloc0(sizeof(KeyExtra));
209216
extra->hash = hash;
210217
result->type = eScalar;
211-
arg = readJsQueryHeader(jqBase, arg, &type, &nextPos);
218+
arg = readJsQueryHeader(jqBase, arg, &childType, &nextPos);
212219
result->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);
215222
return result;
216223
case 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;
217256
case jqiLess:
218257
case jqiGreater:
219258
case jqiLessOrEqual:
220259
case 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;
222286
case jqiContained:
223-
case jqiOverlap:
224287
return NULL;
225288
default:
226289
elog(ERROR,"Wrong state: %d", type);
@@ -354,16 +417,27 @@ make_gin_query_key(char *jqBase, int32 jqPos, int32 type, uint32 hash)
354417
return 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+
357431
static int32
358432
compare_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
}
364438
else
365439
{
366-
switch(arg1->type)
440+
switch(GINKeyType(arg1))
367441
{
368442
case jbvNull:
369443
return 0;
@@ -375,6 +449,18 @@ compare_gin_key_value(GINKey *arg1, GINKey *arg2)
375449
else
376450
return -1;
377451
case 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+
}
378464
return DatumGetInt32(DirectFunctionCall2(numeric_cmp,
379465
PointerGetDatum(GINKeyDataNumeric(arg1)),
380466
PointerGetDatum(GINKeyDataNumeric(arg2))));
@@ -400,6 +486,8 @@ gin_compare_jsonb_bloom_value(PG_FUNCTION_ARGS)
400486
{
401487
result = (arg1->hash > arg2->hash) ? 1 : -1;
402488
}
489+
PG_FREE_IF_COPY(arg1, 0);
490+
PG_FREE_IF_COPY(arg2, 1);
403491
PG_RETURN_INT32(result);
404492
}
405493

@@ -410,27 +498,58 @@ gin_compare_partial_jsonb_bloom_value(PG_FUNCTION_ARGS)
410498
GINKey *key = (GINKey *)PG_GETARG_VARLENA_P(1);
411499
StrategyNumber strategy = PG_GETARG_UINT16(2);
412500
int32 result;
413-
uint32 bloom;
414501

415502
if (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
}
420537
else
421538
{
422539
uint32 *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);
434553
PG_RETURN_INT32(result);
435554
}
436555

@@ -563,7 +682,7 @@ gin_extract_jsonb_query_bloom_value(PG_FUNCTION_ARGS)
563682

564683
case JsQueryMatchStrategyNumber:
565684
jq = 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;
569688
entries = e.entries;
@@ -741,9 +860,13 @@ gin_triconsistent_jsonb_bloom_value(PG_FUNCTION_ARGS)
741860

742861
case JsQueryMatchStrategyNumber:
743862
if (nkeys == 0)
744-
res = GIN_TRUE;
863+
res = GIN_MAYBE;
745864
else
746865
res = execRecursiveTristate(((KeyExtra *)extra_data[0])->root, check);
866+
867+
if (res == GIN_TRUE)
868+
res = GIN_MAYBE;
869+
747870
break;
748871

749872
default:

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