Skip to content

Commit 9073c78

Browse files
author
Nikita Glukhov
committed
Refactor JsonbDeepContains()
1 parent 7b9c90f commit 9073c78

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
@@ -1180,12 +1180,11 @@ JsonbIteratorInit(JsonContainer *cont)
11801180
*/
11811181

11821182
bool
1183-
JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
1183+
JsonbDeepContains(JsonContainer *cval, JsonContainer *ccont)
11841184
{
1185-
JsonbValue vval,
1186-
vcontained;
1187-
JsonbIteratorToken rval,
1188-
rcont;
1185+
JsonIterator *icont;
1186+
JsonbValue vcont;
1187+
JsonbIteratorToken rcont;
11891188

11901189
/*
11911190
* Guard against stack overflow due to overly complex Jsonb.
@@ -1195,94 +1194,76 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
11951194
*/
11961195
check_stack_depth();
11971196

1198-
rval = JsonIteratorNext(val, &vval, false);
1199-
rcont = JsonIteratorNext(mContained, &vcontained, false);
1200-
1201-
if (rval != rcont)
1197+
if (JsonContainerIsObject(cval) != JsonContainerIsObject(ccont))
12021198
{
12031199
/*
12041200
* The differing return values can immediately be taken as indicating
12051201
* two differing container types at this nesting level, which is
12061202
* sufficient reason to give up entirely (but it should be the case
12071203
* that they're both some container type).
12081204
*/
1209-
Assert(rval == WJB_BEGIN_OBJECT || rval == WJB_BEGIN_ARRAY);
1210-
Assert(rcont == WJB_BEGIN_OBJECT || rcont == WJB_BEGIN_ARRAY);
12111205
return false;
12121206
}
1213-
else if (rcont == WJB_BEGIN_OBJECT)
1207+
else if (JsonContainerIsObject(cval))
12141208
{
1215-
Assert(vval.type == jbvObject);
1216-
Assert(vcontained.type == jbvObject);
1217-
12181209
/*
12191210
* If the lhs has fewer pairs than the rhs, it can't possibly contain
12201211
* the rhs. (This conclusion is safe only because we de-duplicate
12211212
* keys in all Jsonb objects; thus there can be no corresponding
12221213
* optimization in the array case.) The case probably won't arise
12231214
* often, but since it's such a cheap check we may as well make it.
12241215
*/
1225-
if (vval.val.object.nPairs < vcontained.val.object.nPairs)
1216+
if (JsonContainerSize(cval) >= 0 &&
1217+
JsonContainerSize(ccont) >= 0 &&
1218+
JsonContainerSize(cval) < JsonContainerSize(ccont))
12261219
return false;
12271220

1228-
/* Work through rhs "is it contained within?" object */
1229-
for (;;)
1230-
{
1231-
JsonbValue *lhsVal; /* lhsVal is from pair in lhs object */
1232-
JsonbValue lhsValBuf;
1233-
1234-
rcont = JsonIteratorNext(mContained, &vcontained, false);
1221+
icont = JsonIteratorInit(ccont);
1222+
rcont = JsonIteratorNext(&icont, &vcont, false);
1223+
Assert(rcont == WJB_BEGIN_OBJECT);
12351224

1236-
/*
1237-
* When we get through caller's rhs "is it contained within?"
1238-
* object without failing to find one of its values, it's
1239-
* contained.
1240-
*/
1241-
if (rcont == WJB_END_OBJECT)
1242-
return true;
1243-
1244-
Assert(rcont == WJB_KEY);
1245-
Assert(vcontained.type == jbvString);
1225+
/*
1226+
* Work through rhs "is it contained within?" object.
1227+
*
1228+
* When we get through caller's rhs "is it contained within?"
1229+
* object without failing to find one of its values, it's
1230+
* contained.
1231+
*/
1232+
while ((rcont = JsonIteratorNext(&icont, &vcont, false)) == WJB_KEY)
1233+
{
1234+
/* First, find value by key in lhs object ... */
1235+
JsonbValue *lhsVal = JsonFindKeyInObject(cval,
1236+
vcont.val.string.val,
1237+
vcont.val.string.len);
12461238

1247-
/* First, find value by key... */
1248-
lhsVal = JsonFindKeyInObject((*val)->container,
1249-
vcontained.val.string.val,
1250-
vcontained.val.string.len);
12511239
if (!lhsVal)
12521240
return false;
12531241

12541242
/*
12551243
* ...at this stage it is apparent that there is at least a key
12561244
* match for this rhs pair.
12571245
*/
1258-
rcont = JsonIteratorNext(mContained, &vcontained, true);
1259-
1246+
rcont = JsonIteratorNext(&icont, &vcont, true);
12601247
Assert(rcont == WJB_VALUE);
12611248

12621249
/*
12631250
* Compare rhs pair's value with lhs pair's value just found using
12641251
* key
12651252
*/
1266-
if (lhsVal->type != vcontained.type)
1253+
if (lhsVal->type != vcont.type)
12671254
{
12681255
return false;
12691256
}
12701257
else if (IsAJsonbScalar(lhsVal))
12711258
{
1272-
if (!equalsJsonbScalarValue(lhsVal, &vcontained))
1259+
if (!equalsJsonbScalarValue(lhsVal, &vcont))
12731260
return false;
12741261
}
12751262
else
12761263
{
12771264
/* Nested container value (object or array) */
1278-
JsonIterator *nestval,
1279-
*nestContained;
1280-
12811265
Assert(lhsVal->type == jbvBinary);
1282-
Assert(vcontained.type == jbvBinary);
1283-
1284-
nestval = JsonIteratorInit(lhsVal->val.binary.data);
1285-
nestContained = JsonIteratorInit(vcontained.val.binary.data);
1266+
Assert(vcont.type == jbvBinary);
12861267

12871268
/*
12881269
* Match "value" side of rhs datum object's pair recursively.
@@ -1304,18 +1285,19 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
13041285
* of containment (plus of course the mapped nodes must be
13051286
* equal).
13061287
*/
1307-
if (!JsonbDeepContains(&nestval, &nestContained))
1288+
if (!JsonbDeepContains(lhsVal->val.binary.data,
1289+
vcont.val.binary.data))
13081290
return false;
13091291
}
13101292
}
1293+
1294+
Assert(rcont == WJB_END_OBJECT);
1295+
Assert(icont == NULL);
13111296
}
1312-
else if (rcont == WJB_BEGIN_ARRAY)
1297+
else
13131298
{
1314-
JsonbValue *lhsConts = NULL;
1315-
uint32 nLhsElems = vval.val.array.nElems;
1316-
1317-
Assert(vval.type == jbvArray);
1318-
Assert(vcontained.type == jbvArray);
1299+
JsonbValue *lhsConts = NULL;
1300+
uint32 nLhsElems = JsonContainerSize(cval);
13191301

13201302
/*
13211303
* Handle distinction between "raw scalar" pseudo arrays, and real
@@ -1327,29 +1309,25 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
13271309
* only contain pairs, never raw scalars (a pair is represented by an
13281310
* rhs object argument with a single contained pair).
13291311
*/
1330-
if (vval.val.array.rawScalar && !vcontained.val.array.rawScalar)
1312+
if (JsonContainerIsScalar(cval) && !JsonContainerIsScalar(ccont))
13311313
return false;
13321314

1333-
/* Work through rhs "is it contained within?" array */
1334-
for (;;)
1335-
{
1336-
rcont = JsonIteratorNext(mContained, &vcontained, true);
1315+
icont = JsonIteratorInit(ccont);
1316+
rcont = JsonIteratorNext(&icont, &vcont, false);
1317+
Assert(rcont == WJB_BEGIN_ARRAY);
13371318

1338-
/*
1339-
* When we get through caller's rhs "is it contained within?"
1340-
* array without failing to find one of its values, it's
1341-
* contained.
1342-
*/
1343-
if (rcont == WJB_END_ARRAY)
1344-
return true;
1345-
1346-
Assert(rcont == WJB_ELEM);
1347-
1348-
if (IsAJsonbScalar(&vcontained))
1319+
/*
1320+
* Work through rhs "is it contained within?" array.
1321+
*
1322+
* When we get through caller's rhs "is it contained within?"
1323+
* array without failing to find one of its values, it's
1324+
* contained.
1325+
*/
1326+
while ((rcont = JsonIteratorNext(&icont, &vcont, true)) == WJB_ELEM)
1327+
{
1328+
if (IsAJsonbScalar(&vcont))
13491329
{
1350-
if (!findJsonbValueFromContainer((*val)->container,
1351-
JB_FARRAY,
1352-
&vcontained))
1330+
if (!findJsonbValueFromContainer(cval, JB_FARRAY, &vcont))
13531331
return false;
13541332
}
13551333
else
@@ -1362,21 +1340,37 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
13621340
*/
13631341
if (lhsConts == NULL)
13641342
{
1365-
uint32 j = 0;
1343+
uint32 j = 0;
1344+
JsonIterator *ival;
1345+
JsonbValue vval;
1346+
1347+
if ((int32) nLhsElems < 0)
1348+
nLhsElems = JsonGetArraySize(cval);
1349+
1350+
if (nLhsElems == 0)
1351+
return false;
13661352

13671353
/* Make room for all possible values */
13681354
lhsConts = palloc(sizeof(JsonbValue) * nLhsElems);
13691355

1356+
ival = JsonIteratorInit(cval);
1357+
rcont = JsonIteratorNext(&ival, &vval, true);
1358+
Assert(rcont == WJB_BEGIN_ARRAY);
1359+
13701360
for (i = 0; i < nLhsElems; i++)
13711361
{
13721362
/* Store all lhs elements in temp array */
1373-
rcont = JsonIteratorNext(val, &vval, true);
1363+
rcont = JsonIteratorNext(&ival, &vval, true);
13741364
Assert(rcont == WJB_ELEM);
13751365

13761366
if (vval.type == jbvBinary)
13771367
lhsConts[j++] = vval;
13781368
}
13791369

1370+
rcont = JsonIteratorNext(&ival, &vval, true);
1371+
Assert(rcont == WJB_END_ARRAY);
1372+
Assert(ival == NULL);
1373+
13801374
/* No container elements in temp array, so give up now */
13811375
if (j == 0)
13821376
return false;
@@ -1389,20 +1383,8 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
13891383
for (i = 0; i < nLhsElems; i++)
13901384
{
13911385
/* Nested container value (object or array) */
1392-
JsonIterator *nestval,
1393-
*nestContained;
1394-
bool contains;
1395-
1396-
nestval = JsonIteratorInit(lhsConts[i].val.binary.data);
1397-
nestContained = JsonIteratorInit(vcontained.val.binary.data);
1398-
1399-
contains = JsonbDeepContains(&nestval, &nestContained);
1400-
1401-
if (nestval)
1402-
pfree(nestval);
1403-
if (nestContained)
1404-
pfree(nestContained);
1405-
if (contains)
1386+
if (JsonbDeepContains(lhsConts[i].val.binary.data,
1387+
vcont.val.binary.data))
14061388
break;
14071389
}
14081390

@@ -1414,14 +1396,15 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
14141396
return false;
14151397
}
14161398
}
1417-
}
1418-
else
1419-
{
1420-
elog(ERROR, "invalid jsonb container type");
1399+
1400+
Assert(rcont == WJB_END_ARRAY);
1401+
Assert(icont == NULL);
1402+
1403+
if (lhsConts != NULL)
1404+
pfree(lhsConts);
14211405
}
14221406

1423-
elog(ERROR, "unexpectedly fell off end of jsonb container");
1424-
return false;
1407+
return true;
14251408
}
14261409

14271410
/*

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)