Skip to content

Commit fcf30ec

Browse files
author
Nikita Glukhov
committed
Extract jsonbFindKeyInObject(), jsonbFindValueInArray(), JsonbArrayIterator
1 parent c1b6a48 commit fcf30ec

File tree

1 file changed

+133
-85
lines changed

1 file changed

+133
-85
lines changed

src/backend/utils/adt/jsonb_util.c

Lines changed: 133 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,131 @@ compareJsonbContainers(JsonbContainer *a, JsonbContainer *b)
325325
return 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
*/
354479
JsonbValue *
355-
findJsonbValueFromContainer(JsonbContainer *container, uint32 flags,
480+
findJsonbValueFromContainer(const JsonbContainer *container, uint32 flags,
356481
JsonbValue *key)
357482
{
358-
JEntry *children = container->children;
359483
int count = JsonContainerSize(container);
360-
JsonbValue *result;
361484

362485
Assert((flags & ~(JB_FARRAY | JB_FOBJECT)) == 0);
363486

364487
/* Quick out without a palloc cycle if object/array is empty */
365488
if (count <= 0)
366489
return NULL;
367490

368-
result = palloc(sizeof(JsonbValue));
369-
370491
if ((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);
438498
return NULL;
439499
}
440500

@@ -446,26 +506,14 @@ findJsonbValueFromContainer(JsonbContainer *container, uint32 flags,
446506
JsonbValue *
447507
getIthJsonbValueFromContainer(JsonbContainer *container, uint32 i)
448508
{
449-
JsonbValue *result;
450-
char *base_addr;
451-
uint32 nelements;
509+
JsonbArrayIterator it;
452510

453511
if (!JsonContainerIsArray(container))
454512
elog(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 *
600648
pushJsonbValueScalar(JsonbParseState **pstate, JsonbIteratorToken seq,
601649
const JsonbValue *scalarVal)
602650
{

0 commit comments

Comments
 (0)