Skip to content

Commit f9cd4d8

Browse files
author
Nikita Glukhov
committed
Refactor JsonbDeepContains()
1 parent f94e8c6 commit f9cd4d8

File tree

3 files changed

+81
-110
lines changed

3 files changed

+81
-110
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(0);
117117
Jsonb *tmpl = PG_GETARG_JSONB(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(0);
136130
Jsonb *val = PG_GETARG_JSONB(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: 78 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,12 +1152,11 @@ JsonbIteratorInit(JsonContainer *cont)
11521152
*/
11531153

11541154
bool
1155-
JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
1155+
JsonbDeepContains(JsonContainer *cval, JsonContainer *ccont)
11561156
{
1157-
JsonbValue vval,
1158-
vcontained;
1159-
JsonbIteratorToken rval,
1160-
rcont;
1157+
JsonIterator *icont;
1158+
JsonbValue vcont;
1159+
JsonbIteratorToken rcont;
11611160

11621161
/*
11631162
* Guard against stack overflow due to overly complex Jsonb.
@@ -1167,57 +1166,46 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
11671166
*/
11681167
check_stack_depth();
11691168

1170-
rval = JsonIteratorNext(val, &vval, false);
1171-
rcont = JsonIteratorNext(mContained, &vcontained, false);
1172-
1173-
if (rval != rcont)
1169+
if (JsonContainerIsObject(cval) != JsonContainerIsObject(ccont))
11741170
{
11751171
/*
11761172
* The differing return values can immediately be taken as indicating
11771173
* two differing container types at this nesting level, which is
11781174
* sufficient reason to give up entirely (but it should be the case
11791175
* that they're both some container type).
11801176
*/
1181-
Assert(rval == WJB_BEGIN_OBJECT || rval == WJB_BEGIN_ARRAY);
1182-
Assert(rcont == WJB_BEGIN_OBJECT || rcont == WJB_BEGIN_ARRAY);
11831177
return false;
11841178
}
1185-
else if (rcont == WJB_BEGIN_OBJECT)
1179+
else if (JsonContainerIsObject(cval))
11861180
{
1187-
Assert(vval.type == jbvObject);
1188-
Assert(vcontained.type == jbvObject);
1189-
11901181
/*
11911182
* If the lhs has fewer pairs than the rhs, it can't possibly contain
11921183
* the rhs. (This conclusion is safe only because we de-duplicate
11931184
* keys in all Jsonb objects; thus there can be no corresponding
11941185
* optimization in the array case.) The case probably won't arise
11951186
* often, but since it's such a cheap check we may as well make it.
11961187
*/
1197-
if (vval.val.object.nPairs < vcontained.val.object.nPairs)
1188+
if (JsonContainerSize(cval) >= 0 &&
1189+
JsonContainerSize(ccont) >= 0 &&
1190+
JsonContainerSize(cval) < JsonContainerSize(ccont))
11981191
return false;
11991192

1200-
/* Work through rhs "is it contained within?" object */
1201-
for (;;)
1202-
{
1203-
JsonbValue *lhsVal; /* lhsVal is from pair in lhs object */
1204-
1205-
rcont = JsonIteratorNext(mContained, &vcontained, false);
1193+
icont = JsonIteratorInit(ccont);
1194+
rcont = JsonIteratorNext(&icont, &vcont, false);
1195+
Assert(rcont == WJB_BEGIN_OBJECT);
12061196

1207-
/*
1208-
* When we get through caller's rhs "is it contained within?"
1209-
* object without failing to find one of its values, it's
1210-
* contained.
1211-
*/
1212-
if (rcont == WJB_END_OBJECT)
1213-
return true;
1214-
1215-
Assert(rcont == WJB_KEY);
1216-
1217-
/* First, find value by key... */
1218-
lhsVal = findJsonbValueFromContainer((*val)->container,
1219-
JB_FOBJECT,
1220-
&vcontained);
1197+
/*
1198+
* Work through rhs "is it contained within?" object.
1199+
*
1200+
* When we get through caller's rhs "is it contained within?"
1201+
* object without failing to find one of its values, it's
1202+
* contained.
1203+
*/
1204+
while ((rcont = JsonIteratorNext(&icont, &vcont, false)) == WJB_KEY)
1205+
{
1206+
/* First, find value by key in lhs object ... */
1207+
JsonbValue *lhsVal = findJsonbValueFromContainer(cval, JB_FOBJECT,
1208+
&vcont);
12211209

12221210
if (!lhsVal)
12231211
return false;
@@ -1226,34 +1214,27 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
12261214
* ...at this stage it is apparent that there is at least a key
12271215
* match for this rhs pair.
12281216
*/
1229-
rcont = JsonIteratorNext(mContained, &vcontained, true);
1230-
1217+
rcont = JsonIteratorNext(&icont, &vcont, true);
12311218
Assert(rcont == WJB_VALUE);
12321219

12331220
/*
12341221
* Compare rhs pair's value with lhs pair's value just found using
12351222
* key
12361223
*/
1237-
if (lhsVal->type != vcontained.type)
1224+
if (lhsVal->type != vcont.type)
12381225
{
12391226
return false;
12401227
}
12411228
else if (IsAJsonbScalar(lhsVal))
12421229
{
1243-
if (!equalsJsonbScalarValue(lhsVal, &vcontained))
1230+
if (!equalsJsonbScalarValue(lhsVal, &vcont))
12441231
return false;
12451232
}
12461233
else
12471234
{
12481235
/* Nested container value (object or array) */
1249-
JsonIterator *nestval,
1250-
*nestContained;
1251-
12521236
Assert(lhsVal->type == jbvBinary);
1253-
Assert(vcontained.type == jbvBinary);
1254-
1255-
nestval = JsonIteratorInit(lhsVal->val.binary.data);
1256-
nestContained = JsonIteratorInit(vcontained.val.binary.data);
1237+
Assert(vcont.type == jbvBinary);
12571238

12581239
/*
12591240
* Match "value" side of rhs datum object's pair recursively.
@@ -1275,18 +1256,19 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
12751256
* of containment (plus of course the mapped nodes must be
12761257
* equal).
12771258
*/
1278-
if (!JsonbDeepContains(&nestval, &nestContained))
1259+
if (!JsonbDeepContains(lhsVal->val.binary.data,
1260+
vcont.val.binary.data))
12791261
return false;
12801262
}
12811263
}
1264+
1265+
Assert(rcont == WJB_END_OBJECT);
1266+
Assert(icont == NULL);
12821267
}
1283-
else if (rcont == WJB_BEGIN_ARRAY)
1268+
else
12841269
{
1285-
JsonbValue *lhsConts = NULL;
1286-
uint32 nLhsElems = vval.val.array.nElems;
1287-
1288-
Assert(vval.type == jbvArray);
1289-
Assert(vcontained.type == jbvArray);
1270+
JsonbValue *lhsConts = NULL;
1271+
uint32 nLhsElems = JsonContainerSize(cval);
12901272

12911273
/*
12921274
* Handle distinction between "raw scalar" pseudo arrays, and real
@@ -1298,29 +1280,25 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
12981280
* only contain pairs, never raw scalars (a pair is represented by an
12991281
* rhs object argument with a single contained pair).
13001282
*/
1301-
if (vval.val.array.rawScalar && !vcontained.val.array.rawScalar)
1283+
if (JsonContainerIsScalar(cval) && !JsonContainerIsScalar(ccont))
13021284
return false;
13031285

1304-
/* Work through rhs "is it contained within?" array */
1305-
for (;;)
1306-
{
1307-
rcont = JsonIteratorNext(mContained, &vcontained, true);
1286+
icont = JsonIteratorInit(ccont);
1287+
rcont = JsonIteratorNext(&icont, &vcont, false);
1288+
Assert(rcont == WJB_BEGIN_ARRAY);
13081289

1309-
/*
1310-
* When we get through caller's rhs "is it contained within?"
1311-
* array without failing to find one of its values, it's
1312-
* contained.
1313-
*/
1314-
if (rcont == WJB_END_ARRAY)
1315-
return true;
1316-
1317-
Assert(rcont == WJB_ELEM);
1318-
1319-
if (IsAJsonbScalar(&vcontained))
1290+
/*
1291+
* Work through rhs "is it contained within?" array.
1292+
*
1293+
* When we get through caller's rhs "is it contained within?"
1294+
* array without failing to find one of its values, it's
1295+
* contained.
1296+
*/
1297+
while ((rcont = JsonIteratorNext(&icont, &vcont, true)) == WJB_ELEM)
1298+
{
1299+
if (IsAJsonbScalar(&vcont))
13201300
{
1321-
if (!findJsonbValueFromContainer((*val)->container,
1322-
JB_FARRAY,
1323-
&vcontained))
1301+
if (!findJsonbValueFromContainer(cval, JB_FARRAY, &vcont))
13241302
return false;
13251303
}
13261304
else
@@ -1333,21 +1311,37 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
13331311
*/
13341312
if (lhsConts == NULL)
13351313
{
1336-
uint32 j = 0;
1314+
uint32 j = 0;
1315+
JsonIterator *ival;
1316+
JsonbValue vval;
1317+
1318+
if ((int32) nLhsElems < 0)
1319+
nLhsElems = JsonGetArraySize(cval);
1320+
1321+
if (nLhsElems == 0)
1322+
return false;
13371323

13381324
/* Make room for all possible values */
13391325
lhsConts = palloc(sizeof(JsonbValue) * nLhsElems);
13401326

1327+
ival = JsonIteratorInit(cval);
1328+
rcont = JsonIteratorNext(&ival, &vval, true);
1329+
Assert(rcont == WJB_BEGIN_ARRAY);
1330+
13411331
for (i = 0; i < nLhsElems; i++)
13421332
{
13431333
/* Store all lhs elements in temp array */
1344-
rcont = JsonIteratorNext(val, &vval, true);
1334+
rcont = JsonIteratorNext(&ival, &vval, true);
13451335
Assert(rcont == WJB_ELEM);
13461336

13471337
if (vval.type == jbvBinary)
13481338
lhsConts[j++] = vval;
13491339
}
13501340

1341+
rcont = JsonIteratorNext(&ival, &vval, true);
1342+
Assert(rcont == WJB_END_ARRAY);
1343+
Assert(ival == NULL);
1344+
13511345
/* No container elements in temp array, so give up now */
13521346
if (j == 0)
13531347
return false;
@@ -1360,20 +1354,8 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
13601354
for (i = 0; i < nLhsElems; i++)
13611355
{
13621356
/* Nested container value (object or array) */
1363-
JsonIterator *nestval,
1364-
*nestContained;
1365-
bool contains;
1366-
1367-
nestval = JsonIteratorInit(lhsConts[i].val.binary.data);
1368-
nestContained = JsonIteratorInit(vcontained.val.binary.data);
1369-
1370-
contains = JsonbDeepContains(&nestval, &nestContained);
1371-
1372-
if (nestval)
1373-
pfree(nestval);
1374-
if (nestContained)
1375-
pfree(nestContained);
1376-
if (contains)
1357+
if (JsonbDeepContains(lhsConts[i].val.binary.data,
1358+
vcont.val.binary.data))
13771359
break;
13781360
}
13791361

@@ -1385,14 +1367,15 @@ JsonbDeepContains(JsonIterator **val, JsonIterator **mContained)
13851367
return false;
13861368
}
13871369
}
1388-
}
1389-
else
1390-
{
1391-
elog(ERROR, "invalid jsonb container type");
1370+
1371+
Assert(rcont == WJB_END_ARRAY);
1372+
Assert(icont == NULL);
1373+
1374+
if (lhsConts != NULL)
1375+
pfree(lhsConts);
13921376
}
13931377

1394-
elog(ERROR, "unexpectedly fell off end of jsonb container");
1395-
return false;
1378+
return true;
13961379
}
13971380

13981381
/*

src/include/utils/json_generic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ extern JsonContainer *JsonValueToContainer(const JsonValue *val);
268268

269269
extern int JsonCompareContainers(JsonContainer *a, JsonContainer *b);
270270

271-
extern bool JsonbDeepContains(JsonIterator **val, JsonIterator **mContained);
271+
extern bool JsonbDeepContains(JsonContainer *val, JsonContainer *mContained);
272272

273273
extern JsonValue *JsonContainerExtractKeys(JsonContainer *jsc);
274274

0 commit comments

Comments
 (0)