@@ -325,6 +325,131 @@ compareJsonbContainers(JsonbContainer *a, JsonbContainer *b)
325325return res ;
326326}
327327
328+ static JsonbValue *
329+ jsonbFindKeyInObject (const JsonbContainer * container ,const JsonbValue * key )
330+ {
331+ /* Since this is an object, account for *Pairs* of Jentrys */
332+ const JEntry * children = container -> children ;
333+ int count = (container -> header & JB_CMASK );
334+ char * base_addr = (char * ) (children + count * 2 );
335+ uint32 stopLow = 0 ,
336+ stopHigh = count ;
337+
338+ /* Object key passed by caller must be a string */
339+ Assert (key -> type == jbvString );
340+
341+ /* Binary search on object/pair keys *only* */
342+ while (stopLow < stopHigh )
343+ {
344+ uint32 stopMiddle ;
345+ int difference ;
346+ JsonbValue candidate ;
347+
348+ stopMiddle = stopLow + (stopHigh - stopLow ) /2 ;
349+
350+ candidate .type = jbvString ;
351+ candidate .val .string .val =
352+ base_addr + getJsonbOffset (container ,stopMiddle );
353+ candidate .val .string .len = getJsonbLength (container ,stopMiddle );
354+
355+ difference = lengthCompareJsonbStringValue (& candidate ,key );
356+
357+ if (difference == 0 )
358+ {
359+ /* Found our key, return corresponding value */
360+ JsonbValue * result = palloc (sizeof (JsonbValue ));
361+ int index = stopMiddle + count ;
362+
363+ fillJsonbValue (container ,index ,base_addr ,
364+ getJsonbOffset (container ,index ),
365+ result );
366+
367+ return result ;
368+ }
369+ else
370+ {
371+ if (difference < 0 )
372+ stopLow = stopMiddle + 1 ;
373+ else
374+ stopHigh = stopMiddle ;
375+ }
376+ }
377+
378+ return NULL ;
379+ }
380+
381+ typedef struct JsonbArrayIterator
382+ {
383+ const JsonbContainer * container ;
384+ char * base_addr ;
385+ int index ;
386+ int count ;
387+ uint32 offset ;
388+ }JsonbArrayIterator ;
389+
390+ static void
391+ JsonbArrayIteratorInit (JsonbArrayIterator * it ,const JsonbContainer * container )
392+ {
393+ it -> container = container ;
394+ it -> index = 0 ;
395+ it -> count = (container -> header & JB_CMASK );
396+ it -> offset = 0 ;
397+ it -> base_addr = (char * ) (container -> children + it -> count );
398+ }
399+
400+ static bool
401+ JsonbArrayIteratorNext (JsonbArrayIterator * it ,JsonbValue * result )
402+ {
403+ if (it -> index >=it -> count )
404+ return false;
405+
406+ fillJsonbValue (it -> container ,it -> index ,it -> base_addr ,it -> offset ,result );
407+
408+ JBE_ADVANCE_OFFSET (it -> offset ,it -> container -> children [it -> index ]);
409+
410+ it -> index ++ ;
411+
412+ return true;
413+ }
414+
415+ static JsonbValue *
416+ JsonbArrayIteratorGetIth (JsonbArrayIterator * it ,uint32 i )
417+ {
418+ JsonbValue * result ;
419+
420+ if (i >=it -> count )
421+ return NULL ;
422+
423+ result = palloc (sizeof (JsonbValue ));
424+
425+ fillJsonbValue (it -> container ,i ,it -> base_addr ,
426+ getJsonbOffset (it -> container ,i ),
427+ result );
428+
429+ return result ;
430+ }
431+
432+ static JsonbValue *
433+ jsonbFindValueInArray (const JsonbContainer * container ,const JsonbValue * key )
434+ {
435+ JsonbArrayIterator it ;
436+ JsonbValue * result = palloc (sizeof (JsonbValue ));
437+
438+ JsonbArrayIteratorInit (& it ,container );
439+
440+ while (JsonbArrayIteratorNext (& it ,result ))
441+ {
442+ if (key -> type == result -> type )
443+ {
444+ if (equalsJsonbScalarValue (key ,result ))
445+ return result ;
446+ }
447+ }
448+
449+ pfree (result );
450+ return NULL ;
451+ }
452+
328453/*
329454 * Find value in object (i.e. the "value" part of some key/value pair in an
330455 * object), or find a matching element if we're looking through an array. Do
@@ -352,89 +477,24 @@ compareJsonbContainers(JsonbContainer *a, JsonbContainer *b)
352477 * return NULL. Otherwise, return palloc()'d copy of value.
353478 */
354479JsonbValue *
355- findJsonbValueFromContainer (JsonbContainer * container ,uint32 flags ,
480+ findJsonbValueFromContainer (const JsonbContainer * container ,uint32 flags ,
356481JsonbValue * key )
357482{
358- JEntry * children = container -> children ;
359483int count = JsonContainerSize (container );
360- JsonbValue * result ;
361484
362485Assert ((flags & ~(JB_FARRAY |JB_FOBJECT ))== 0 );
363486
364487/* Quick out without a palloc cycle if object/array is empty */
365488if (count <=0 )
366489return NULL ;
367490
368- result = palloc (sizeof (JsonbValue ));
369-
370491if ((flags & JB_FARRAY )&& JsonContainerIsArray (container ))
371- {
372- char * base_addr = (char * ) (children + count );
373- uint32 offset = 0 ;
374- int i ;
375-
376- for (i = 0 ;i < count ;i ++ )
377- {
378- fillJsonbValue (container ,i ,base_addr ,offset ,result );
379-
380- if (key -> type == result -> type )
381- {
382- if (equalsJsonbScalarValue (key ,result ))
383- return result ;
384- }
385-
386- JBE_ADVANCE_OFFSET (offset ,children [i ]);
387- }
388- }
389- else if ((flags & JB_FOBJECT )&& JsonContainerIsObject (container ))
390- {
391- /* Since this is an object, account for *Pairs* of Jentrys */
392- char * base_addr = (char * ) (children + count * 2 );
393- uint32 stopLow = 0 ,
394- stopHigh = count ;
395-
396- /* Object key passed by caller must be a string */
397- Assert (key -> type == jbvString );
398-
399- /* Binary search on object/pair keys *only* */
400- while (stopLow < stopHigh )
401- {
402- uint32 stopMiddle ;
403- int difference ;
404- JsonbValue candidate ;
405-
406- stopMiddle = stopLow + (stopHigh - stopLow ) /2 ;
407-
408- candidate .type = jbvString ;
409- candidate .val .string .val =
410- base_addr + getJsonbOffset (container ,stopMiddle );
411- candidate .val .string .len = getJsonbLength (container ,stopMiddle );
412-
413- difference = lengthCompareJsonbStringValue (& candidate ,key );
414-
415- if (difference == 0 )
416- {
417- /* Found our key, return corresponding value */
418- int index = stopMiddle + count ;
419-
420- fillJsonbValue (container ,index ,base_addr ,
421- getJsonbOffset (container ,index ),
422- result );
492+ return jsonbFindValueInArray (container ,key );
423493
424- return result ;
425- }
426- else
427- {
428- if (difference < 0 )
429- stopLow = stopMiddle + 1 ;
430- else
431- stopHigh = stopMiddle ;
432- }
433- }
434- }
494+ if ((flags & JB_FOBJECT )&& JsonContainerIsObject (container ))
495+ return jsonbFindKeyInObject (container ,key );
435496
436497/* Not found */
437- pfree (result );
438498return NULL ;
439499}
440500
@@ -446,26 +506,14 @@ findJsonbValueFromContainer(JsonbContainer *container, uint32 flags,
446506JsonbValue *
447507getIthJsonbValueFromContainer (JsonbContainer * container ,uint32 i )
448508{
449- JsonbValue * result ;
450- char * base_addr ;
451- uint32 nelements ;
509+ JsonbArrayIterator it ;
452510
453511if (!JsonContainerIsArray (container ))
454512elog (ERROR ,"not a jsonb array" );
455513
456- nelements = JsonContainerSize (container );
457- base_addr = (char * )& container -> children [nelements ];
514+ JsonbArrayIteratorInit (& it ,container );
458515
459- if (i >=nelements )
460- return NULL ;
461-
462- result = palloc (sizeof (JsonbValue ));
463-
464- fillJsonbValue (container ,i ,base_addr ,
465- getJsonbOffset (container ,i ),
466- result );
467-
468- return result ;
516+ return JsonbArrayIteratorGetIth (& it ,i );
469517}
470518
471519/*
@@ -596,7 +644,7 @@ pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq,
596644 * Do the actual pushing, with only scalar or pseudo-scalar-array values
597645 * accepted.
598646 */
599- static JsonbValue *
647+ JsonbValue *
600648pushJsonbValueScalar (JsonbParseState * * pstate ,JsonbIteratorToken seq ,
601649const JsonbValue * scalarVal )
602650{