Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit fb4ab66

Browse files
author
Nikita Glukhov
committed
Refactor JsonbDeepContains()
1 parent 4079d52 commit fb4ab66

File tree

3 files changed

+82
-111
lines changed

3 files changed

+82
-111
lines changed

src/backend/utils/adt/jsonb_op.c

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

119-
JsonbIterator *it1,
120-
*it2;
121-
122119
if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl))
123120
PG_RETURN_BOOL(false);
124121

125-
it1 = JsonbIteratorInit(&val->root);
126-
it2 = JsonbIteratorInit(&tmpl->root);
127-
128-
PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
122+
PG_RETURN_BOOL(JsonbDeepContains(JsonRoot(val), JsonRoot(tmpl)));
129123
}
130124

131125
Datum
@@ -135,16 +129,10 @@ jsonb_contained(PG_FUNCTION_ARGS)
135129
Jsonb *tmpl = PG_GETARG_JSONB_P(0);
136130
Jsonb *val = PG_GETARG_JSONB_P(1);
137131

138-
JsonbIterator *it1,
139-
*it2;
140-
141132
if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl))
142133
PG_RETURN_BOOL(false);
143134

144-
it1 = JsonbIteratorInit(&val->root);
145-
it2 = JsonbIteratorInit(&tmpl->root);
146-
147-
PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
135+
PG_RETURN_BOOL(JsonbDeepContains(JsonRoot(val), JsonRoot(tmpl)));
148136
}
149137

150138
Datum

src/backend/utils/adt/jsonb_util.c

Lines changed: 79 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,12 +1227,11 @@ JsonbIteratorInit(JsonContainer *cont)
12271227
*/
12281228

