Skip to content

Commit 611cdfe

Browse files
author
Nikita Glukhov
committed
Refactor JsonbDeepContains()
1 parent f8d860b commit 611cdfe

File tree

3 files changed

+83
-111
lines changed

3 files changed

+83
-111
lines changed

src/backend/utils/adt/jsonb_op.c

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -114,16 +114,10 @@ jsonb_contains(PG_FUNCTION_ARGS)
114114
Jsonb *val = PG_GETARG_JSONB_P(0);
115115
Jsonb *tmpl = PG_GETARG_JSONB_P(1);
116116

117-
JsonbIterator *it1,
118-
*it2;
119-
120117
if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl))
121118
PG_RETURN_BOOL(false);
122119

123-
it1 = JsonbIteratorInit(&val->root);
124-
it2 = JsonbIteratorInit(&tmpl->root);
125-
126-
PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
120+
PG_RETURN_BOOL(JsonbDeepContains(JsonRoot(val), JsonRoot(tmpl)));
127121
}
128122

129123
Datum
@@ -133,16 +127,10 @@ jsonb_contained(PG_FUNCTION_ARGS)
133127
Jsonb *tmpl = PG_GETARG_JSONB_P(0);
134128
Jsonb *val = PG_GETARG_JSONB_P(1);
135129

136-
JsonbIterator *it1,
137-
*it2;
138-
139130
if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl))
140131
PG_RETURN_BOOL(false);
141132

142-
it1 = JsonbIteratorInit(&val->root);
143-
it2 = JsonbIteratorInit(&tmpl->root);
144-
145-
PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
133+
PG_RETURN_BOOL(JsonbDeepContains(JsonRoot(val), JsonRoot(tmpl)));
146134
}
147135

148136
Datum

src/backend/utils/adt/jsonb_util.c

Lines changed: 80 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,12 +1244,11 @@ jsonbIteratorInit(JsonContainer *cont)
12441244
*/
12451245

