Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+2-14
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

+80-96
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

+1-1
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)