12291229
bool
1230-
JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
1230+
JsonbDeepContains(JsonContainer *cval, JsonContainer *ccont)
12311231
{
1232-
JsonbValue vval,
1233-
vcontained;
1234-
JsonbIteratorToken rval,
1235-
rcont;
1232+
JsonIterator *icont;
1233+
JsonbValue vcont;
1234+
JsonbIteratorToken rcont;
12361235

12371236
/*
12381237
* Guard against stack overflow due to overly complex Jsonb.
@@ -1242,94 +1241,76 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
12421241
*/
12431242
check_stack_depth();
12441243

1245-
rval = JsonIteratorNext(val, &vval, false);
1246-
rcont = JsonIteratorNext(mContained, &vcontained, false);
1247-
1248-
if (rval != rcont)
1244+
if (JsonContainerIsObject(cval) != JsonContainerIsObject(ccont))
12491245
{
12501246
/*
12511247
* The differing return values can immediately be taken as indicating
12521248
* two differing container types at this nesting level, which is
12531249
* sufficient reason to give up entirely (but it should be the case
12541250
* that they're both some container type).
12551251
*/
1256-
Assert(rval == WJB_BEGIN_OBJECT || rval == WJB_BEGIN_ARRAY);
1257-
Assert(rcont == WJB_BEGIN_OBJECT || rcont == WJB_BEGIN_ARRAY);
12581252
return false;
12591253
}
1260-
else if (rcont == WJB_BEGIN_OBJECT)
1254+
else if (JsonContainerIsObject(cval))
12611255
{
1262-
Assert(vval.type == jbvObject);
1263-
Assert(vcontained.type == jbvObject);
1264-
12651256
/*
12661257
* If the lhs has fewer pairs than the rhs, it can't possibly contain
12671258
* the rhs. (This conclusion is safe only because we de-duplicate
12681259
* keys in all Jsonb objects; thus there can be no corresponding
12691260
* optimization in the array case.) The case probably won't arise
12701261
* often, but since it's such a cheap check we may as well make it.
12711262
*/
1272-
if (vval.val.object.nPairs < vcontained.val.object.nPairs)
1263+
if (JsonContainerSize(cval) >= 0 &&
1264+
JsonContainerSize(ccont) >= 0 &&
1265+
JsonContainerSize(cval) < JsonContainerSize(ccont))
12731266
return false;
12741267

1275-
/* Work through rhs "is it contained within?" object */
1276-
for (;;)
1277-
{
1278-
JsonbValue *lhsVal; /* lhsVal is from pair in lhs object */
1279-
JsonbValue lhsValBuf;
1280-
1281-
rcont = JsonIteratorNext(mContained, &vcontained, false);
1268+
icont = JsonIteratorInit(ccont);
1269+
rcont = JsonIteratorNext(&icont, &vcont, false);
1270+
Assert(rcont == WJB_BEGIN_OBJECT);
12821271

1283-
/*
1284-
* When we get through caller's rhs "is it contained within?"
1285-
* object without failing to find one of its values, it's
1286-
* contained.
1287-
*/
1288-
if (rcont == WJB_END_OBJECT)
1289-
return true;
1290-
1291-
Assert(rcont == WJB_KEY);
1292-
Assert(vcontained.type == jbvString);
1272+
/*
1273+
* Work through rhs "is it contained within?" object.
1274+
*
1275+
* When we get through caller's rhs "is it contained within?"
1276+
* object without failing to find one of its values, it's
1277+
* contained.
1278+
*/
1279+
while ((rcont = JsonIteratorNext(&icont, &vcont, false)) == WJB_KEY)
1280+
{
1281+
/* First, find value by key in lhs object ... */
1282+
JsonbValue *lhsVal = JsonFindKeyInObject(cval,
1283+
vcont.val.string.val,
1284+
vcont.val.string.len);
12931285

1294-
/* First, find value by key... */
1295-
lhsVal = JsonFindKeyInObject((*val)->container,
1296-
vcontained.val.string.val,
1297-
vcontained.val.string.len);
12981286
if (!lhsVal)
12991287
return false;
13001288

13011289
/*
13021290
* ...at this stage it is apparent that there is at least a key
13031291
* match for this rhs pair.
13041292
*/
1305-
rcont = JsonIteratorNext(mContained, &vcontained, true);
1306-
1293+
rcont = JsonIteratorNext(&icont, &vcont, true);
13071294
Assert(rcont == WJB_VALUE);
13081295

13091296
/*
13101297
* Compare rhs pair's value with lhs pair's value just found using
13111298
* key
13121299
*/
1313-
if (lhsVal->type != vcontained.type)
1300+
if (lhsVal->type != vcont.type)
13141301
{
13151302
return false;
13161303
}
13171304
else if (IsAJsonbScalar(lhsVal))
13181305
{
1319-
if (!equalsJsonbScalarValue(lhsVal, &vcontained))
1306+
if (!equalsJsonbScalarValue(lhsVal, &vcont))
13201307
return false;
13211308
}
13221309
else
13231310
{
13241311
/* Nested container value (object or array) */
1325-
JsonIterator *nestval,
1326-
*nestContained;
1327-
13281312
Assert(lhsVal->type == jbvBinary);
1329-
Assert(vcontained.type == jbvBinary);
1330-
1331-
nestval = JsonIteratorInit(lhsVal->val.binary.data);
1332-
nestContained = JsonIteratorInit(vcontained.val.binary.data);
1313+
Assert(vcont.type == jbvBinary);
13331314

13341315
/*
13351316
* Match "value" side of rhs datum object's pair recursively.
@@ -1351,18 +1332,19 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
13511332
* of containment (plus of course the mapped nodes must be
13521333
* equal).
13531334
*/
1354-
if (!JsonbDeepContains(&nestval, &nestContained))
1335+
if (!JsonbDeepContains(lhsVal->val.binary.data,
1336+
vcont.val.binary.data))
13551337
return false;
13561338
}
13571339
}
1340+
1341+
Assert(rcont == WJB_END_OBJECT);
1342+
Assert(icont == NULL);
13581343
}
1359-
else if (rcont == WJB_BEGIN_ARRAY)
1344+
else
13601345
{
1361-
JsonbValue *lhsConts = NULL;
1362-
uint32 nLhsElems = vval.val.array.nElems;
1363-
1364-
Assert(vval.type == jbvArray);
1365-
Assert(vcontained.type == jbvArray);
1346+
JsonbValue *lhsConts = NULL;
1347+
uint32 nLhsElems = JsonContainerSize(cval);
13661348

13671349
/*
13681350
* Handle distinction between "raw scalar" pseudo arrays, and real
@@ -1374,29 +1356,25 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
13741356
* only contain pairs, never raw scalars (a pair is represented by an
13751357
* rhs object argument with a single contained pair).
13761358
*/
1377-
if (vval.val.array.rawScalar && !vcontained.val.array.rawScalar)
1359+
if (JsonContainerIsScalar(cval) && !JsonContainerIsScalar(ccont))
13781360
return false;
13791361

1380-
/* Work through rhs "is it contained within?" array */
1381-
for (;;)
1382-
{
1383-
rcont = JsonIteratorNext(mContained, &vcontained, true);
1362+
icont = JsonIteratorInit(ccont);
1363+
rcont = JsonIteratorNext(&icont, &vcont, false);
1364+
Assert(rcont == WJB_BEGIN_ARRAY);
13841365

1385-
/*
1386-
* When we get through caller's rhs "is it contained within?"
1387-
* array without failing to find one of its values, it's
1388-
* contained.
1389-
*/
1390-
if (rcont == WJB_END_ARRAY)
1391-
return true;
1392-
1393-
Assert(rcont == WJB_ELEM);
1394-
1395-
if (IsAJsonbScalar(&vcontained))
1366+
/*
1367+
* Work through rhs "is it contained within?" array.
1368+
*
1369+
* When we get through caller's rhs "is it contained within?"
1370+
* array without failing to find one of its values, it's
1371+
* contained.
1372+
*/
1373+
while ((rcont = JsonIteratorNext(&icont, &vcont, true)) == WJB_ELEM)
1374+
{
1375+
if (IsAJsonbScalar(&vcont))
13961376
{
1397-
if (!findJsonbValueFromContainer((*val)->container,
1398-
JB_FARRAY,
1399-
&vcontained))
1377+
if (!findJsonbValueFromContainer(cval, JB_FARRAY, &vcont))
14001378
return false;
14011379
}
14021380
else
@@ -1409,21 +1387,37 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
14091387
*/
14101388
if (lhsConts == NULL)
14111389
{
1412-
uint32 j = 0;
1390+
uint32 j = 0;
1391+
JsonIterator *ival;
1392+
JsonbValue vval;
1393+
1394+
if ((int32) nLhsElems < 0)
1395+
nLhsElems = JsonGetArraySize(cval);
1396+
1397+
if (nLhsElems == 0)
1398+
return false;
14131399

14141400
/* Make room for all possible values */
14151401
lhsConts = palloc(sizeof(JsonbValue) * nLhsElems);
14161402

1403+
ival = JsonIteratorInit(cval);
1404+
rcont = JsonIteratorNext(&ival, &vval, true);
1405+
Assert(rcont == WJB_BEGIN_ARRAY);
1406+
14171407
for (i = 0; i < nLhsElems; i++)
14181408
{
14191409
/* Store all lhs elements in temp array */
1420-
rcont = JsonIteratorNext(val, &vval, true);
1410+
rcont = JsonIteratorNext(&ival, &vval, true);
14211411
Assert(rcont == WJB_ELEM);
14221412

14231413
if (vval.type == jbvBinary)
14241414
lhsConts[j++] = vval;
14251415
}
14261416

1417+
rcont = JsonIteratorNext(&ival, &vval, true);
1418+
Assert(rcont == WJB_END_ARRAY);
1419+
Assert(ival == NULL);
1420+
14271421
/* No container elements in temp array, so give up now */
14281422
if (j == 0)
14291423
return false;
@@ -1436,20 +1430,8 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
14361430
for (i = 0; i < nLhsElems; i++)
14371431
{
14381432
/* Nested container value (object or array) */
1439-
JsonIterator *nestval,
1440-
*nestContained;
1441-
bool contains;
1442-
1443-
nestval = JsonIteratorInit(lhsConts[i].val.binary.data);
1444-
nestContained = JsonIteratorInit(vcontained.val.binary.data);
1445-
1446-
contains = JsonbDeepContains(&nestval, &nestContained);
1447-
1448-
if (nestval)
1449-
pfree(nestval);
1450-
if (nestContained)
1451-
pfree(nestContained);
1452-
if (contains)
1433+
if (JsonbDeepContains(lhsConts[i].val.binary.data,
1434+
vcont.val.binary.data))
14531435
break;
14541436
}
14551437

@@ -1461,14 +1443,15 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
14611443
return false;
14621444
}
14631445
}
1464-
}
1465-
else
1466-
{
1467-
elog(ERROR, "invalid jsonb container type");
1446+
1447+
Assert(rcont == WJB_END_ARRAY);
1448+
Assert(icont == NULL);
1449+
1450+
if (lhsConts != NULL)
1451+
pfree(lhsConts);
14681452
}
14691453

1470-
elog(ERROR, "unexpectedly fell off end of jsonb container");
1471-
return false;
1454+
return true;
14721455
}
14731456

14741457
/*

src/include/utils/json_generic.h

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

294294
extern int JsonCompareContainers(JsonContainer *a, JsonContainer *b);
295295

296-
extern bool JsonbDeepContains(JsonIterator **val, JsonIterator **mContained);
296+
extern bool JsonbDeepContains(JsonContainer *val, JsonContainer *mContained);
297297

298298
extern JsonValue *JsonContainerExtractKeys(JsonContainer *jsc);
299299

0 commit comments

Comments
 (0)