Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1a29832

Browse filesBrowse files
committed
Split out code into new getKeyJsonValueFromContainer()
The new function stashes its output value in a JsonbValue that can be passed in by the caller, which enables some of them to pass stack-allocated structs -- saving palloc cycles. It also allows some callers that know they are handling a jsonb object to use this new jsonb object-specific API, instead of going through generic container findJsonbValueFromContainer. Author: Nikita Glukhov Discussion: https://postgr.es/m/7c417f90-f95f-247e-ba63-d95e39c0ad14@postgrespro.ru
1 parent dbb9aed commit 1a29832
Copy full SHA for 1a29832

File tree

Expand file treeCollapse file tree

3 files changed

+113
-85
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+113
-85
lines changed

‎src/backend/utils/adt/jsonb_util.c

Copy file name to clipboardExpand all lines: src/backend/utils/adt/jsonb_util.c
+93-50Lines changed: 93 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ static void appendKey(JsonbParseState *pstate, JsonbValue *scalarVal);
5656
static void appendValue(JsonbParseState *pstate, JsonbValue *scalarVal);
5757
static void appendElement(JsonbParseState *pstate, JsonbValue *scalarVal);
5858
static int lengthCompareJsonbStringValue(const void *a, const void *b);
59+
static int lengthCompareJsonbString(const char *val1, int len1,
60+
const char *val2, int len2);
5961
static int lengthCompareJsonbPair(const void *a, const void *b, void *arg);
6062
static void uniqueifyJsonbObject(JsonbValue *object);
6163
static 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
/*

‎src/backend/utils/adt/jsonfuncs.c

Copy file name to clipboardExpand all lines: src/backend/utils/adt/jsonfuncs.c
+17-35Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -454,12 +454,6 @@ static Datum populate_array(ArrayIOData *aio, const char *colname,
454454
static Datum populate_domain(DomainIOData *io, Oid typid, const char *colname,
455455
MemoryContext mcxt, JsValue *jsv, bool isnull);
456456

457-
/* Worker that takes care of common setup for us */
458-
static JsonbValue *findJsonbValueFromContainerLen(JsonbContainer *container,
459-
uint32 flags,
460-
char *key,
461-
uint32 keylen);
462-
463457
/* functions supporting jsonb_delete, jsonb_set and jsonb_concat */
464458
static JsonbValue *IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
465459
JsonbParseState **state);
@@ -718,13 +712,15 @@ jsonb_object_field(PG_FUNCTION_ARGS)
718712
Jsonb *jb = PG_GETARG_JSONB_P(0);
719713
text *key = PG_GETARG_TEXT_PP(1);
720714
JsonbValue *v;
715+
JsonbValue vbuf;
721716

722717
if (!JB_ROOT_IS_OBJECT(jb))
723718
PG_RETURN_NULL();
724719

725-
v = findJsonbValueFromContainerLen(&jb->root, JB_FOBJECT,
726-
VARDATA_ANY(key),
727-
VARSIZE_ANY_EXHDR(key));
720+
v = getKeyJsonValueFromContainer(&jb->root,
721+
VARDATA_ANY(key),
722+
VARSIZE_ANY_EXHDR(key),
723+
&vbuf);
728724

729725
if (v != NULL)
730726
PG_RETURN_JSONB_P(JsonbValueToJsonb(v));
@@ -754,14 +750,15 @@ jsonb_object_field_text(PG_FUNCTION_ARGS)
754750
Jsonb *jb = PG_GETARG_JSONB_P(0);
755751
text *key = PG_GETARG_TEXT_PP(1);
756752
JsonbValue *v;
753+
JsonbValue vbuf;
757754

758755
if (!JB_ROOT_IS_OBJECT(jb))
759756
PG_RETURN_NULL();
760757

761-
v = findJsonbValueFromContainerLen(&jb->root, JB_FOBJECT,
762-
VARDATA_ANY(key),
763-
VARSIZE_ANY_EXHDR(key));
764-
758+
v = getKeyJsonValueFromContainer(&jb->root,
759+
VARDATA_ANY(key),
760+
VARSIZE_ANY_EXHDR(key),
761+
&vbuf);
765762

766763
if (v != NULL && v->type != jbvNull)
767764
PG_RETURN_TEXT_P(JsonbValueAsText(v));
@@ -1336,6 +1333,7 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
13361333
bool have_object = false,
13371334
have_array = false;
13381335
JsonbValue *jbvp = NULL;
1336+
JsonbValue jbvbuf;
13391337
JsonbContainer *container;
13401338

13411339
/*
@@ -1393,10 +1391,10 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
13931391
{
13941392
if (have_object)
13951393
{
1396-
jbvp = findJsonbValueFromContainerLen(container,
1397-
JB_FOBJECT,
1398-
VARDATA(pathtext[i]),
1399-
VARSIZE(pathtext[i]) - VARHDRSZ);
1394+
jbvp = getKeyJsonValueFromContainer(container,
1395+
VARDATA(pathtext[i]),
1396+
VARSIZE(pathtext[i]) - VARHDRSZ,
1397+
&jbvbuf);
14001398
}
14011399
else if (have_array)
14021400
{
@@ -3023,8 +3021,8 @@ JsObjectGetField(JsObject *obj, char *field, JsValue *jsv)
30233021
else
30243022
{
30253023
jsv->val.jsonb = !obj->val.jsonb_cont ? NULL :
3026-
findJsonbValueFromContainerLen(obj->val.jsonb_cont, JB_FOBJECT,
3027-
field, strlen(field));
3024+
getKeyJsonValueFromContainer(obj->val.jsonb_cont, field, strlen(field),
3025+
NULL);
30283026

30293027
return jsv->val.jsonb != NULL;
30303028
}
@@ -3848,22 +3846,6 @@ populate_recordset_object_field_end(void *state, char *fname, bool isnull)
38483846
}
38493847
}
38503848

3851-
/*
3852-
* findJsonbValueFromContainer() wrapper that sets up JsonbValue key string.
3853-
*/
3854-
static JsonbValue *
3855-
findJsonbValueFromContainerLen(JsonbContainer *container, uint32 flags,
3856-
char *key, uint32 keylen)
3857-
{
3858-
JsonbValue k;
3859-
3860-
k.type = jbvString;
3861-
k.val.string.val = key;
3862-
k.val.string.len = keylen;
3863-
3864-
return findJsonbValueFromContainer(container, flags, &k);
3865-
}
3866-
38673849
/*
38683850
* Semantic actions for json_strip_nulls.
38693851
*

‎src/include/utils/jsonb.h

Copy file name to clipboardExpand all lines: src/include/utils/jsonb.h
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,9 @@ extern int compareJsonbContainers(JsonbContainer *a, JsonbContainer *b);
364364
extern JsonbValue *findJsonbValueFromContainer(JsonbContainer *sheader,
365365
uint32 flags,
366366
JsonbValue *key);
367+
extern JsonbValue *getKeyJsonValueFromContainer(JsonbContainer *container,
368+
const char *keyVal, int keyLen,
369+
JsonbValue *res);
367370
extern JsonbValue *getIthJsonbValueFromContainer(JsonbContainer *sheader,
368371
uint32 i);
369372
extern JsonbValue *pushJsonbValue(JsonbParseState **pstate,

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.