@@ -56,6 +56,8 @@ static void appendKey(JsonbParseState *pstate, JsonbValue *scalarVal);
56
56
static void appendValue (JsonbParseState * pstate , JsonbValue * scalarVal );
57
57
static void appendElement (JsonbParseState * pstate , JsonbValue * scalarVal );
58
58
static int lengthCompareJsonbStringValue (const void * a , const void * b );
59
+ static int lengthCompareJsonbString (const char * val1 , int len1 ,
60
+ const char * val2 , int len2 );
59
61
static int lengthCompareJsonbPair (const void * a , const void * b , void * arg );
60
62
static void uniqueifyJsonbObject (JsonbValue * object );
61
63
static JsonbValue * pushJsonbValueScalar (JsonbParseState * * pstate ,
@@ -329,18 +331,16 @@ findJsonbValueFromContainer(JsonbContainer *container, uint32 flags,
329
331
{
330
332
JEntry * children = container -> children ;
331
333
int count = JsonContainerSize (container );
332
- JsonbValue * result ;
333
334
334
335
Assert ((flags & ~(JB_FARRAY | JB_FOBJECT )) == 0 );
335
336
336
337
/* Quick out without a palloc cycle if object/array is empty */
337
338
if (count <= 0 )
338
339
return NULL ;
339
340
340
- result = palloc (sizeof (JsonbValue ));
341
-
342
341
if ((flags & JB_FARRAY ) && JsonContainerIsArray (container ))
343
342
{
343
+ JsonbValue * result = palloc (sizeof (JsonbValue ));
344
344
char * base_addr = (char * ) (children + count );
345
345
uint32 offset = 0 ;
346
346
int i ;
@@ -357,56 +357,90 @@ findJsonbValueFromContainer(JsonbContainer *container, uint32 flags,
357
357
358
358
JBE_ADVANCE_OFFSET (offset , children [i ]);
359
359
}
360
+
361
+ pfree (result );
360
362
}
361
363
else if ((flags & JB_FOBJECT ) && JsonContainerIsObject (container ))
362
364
{
363
- /* Since this is an object, account for *Pairs* of Jentrys */
364
- char * base_addr = (char * ) (children + count * 2 );
365
- uint32 stopLow = 0 ,
366
- stopHigh = count ;
367
-
368
365
/* Object key passed by caller must be a string */
369
366
Assert (key -> type == jbvString );
370
367
371
- /* Binary search on object/pair keys *only* */
372
- while (stopLow < stopHigh )
373
- {
374
- uint32 stopMiddle ;
375
- int difference ;
376
- JsonbValue candidate ;
368
+ return getKeyJsonValueFromContainer (container , key -> val .string .val ,
369
+ key -> val .string .len , NULL );
370
+ }
371
+
372
+ /* Not found */
373
+ return NULL ;
374
+ }
375
+
376
+ /*
377
+ * Find value by key in Jsonb object and fetch it into 'res', which is also
378
+ * returned.
379
+ *
380
+ * 'res' can be passed in as NULL, in which case it's newly palloc'ed here.
381
+ */
382
+ JsonbValue *
383
+ getKeyJsonValueFromContainer (JsonbContainer * container ,
384
+ const char * keyVal , int keyLen , JsonbValue * res )
385
+ {
386
+ JEntry * children = container -> children ;
387
+ int count = JsonContainerSize (container );
388
+ char * baseAddr ;
389
+ uint32 stopLow ,
390
+ stopHigh ;
377
391
378
- stopMiddle = stopLow + ( stopHigh - stopLow ) / 2 ;
392
+ Assert ( JsonContainerIsObject ( container )) ;
379
393
380
- candidate .type = jbvString ;
381
- candidate .val .string .val =
382
- base_addr + getJsonbOffset (container , stopMiddle );
383
- candidate .val .string .len = getJsonbLength (container , stopMiddle );
394
+ /* Quick out without a palloc cycle if object is empty */
395
+ if (count <= 0 )
396
+ return NULL ;
384
397
385
- difference = lengthCompareJsonbStringValue (& candidate , key );
398
+ /*
399
+ * Binary search the container. Since we know this is an object, account
400
+ * for *Pairs* of Jentrys
401
+ */
402
+ baseAddr = (char * ) (children + count * 2 );
403
+ stopLow = 0 ;
404
+ stopHigh = count ;
405
+ while (stopLow < stopHigh )
406
+ {
407
+ uint32 stopMiddle ;
408
+ int difference ;
409
+ const char * candidateVal ;
410
+ int candidateLen ;
386
411
387
- if (difference == 0 )
388
- {
389
- /* Found our key, return corresponding value */
390
- int index = stopMiddle + count ;
412
+ stopMiddle = stopLow + (stopHigh - stopLow ) / 2 ;
391
413
392
- fillJsonbValue (container , index , base_addr ,
393
- getJsonbOffset (container , index ),
394
- result );
414
+ candidateVal = baseAddr + getJsonbOffset (container , stopMiddle );
415
+ candidateLen = getJsonbLength (container , stopMiddle );
395
416
396
- return result ;
397
- }
417
+ difference = lengthCompareJsonbString (candidateVal , candidateLen ,
418
+ keyVal , keyLen );
419
+
420
+ if (difference == 0 )
421
+ {
422
+ /* Found our key, return corresponding value */
423
+ int index = stopMiddle + count ;
424
+
425
+ if (!res )
426
+ res = palloc (sizeof (JsonbValue ));
427
+
428
+ fillJsonbValue (container , index , baseAddr ,
429
+ getJsonbOffset (container , index ),
430
+ res );
431
+
432
+ return res ;
433
+ }
434
+ else
435
+ {
436
+ if (difference < 0 )
437
+ stopLow = stopMiddle + 1 ;
398
438
else
399
- {
400
- if (difference < 0 )
401
- stopLow = stopMiddle + 1 ;
402
- else
403
- stopHigh = stopMiddle ;
404
- }
439
+ stopHigh = stopMiddle ;
405
440
}
406
441
}
407
442
408
443
/* Not found */
409
- pfree (result );
410
444
return NULL ;
411
445
}
412
446
@@ -1009,6 +1043,7 @@ JsonbDeepContains(JsonbIterator **val, JsonbIterator **mContained)
1009
1043
for (;;)
1010
1044
{
1011
1045
JsonbValue * lhsVal ; /* lhsVal is from pair in lhs object */
1046
+ JsonbValue lhsValBuf ;
1012
1047
1013
1048
rcont = JsonbIteratorNext (mContained , & vcontained , false);
1014
1049
@@ -1021,12 +1056,14 @@ JsonbDeepContains(JsonbIterator **val, JsonbIterator **mContained)
1021
1056
return true;
1022
1057
1023
1058
Assert (rcont == WJB_KEY );
1059
+ Assert (vcontained .type == jbvString );
1024
1060
1025
1061
/* First, find value by key... */
1026
- lhsVal = findJsonbValueFromContainer ((* val )-> container ,
1027
- JB_FOBJECT ,
1028
- & vcontained );
1029
-
1062
+ lhsVal =
1063
+ getKeyJsonValueFromContainer ((* val )-> container ,
1064
+ vcontained .val .string .val ,
1065
+ vcontained .val .string .len ,
1066
+ & lhsValBuf );
1030
1067
if (!lhsVal )
1031
1068
return false;
1032
1069
@@ -1771,21 +1808,27 @@ lengthCompareJsonbStringValue(const void *a, const void *b)
1771
1808
{
1772
1809
const JsonbValue * va = (const JsonbValue * ) a ;
1773
1810
const JsonbValue * vb = (const JsonbValue * ) b ;
1774
- int res ;
1775
1811
1776
1812
Assert (va -> type == jbvString );
1777
1813
Assert (vb -> type == jbvString );
1778
1814
1779
- if (va -> val .string .len == vb -> val .string .len )
1780
- {
1781
- res = memcmp (va -> val .string .val , vb -> val .string .val , va -> val .string .len );
1782
- }
1783
- else
1784
- {
1785
- res = (va -> val .string .len > vb -> val .string .len ) ? 1 : -1 ;
1786
- }
1815
+ return lengthCompareJsonbString (va -> val .string .val , va -> val .string .len ,
1816
+ vb -> val .string .val , vb -> val .string .len );
1817
+ }
1787
1818
1788
- return res ;
1819
+ /*
1820
+ * Subroutine for lengthCompareJsonbStringValue
1821
+ *
1822
+ * This is also useful separately to implement binary search on
1823
+ * JsonbContainers.
1824
+ */
1825
+ static int
1826
+ lengthCompareJsonbString (const char * val1 , int len1 , const char * val2 , int len2 )
1827
+ {
1828
+ if (len1 == len2 )
1829
+ return memcmp (val1 , val2 , len1 );
1830
+ else
1831
+ return len1 > len2 ? 1 : -1 ;
1789
1832
}
1790
1833
1791
1834
/*
0 commit comments