12461246
bool
1247-
JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
1247+
JsonbDeepContains(JsonContainer *cval, JsonContainer *ccont)
12481248
{
1249-
JsonbValue vval,
1250-
vcontained;
1251-
JsonbIteratorToken rval,
1252-
rcont;
1249+
JsonbIterator *icont;
1250+
JsonbValue vcont;
1251+
JsonbIteratorToken rcont;
12531252

12541253
/*
12551254
* Guard against stack overflow due to overly complex Jsonb.
@@ -1259,95 +1258,78 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
12591258
*/
12601259
check_stack_depth();
12611260

1262-
rval = JsonbIteratorNext(val, &vval, false);
1263-
rcont = JsonbIteratorNext(mContained, &vcontained, false);
1264-
1265-
if (rval != rcont)
1261+
if (JsonContainerIsObject(cval) != JsonContainerIsObject(ccont))
12661262
{
12671263
/*
12681264
* The differing return values can immediately be taken as indicating
12691265
* two differing container types at this nesting level, which is
12701266
* sufficient reason to give up entirely (but it should be the case
12711267
* that they're both some container type).
12721268
*/
1273-
Assert(rval == WJB_BEGIN_OBJECT || rval == WJB_BEGIN_ARRAY);
1274-
Assert(rcont == WJB_BEGIN_OBJECT || rcont == WJB_BEGIN_ARRAY);
12751269
return false;
12761270
}
1277-
else if (rcont == WJB_BEGIN_OBJECT)
1271+
else if (JsonContainerIsObject(cval))
12781272
{
1279-
Assert(vval.type == jbvObject);
1280-
Assert(vcontained.type == jbvObject);
1281-
12821273
/*
12831274
* If the lhs has fewer pairs than the rhs, it can't possibly contain
12841275
* the rhs. (This conclusion is safe only because we de-duplicate
12851276
* keys in all Jsonb objects; thus there can be no corresponding
12861277
* optimization in the array case.) The case probably won't arise
12871278
* often, but since it's such a cheap check we may as well make it.
12881279
*/
1289-
if (vval.val.object.nPairs < vcontained.val.object.nPairs)
1280+
if (JsonContainerSize(cval) >= 0 &&
1281+
JsonContainerSize(ccont) >= 0 &&
1282+
JsonContainerSize(cval) < JsonContainerSize(ccont))
12901283
return false;
12911284

1292-
/* Work through rhs "is it contained within?" object */
1293-
for (;;)
1285+
icont = JsonbIteratorInit(ccont);
1286+
rcont = JsonbIteratorNext(&icont, &vcont, false);
1287+
Assert(rcont == WJB_BEGIN_OBJECT);
1288+
1289+
/*
1290+
* Work through rhs "is it contained within?" object.
1291+
*
1292+
* When we get through caller's rhs "is it contained within?"
1293+
* object without failing to find one of its values, it's
1294+
* contained.
1295+
*/
1296+
while ((rcont = JsonbIteratorNext(&icont, &vcont, false)) == WJB_KEY)
12941297
{
1295-
JsonbValue *lhsVal; /* lhsVal is from pair in lhs object */
1298+
/* First, find value by key in lhs object ... */
12961299
JsonbValue lhsValBuf;
1300+
JsonbValue *lhsVal = JsonFindKeyInObject(cval,
1301+
vcont.val.string.val,
1302+
vcont.val.string.len,
1303+
&lhsValBuf);
12971304

1298-
rcont = JsonbIteratorNext(mContained, &vcontained, false);
1299-
1300-
/*
1301-
* When we get through caller's rhs "is it contained within?"
1302-
* object without failing to find one of its values, it's
1303-
* contained.
1304-
*/
1305-
if (rcont == WJB_END_OBJECT)
1306-
return true;
1307-
1308-
Assert(rcont == WJB_KEY);
1309-
Assert(vcontained.type == jbvString);
1310-
1311-
/* First, find value by key... */
1312-
lhsVal = getKeyJsonValueFromContainer((*val)->container,
1313-
vcontained.val.string.val,
1314-
vcontained.val.string.len,
1315-
&lhsValBuf);
13161305
if (!lhsVal)
13171306
return false;
13181307

13191308
/*
13201309
* ...at this stage it is apparent that there is at least a key
13211310
* match for this rhs pair.
13221311
*/
1323-
rcont = JsonbIteratorNext(mContained, &vcontained, true);
1324-
1312+
rcont = JsonbIteratorNext(&icont, &vcont, true);
13251313
Assert(rcont == WJB_VALUE);
13261314

13271315
/*
13281316
* Compare rhs pair's value with lhs pair's value just found using
13291317
* key
13301318
*/
1331-
if (lhsVal->type != vcontained.type)
1319+
if (lhsVal->type != vcont.type)
13321320
{
13331321
return false;
13341322
}
13351323
else if (IsAJsonbScalar(lhsVal))
13361324
{
1337-
if (!equalsJsonbScalarValue(lhsVal, &vcontained))
1325+
if (!equalsJsonbScalarValue(lhsVal, &vcont))
13381326
return false;
13391327
}
13401328
else
13411329
{
13421330
/* Nested container value (object or array) */
1343-
JsonIterator *nestval,
1344-
*nestContained;
1345-
13461331
Assert(lhsVal->type == jbvBinary);
1347-
Assert(vcontained.type == jbvBinary);
1348-
1349-
nestval = JsonbIteratorInit(lhsVal->val.binary.data);
1350-
nestContained = JsonbIteratorInit(vcontained.val.binary.data);
1332+
Assert(vcont.type == jbvBinary);
13511333

13521334
/*
13531335
* Match "value" side of rhs datum object's pair recursively.
@@ -1369,18 +1351,19 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
13691351
* of containment (plus of course the mapped nodes must be
13701352
* equal).
13711353
*/
1372-
if (!JsonbDeepContains(&nestval, &nestContained))
1354+
if (!JsonbDeepContains(lhsVal->val.binary.data,
1355+
vcont.val.binary.data))
13731356
return false;
13741357
}
13751358
}
1359+
1360+
Assert(rcont == WJB_END_OBJECT);
1361+
Assert(icont == NULL);
13761362
}
1377-
else if (rcont == WJB_BEGIN_ARRAY)
1363+
else
13781364
{
1379-
JsonbValue *lhsConts = NULL;
1380-
uint32 nLhsElems = vval.val.array.nElems;
1381-
1382-
Assert(vval.type == jbvArray);
1383-
Assert(vcontained.type == jbvArray);
1365+
JsonbValue *lhsConts = NULL;
1366+
uint32 nLhsElems = JsonContainerSize(cval);
13841367

13851368
/*
13861369
* Handle distinction between "raw scalar" pseudo arrays, and real
@@ -1392,29 +1375,25 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
13921375
* only contain pairs, never raw scalars (a pair is represented by an
13931376
* rhs object argument with a single contained pair).
13941377
*/
1395-
if (vval.val.array.rawScalar && !vcontained.val.array.rawScalar)
1378+
if (JsonContainerIsScalar(cval) && !JsonContainerIsScalar(ccont))
13961379
return false;
13971380

1398-
/* Work through rhs "is it contained within?" array */
1399-
for (;;)
1400-
{
1401-
rcont = JsonbIteratorNext(mContained, &vcontained, true);
1381+
icont = JsonbIteratorInit(ccont);
1382+
rcont = JsonbIteratorNext(&icont, &vcont, false);
1383+
Assert(rcont == WJB_BEGIN_ARRAY);
14021384

1403-
/*
1404-
* When we get through caller's rhs "is it contained within?"
1405-
* array without failing to find one of its values, it's
1406-
* contained.
1407-
*/
1408-
if (rcont == WJB_END_ARRAY)
1409-
return true;
1410-
1411-
Assert(rcont == WJB_ELEM);
1412-
1413-
if (IsAJsonbScalar(&vcontained))
1385+
/*
1386+
* Work through rhs "is it contained within?" array.
1387+
*
1388+
* When we get through caller's rhs "is it contained within?"
1389+
* array without failing to find one of its values, it's
1390+
* contained.
1391+
*/
1392+
while ((rcont = JsonbIteratorNext(&icont, &vcont, true)) == WJB_ELEM)
1393+
{
1394+
if (IsAJsonbScalar(&vcont))
14141395
{
1415-
if (!findJsonbValueFromContainer((*val)->container,
1416-
JB_FARRAY,
1417-
&vcontained))
1396+
if (!findJsonbValueFromContainer(cval, JB_FARRAY, &vcont))
14181397
return false;
14191398
}
14201399
else
@@ -1427,21 +1406,37 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
14271406
*/
14281407
if (lhsConts == NULL)
14291408
{
1430-
uint32 j = 0;
1409+
uint32 j = 0;
1410+
JsonbIterator *ival;
1411+
JsonbValue vval;
1412+
1413+
if ((int32) nLhsElems < 0)
1414+
nLhsElems = JsonGetArraySize(cval);
1415+
1416+
if (nLhsElems == 0)
1417+
return false;
14311418

14321419
/* Make room for all possible values */
14331420
lhsConts = palloc(sizeof(JsonbValue) * nLhsElems);
14341421

1422+
ival = JsonbIteratorInit(cval);
1423+
rcont = JsonbIteratorNext(&ival, &vval, true);
1424+
Assert(rcont == WJB_BEGIN_ARRAY);
1425+
14351426
for (i = 0; i < nLhsElems; i++)
14361427
{
14371428
/* Store all lhs elements in temp array */
1438-
rcont = JsonbIteratorNext(val, &vval, true);
1429+
rcont = JsonbIteratorNext(&ival, &vval, true);
14391430
Assert(rcont == WJB_ELEM);
14401431

14411432
if (vval.type == jbvBinary)
14421433
lhsConts[j++] = vval;
14431434
}
14441435

1436+
rcont = JsonbIteratorNext(&ival, &vval, true);
1437+
Assert(rcont == WJB_END_ARRAY);
1438+
Assert(ival == NULL);
1439+
14451440
/* No container elements in temp array, so give up now */
14461441
if (j == 0)
14471442
return false;
@@ -1454,20 +1449,8 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
14541449
for (i = 0; i < nLhsElems; i++)
14551450
{
14561451
/* Nested container value (object or array) */
1457-
JsonIterator *nestval,
1458-
*nestContained;
1459-
bool contains;
1460-
1461-
nestval = JsonbIteratorInit(lhsConts[i].val.binary.data);
1462-
nestContained = JsonbIteratorInit(vcontained.val.binary.data);
1463-
1464-
contains = JsonbDeepContains(&nestval, &nestContained);
1465-
1466-
if (nestval)
1467-
pfree(nestval);
1468-
if (nestContained)
1469-
pfree(nestContained);
1470-
if (contains)
1452+
if (JsonbDeepContains(lhsConts[i].val.binary.data,
1453+
vcont.val.binary.data))
14711454
break;
14721455
}
14731456

@@ -1479,14 +1462,15 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
14791462
return false;
14801463
}
14811464
}
1482-
}
1483-
else
1484-
{
1485-
elog(ERROR, "invalid jsonb container type");
1465+
1466+
Assert(rcont == WJB_END_ARRAY);
1467+
Assert(icont == NULL);
1468+
1469+
if (lhsConts != NULL)
1470+
pfree(lhsConts);
14861471
}
14871472

1488-
elog(ERROR, "unexpectedly fell off end of jsonb container");
1489-
return false;
1473+
return true;
14901474
}
14911475

14921476
/*

src/include/utils/json_generic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ extern const char *JsonbTypeName(JsonbValue *jb);
281281

282282
extern int JsonCompareContainers(JsonContainer *a, JsonContainer *b);
283283

284-
extern bool JsonbDeepContains(JsonIterator **val, JsonIterator **mContained);
284+
extern bool JsonbDeepContains(JsonContainer *val, JsonContainer *mContained);
285285

286286
extern JsonValue *JsonContainerExtractKeys(JsonContainer *jsc);
287287

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy