26
26
typedef struct JsonPathExecContext
27
27
{
28
28
List * vars ;
29
- bool lax ;
30
29
JsonbValue * root ; /* for $ evaluation */
31
30
int innermostArraySize ; /* for LAST array index evaluation */
31
+ bool laxMode ;
32
+ bool ignoreStructuralErrors ;
32
33
} JsonPathExecContext ;
33
34
35
+ /* strict/lax flags is decomposed into four [un]wrap/error flags */
36
+ #define jspStrictAbsenseOfErrors (cxt ) (!(cxt)->laxMode)
37
+ #define jspAutoUnwrap (cxt ) ((cxt)->laxMode)
38
+ #define jspAutoWrap (cxt ) ((cxt)->laxMode)
39
+ #define jspIgnoreStructuralErrors (cxt ) ((cxt)->ignoreStructuralErrors)
40
+
34
41
typedef struct JsonValueListIterator
35
42
{
36
43
ListCell * lcell ;
@@ -724,7 +731,7 @@ static inline JsonPathExecResult
724
731
recursiveExecuteAndUnwrap (JsonPathExecContext * cxt , JsonPathItem * jsp ,
725
732
JsonbValue * jb , JsonValueList * found )
726
733
{
727
- if (cxt -> lax )
734
+ if (jspAutoUnwrap ( cxt ) )
728
735
{
729
736
JsonValueList seq = { 0 };
730
737
JsonValueListIterator it = { 0 };
@@ -816,14 +823,14 @@ executeExpr(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb)
816
823
817
824
if (res == jperOk )
818
825
{
819
- if (cxt -> lax )
826
+ if (! jspStrictAbsenseOfErrors ( cxt ) )
820
827
return jperOk ;
821
828
822
829
found = true;
823
830
}
824
831
else if (res == jperError )
825
832
{
826
- if (! cxt -> lax )
833
+ if (jspStrictAbsenseOfErrors ( cxt ) )
827
834
return jperError ;
828
835
829
836
error = true;
@@ -1153,7 +1160,7 @@ executeStartsWithPredicate(JsonPathExecContext *cxt, JsonPathItem *jsp,
1153
1160
1154
1161
if (whole -> type != jbvString )
1155
1162
{
1156
- if (! cxt -> lax )
1163
+ if (jspStrictAbsenseOfErrors ( cxt ) )
1157
1164
return jperError ;
1158
1165
1159
1166
error = true;
@@ -1163,7 +1170,7 @@ executeStartsWithPredicate(JsonPathExecContext *cxt, JsonPathItem *jsp,
1163
1170
initial -> val .string .val ,
1164
1171
initial -> val .string .len ))
1165
1172
{
1166
- if (cxt -> lax )
1173
+ if (! jspStrictAbsenseOfErrors ( cxt ) )
1167
1174
return jperOk ;
1168
1175
1169
1176
found = true;
@@ -1220,7 +1227,7 @@ executeLikeRegexPredicate(JsonPathExecContext *cxt, JsonPathItem *jsp,
1220
1227
1221
1228
if (str -> type != jbvString )
1222
1229
{
1223
- if (! cxt -> lax )
1230
+ if (jspStrictAbsenseOfErrors ( cxt ) )
1224
1231
return jperError ;
1225
1232
1226
1233
error = true;
@@ -1229,7 +1236,7 @@ executeLikeRegexPredicate(JsonPathExecContext *cxt, JsonPathItem *jsp,
1229
1236
str -> val .string .len , cflags ,
1230
1237
DEFAULT_COLLATION_OID , 0 , NULL ))
1231
1238
{
1232
- if (cxt -> lax )
1239
+ if (! jspStrictAbsenseOfErrors ( cxt ) )
1233
1240
return jperOk ;
1234
1241
1235
1242
found = true;
@@ -1400,13 +1407,13 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1400
1407
if (jspHasNext (jsp ) || !found )
1401
1408
pfree (v ); /* free value if it was not added to found list */
1402
1409
}
1403
- else if (!cxt -> lax )
1410
+ else if (!jspIgnoreStructuralErrors ( cxt ) )
1404
1411
{
1405
1412
Assert (found );
1406
1413
res = jperMakeError (ERRCODE_JSON_MEMBER_NOT_FOUND );
1407
1414
}
1408
1415
}
1409
- else if (!cxt -> lax )
1416
+ else if (!jspIgnoreStructuralErrors ( cxt ) )
1410
1417
{
1411
1418
Assert (found );
1412
1419
res = jperMakeError (ERRCODE_JSON_MEMBER_NOT_FOUND );
@@ -1483,7 +1490,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1483
1490
}
1484
1491
}
1485
1492
}
1486
- else
1493
+ else if (! jspIgnoreStructuralErrors ( cxt ))
1487
1494
res = jperMakeError (ERRCODE_JSON_ARRAY_NOT_FOUND );
1488
1495
break ;
1489
1496
@@ -1523,7 +1530,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1523
1530
else
1524
1531
index_to = index_from ;
1525
1532
1526
- if (!cxt -> lax &&
1533
+ if (!jspIgnoreStructuralErrors ( cxt ) &&
1527
1534
(index_from < 0 ||
1528
1535
index_from > index_to ||
1529
1536
index_to >= size ))
@@ -1569,8 +1576,10 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1569
1576
1570
1577
cxt -> innermostArraySize = innermostArraySize ;
1571
1578
}
1572
- else
1579
+ else if (!jspIgnoreStructuralErrors (cxt ))
1580
+ {
1573
1581
res = jperMakeError (ERRCODE_JSON_ARRAY_NOT_FOUND );
1582
+ }
1574
1583
break ;
1575
1584
1576
1585
case jpiLast :
@@ -1631,7 +1640,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1631
1640
}
1632
1641
}
1633
1642
}
1634
- else if (!cxt -> lax )
1643
+ else if (!jspIgnoreStructuralErrors ( cxt ) )
1635
1644
{
1636
1645
Assert (found );
1637
1646
res = jperMakeError (ERRCODE_JSON_OBJECT_NOT_FOUND );
@@ -1693,9 +1702,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1693
1702
case jpiExists :
1694
1703
jspGetArg (jsp , & elem );
1695
1704
1696
- if (cxt -> lax )
1697
- res = recursiveExecute (cxt , & elem , jb , NULL );
1698
- else
1705
+ if (jspStrictAbsenseOfErrors (cxt ))
1699
1706
{
1700
1707
JsonValueList vals = { 0 };
1701
1708
@@ -1708,6 +1715,10 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1708
1715
if (!jperIsError (res ))
1709
1716
res = JsonValueListIsEmpty (& vals ) ? jperNotFound : jperOk ;
1710
1717
}
1718
+ else
1719
+ {
1720
+ res = recursiveExecute (cxt , & elem , jb , NULL );
1721
+ }
1711
1722
1712
1723
res = appendBoolResult (cxt , jsp , found , res , needBool );
1713
1724
break ;
@@ -1751,9 +1762,10 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1751
1762
1752
1763
if (size < 0 )
1753
1764
{
1754
- if (!cxt -> lax )
1765
+ if (!jspAutoWrap ( cxt ) )
1755
1766
{
1756
- res = jperMakeError (ERRCODE_JSON_ARRAY_NOT_FOUND );
1767
+ if (!jspIgnoreStructuralErrors (cxt ))
1768
+ res = jperMakeError (ERRCODE_JSON_ARRAY_NOT_FOUND );
1757
1769
break ;
1758
1770
}
1759
1771
@@ -2120,7 +2132,7 @@ static inline JsonPathExecResult
2120
2132
recursiveExecuteUnwrap (JsonPathExecContext * cxt , JsonPathItem * jsp ,
2121
2133
JsonbValue * jb , JsonValueList * found )
2122
2134
{
2123
- if (cxt -> lax && JsonbType (jb ) == jbvArray )
2135
+ if (jspAutoUnwrap ( cxt ) && JsonbType (jb ) == jbvArray )
2124
2136
return recursiveExecuteUnwrapArray (cxt , jsp , jb , found );
2125
2137
2126
2138
return recursiveExecuteNoUnwrap (cxt , jsp , jb , found , false);
@@ -2172,7 +2184,7 @@ static inline JsonPathExecResult
2172
2184
recursiveExecute (JsonPathExecContext * cxt , JsonPathItem * jsp , JsonbValue * jb ,
2173
2185
JsonValueList * found )
2174
2186
{
2175
- if (cxt -> lax )
2187
+ if (jspAutoUnwrap ( cxt ) )
2176
2188
{
2177
2189
switch (jsp -> type )
2178
2190
{
@@ -2247,11 +2259,12 @@ executeJsonPath(JsonPath *path, List *vars, Jsonb *json, JsonValueList *foundJso
2247
2259
jspInit (& jsp , path );
2248
2260
2249
2261
cxt .vars = vars ;
2250
- cxt .lax = (path -> header & JSONPATH_LAX ) != 0 ;
2262
+ cxt .laxMode = (path -> header & JSONPATH_LAX ) != 0 ;
2263
+ cxt .ignoreStructuralErrors = cxt .laxMode ;
2251
2264
cxt .root = JsonbInitBinary (& jbv , json );
2252
2265
cxt .innermostArraySize = -1 ;
2253
2266
2254
- if (! cxt . lax && !foundJson )
2267
+ if (jspStrictAbsenseOfErrors ( & cxt ) && !foundJson )
2255
2268
{
2256
2269
/*
2257
2270
* In strict mode we must get a complete list of values to check
0 commit comments