@@ -56,6 +56,8 @@ static void appendKey(JsonbParseState *pstate, JsonbValue *scalarVal);
5656static void appendValue (JsonbParseState * pstate , JsonbValue * scalarVal );
5757static void appendElement (JsonbParseState * pstate , JsonbValue * scalarVal );
5858static int lengthCompareJsonbStringValue (const void * a , const void * b );
59+ static int lengthCompareJsonbString (const char * val1 , int len1 ,
60+ const char * val2 , int len2 );
5961static int lengthCompareJsonbPair (const void * a , const void * b , void * arg );
6062static void uniqueifyJsonbObject (JsonbValue * object );
6163static JsonbValue * pushJsonbValueScalar (JsonbParseState * * pstate ,
@@ -329,18 +331,16 @@ findJsonbValueFromContainer(JsonbContainer *container, uint32 flags,
329331{
330332 JEntry * children = container -> children ;
331333 int count = JsonContainerSize (container );
332- JsonbValue * result ;
333334
334335 Assert ((flags & ~(JB_FARRAY | JB_FOBJECT )) == 0 );
335336
336337 /* Quick out without a palloc cycle if object/array is empty */
337338 if (count <= 0 )
338339 return NULL ;
339340
340- result = palloc (sizeof (JsonbValue ));
341-
342341 if ((flags & JB_FARRAY ) && JsonContainerIsArray (container ))
343342 {
343+ JsonbValue * result = palloc (sizeof (JsonbValue ));
344344 char * base_addr = (char * ) (children + count );
345345 uint32 offset = 0 ;
346346 int i ;
@@ -357,56 +357,90 @@ findJsonbValueFromContainer(JsonbContainer *container, uint32 flags,
357357
358358 JBE_ADVANCE_OFFSET (offset , children [i ]);
359359 }
360+
361+ pfree (result );
360362 }
361363 else if ((flags & JB_FOBJECT ) && JsonContainerIsObject (container ))
362364 {
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-
368365 /* Object key passed by caller must be a string */
369366 Assert (key -> type == jbvString );
370367
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 ;
377391
378- stopMiddle = stopLow + ( stopHigh - stopLow ) / 2 ;
392+ Assert ( JsonContainerIsObject ( container )) ;
379393
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 ;
384397
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 ;
386411
387- if (difference == 0 )
388- {
389- /* Found our key, return corresponding value */
390- int index = stopMiddle + count ;
412+ stopMiddle = stopLow + (stopHigh - stopLow ) / 2 ;
391413
392- fillJsonbValue (container , index , base_addr ,
393- getJsonbOffset (container , index ),
394- result );
414+ candidateVal = baseAddr + getJsonbOffset (container , stopMiddle );
415+ candidateLen = getJsonbLength (container , stopMiddle );
395416
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 ;
398438 else
399- {
400- if (difference < 0 )
401- stopLow = stopMiddle + 1 ;
402- else
403- stopHigh = stopMiddle ;
404- }
439+ stopHigh = stopMiddle ;
405440 }
406441 }
407442
408443 /* Not found */
409- pfree (result );
410444 return NULL ;
411445}
412446
@@ -1009,6 +1043,7 @@ JsonbDeepContains(JsonbIterator **val, JsonbIterator **mContained)
10091043 for (;;)
10101044 {
10111045 JsonbValue * lhsVal ; /* lhsVal is from pair in lhs object */
1046+ JsonbValue lhsValBuf ;
10121047
10131048 rcont = JsonbIteratorNext (mContained , & vcontained , false);
10141049
@@ -1021,12 +1056,14 @@ JsonbDeepContains(JsonbIterator **val, JsonbIterator **mContained)
10211056 return true;
10221057
10231058 Assert (rcont == WJB_KEY );
1059+ Assert (vcontained .type == jbvString );
10241060
10251061 /* 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 );
10301067 if (!lhsVal )
10311068 return false;
10321069
@@ -1771,21 +1808,27 @@ lengthCompareJsonbStringValue(const void *a, const void *b)
17711808{
17721809 const JsonbValue * va = (const JsonbValue * ) a ;
17731810 const JsonbValue * vb = (const JsonbValue * ) b ;
1774- int res ;
17751811
17761812 Assert (va -> type == jbvString );
17771813 Assert (vb -> type == jbvString );
17781814
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+ }
17871818
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 ;
17891832}
17901833
17911834/*
0 commit comments