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