2727typedef 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+
3542typedef struct JsonValueListIterator
3643{
3744 ListCell * lcell ;
@@ -693,7 +700,7 @@ static inline JsonPathExecResult
693700recursiveExecuteAndUnwrap (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
20902102recursiveExecuteUnwrap (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
21422154recursiveExecute (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