Skip to content

Commit 14deee5

Browse files
author
Nikita Glukhov
committed
Decompose jsonpath strict/lax flag
1 parent 0864532 commit 14deee5

File tree

1 file changed

+36
-23
lines changed

1 file changed

+36
-23
lines changed

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,18 @@
2727
typedef struct JsonPathExecContext
2828
{
2929
List *vars;
30-
bool lax;
3130
JsonbValue *root; /* for $ evaluation */
3231
int innermostArraySize; /* for LAST array index evaluation */
32+
bool laxMode;
33+
bool ignoreStructuralErrors;
3334
} JsonPathExecContext;
3435

36+
/* strict/lax flags is decomposed into four [un]wrap/error flags */
37+
#define jspStrictAbsenseOfErrors(cxt) (!(cxt)->laxMode)
38+
#define jspAutoUnwrap(cxt) ((cxt)->laxMode)
39+
#define jspAutoWrap(cxt) ((cxt)->laxMode)
40+
#define jspIgnoreStructuralErrors(cxt) ((cxt)->ignoreStructuralErrors)
41+
3542
typedef struct JsonValueListIterator
3643
{
3744
ListCell *lcell;
@@ -693,7 +700,7 @@ static inline JsonPathExecResult
693700
recursiveExecuteAndUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
694701
JsonbValue *jb, JsonValueList *found)
695702
{
696-
if (cxt->lax)
703+
if (jspAutoUnwrap(cxt))
697704
{
698705
JsonValueList seq = { 0 };
699706
JsonValueListIterator it = { 0 };
@@ -785,14 +792,14 @@ executeExpr(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb)
785792

786793
if (res == jperOk)
787794
{
788-
if (cxt->lax)
795+
if (!jspStrictAbsenseOfErrors(cxt))
789796
return jperOk;
790797

791798
found = true;
792799
}
793800
else if (res == jperError)
794801
{
795-
if (!cxt->lax)
802+
if (jspStrictAbsenseOfErrors(cxt))
796803
return jperError;
797804

798805
error = true;
@@ -1122,7 +1129,7 @@ executeStartsWithPredicate(JsonPathExecContext *cxt, JsonPathItem *jsp,
11221129

11231130
if (whole->type != jbvString)
11241131
{
1125-
if (!cxt->lax)
1132+
if (jspStrictAbsenseOfErrors(cxt))
11261133
return jperError;
11271134

11281135
error = true;
@@ -1132,7 +1139,7 @@ executeStartsWithPredicate(JsonPathExecContext *cxt, JsonPathItem *jsp,
11321139
initial->val.string.val,
11331140
initial->val.string.len))
11341141
{
1135-
if (cxt->lax)
1142+
if (!jspStrictAbsenseOfErrors(cxt))
11361143
return jperOk;
11371144

11381145
found = true;
@@ -1189,7 +1196,7 @@ executeLikeRegexPredicate(JsonPathExecContext *cxt, JsonPathItem *jsp,
11891196

11901197
if (str->type != jbvString)
11911198
{
1192-
if (!cxt->lax)
1199+
if (jspStrictAbsenseOfErrors(cxt))
11931200
return jperError;
11941201

11951202
error = true;
@@ -1198,7 +1205,7 @@ executeLikeRegexPredicate(JsonPathExecContext *cxt, JsonPathItem *jsp,
11981205
str->val.string.len, cflags,
11991206
DEFAULT_COLLATION_OID, 0, NULL))
12001207
{
1201-
if (cxt->lax)
1208+
if (!jspStrictAbsenseOfErrors(cxt))
12021209
return jperOk;
12031210

12041211
found = true;
@@ -1370,13 +1377,13 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
13701377
if (jspHasNext(jsp) || !found)
13711378
pfree(v); /* free value if it was not added to found list */
13721379
}
1373-
else if (!cxt->lax)
1380+
else if (!jspIgnoreStructuralErrors(cxt))
13741381
{
13751382
Assert(found);
13761383
res = jperMakeError(ERRCODE_JSON_MEMBER_NOT_FOUND);
13771384
}
13781385
}
1379-
else if (!cxt->lax)
1386+
else if (!jspIgnoreStructuralErrors(cxt))
13801387
{
13811388
Assert(found);
13821389
res = jperMakeError(ERRCODE_JSON_MEMBER_NOT_FOUND);
@@ -1453,7 +1460,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
14531460
}
14541461
}
14551462
}
1456-
else
1463+
else if (!jspIgnoreStructuralErrors(cxt))
14571464
res = jperMakeError(ERRCODE_JSON_ARRAY_NOT_FOUND);
14581465
break;
14591466

@@ -1493,7 +1500,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
14931500
else
14941501
index_to = index_from;
14951502

1496-
if (!cxt->lax &&
1503+
if (!jspIgnoreStructuralErrors(cxt) &&
14971504
(index_from < 0 ||
14981505
index_from > index_to ||
14991506
index_to >= size))
@@ -1539,8 +1546,10 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
15391546

15401547
cxt->innermostArraySize = innermostArraySize;
15411548
}
1542-
else
1549+
else if (!jspIgnoreStructuralErrors(cxt))
1550+
{
15431551
res = jperMakeError(ERRCODE_JSON_ARRAY_NOT_FOUND);
1552+
}
15441553
break;
15451554

15461555
case jpiLast:
@@ -1601,7 +1610,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
16011610
}
16021611
}
16031612
}
1604-
else if (!cxt->lax)
1613+
else if (!jspIgnoreStructuralErrors(cxt))
16051614
{
16061615
Assert(found);
16071616
res = jperMakeError(ERRCODE_JSON_OBJECT_NOT_FOUND);
@@ -1663,9 +1672,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
16631672
case jpiExists:
16641673
jspGetArg(jsp, &elem);
16651674

1666-
if (cxt->lax)
1667-
res = recursiveExecute(cxt, &elem, jb, NULL);
1668-
else
1675+
if (jspStrictAbsenseOfErrors(cxt))
16691676
{
16701677
JsonValueList vals = { 0 };
16711678

@@ -1678,6 +1685,10 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
16781685
if (!jperIsError(res))
16791686
res = JsonValueListIsEmpty(&vals) ? jperNotFound : jperOk;
16801687
}
1688+
else
1689+
{
1690+
res = recursiveExecute(cxt, &elem, jb, NULL);
1691+
}
16811692

16821693
res = appendBoolResult(cxt, jsp, found, res, needBool);
16831694
break;
@@ -1721,9 +1732,10 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
17211732

17221733
if (size < 0)
17231734
{
1724-
if (!cxt->lax)
1735+
if (!jspAutoWrap(cxt))
17251736
{
1726-
res = jperMakeError(ERRCODE_JSON_ARRAY_NOT_FOUND);
1737+
if (!jspIgnoreStructuralErrors(cxt))
1738+
res = jperMakeError(ERRCODE_JSON_ARRAY_NOT_FOUND);
17271739
break;
17281740
}
17291741

@@ -2090,7 +2102,7 @@ static inline JsonPathExecResult
20902102
recursiveExecuteUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
20912103
JsonbValue *jb, JsonValueList *found)
20922104
{
2093-
if (cxt->lax && JsonbType(jb) == jbvArray)
2105+
if (jspAutoUnwrap(cxt) && JsonbType(jb) == jbvArray)
20942106
return recursiveExecuteUnwrapArray(cxt, jsp, jb, found);
20952107

20962108
return recursiveExecuteNoUnwrap(cxt, jsp, jb, found, false);
@@ -2142,7 +2154,7 @@ static inline JsonPathExecResult
21422154
recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
21432155
JsonValueList *found)
21442156
{
2145-
if (cxt->lax)
2157+
if (jspAutoUnwrap(cxt))
21462158
{
21472159
switch (jsp->type)
21482160
{
@@ -2217,11 +2229,12 @@ executeJsonPath(JsonPath *path, List *vars, Jsonb *json, JsonValueList *foundJso
22172229
jspInit(&jsp, path);
22182230

22192231
cxt.vars = vars;
2220-
cxt.lax = (path->header & JSONPATH_LAX) != 0;
2232+
cxt.laxMode = (path->header & JSONPATH_LAX) != 0;
2233+
cxt.ignoreStructuralErrors = cxt.laxMode;
22212234
cxt.root = JsonbInitBinary(&jbv, json);
22222235
cxt.innermostArraySize = -1;
22232236

2224-
if (!cxt.lax && !foundJson)
2237+
if (jspStrictAbsenseOfErrors(&cxt) && !foundJson)
22252238
{
22262239
/*
22272240
* In strict mode we must get a complete list of values to check

0 commit comments

Comments
 (0)