3232#define JSONXOID JSONBOID
3333#endif
3434
35+ typedef struct JsonItemStackEntry
36+ {
37+ JsonbValue * item ;
38+ struct JsonItemStackEntry * parent ;
39+ } JsonItemStackEntry ;
40+
41+ typedef JsonItemStackEntry * JsonItemStack ;
42+
3543typedef struct JsonPathExecContext
3644{
3745 List * vars ;
3846 bool lax ;
3947 JsonbValue * root ; /* for $ evaluation */
48+ JsonItemStack stack ; /* for @N evaluation */
4049 int innermostArraySize ; /* for LAST array index evaluation */
4150} JsonPathExecContext ;
4251
@@ -105,6 +114,10 @@ static inline JsonPathExecResult recursiveExecute(JsonPathExecContext *cxt,
105114static inline JsonPathExecResult recursiveExecuteBool (JsonPathExecContext * cxt ,
106115 JsonPathItem * jsp , JsonbValue * jb );
107116
117+ static inline JsonPathExecResult recursiveExecuteNested (JsonPathExecContext * cxt ,
118+ JsonPathItem * jsp , JsonbValue * jb ,
119+ JsonValueList * found );
120+
108121static inline JsonPathExecResult recursiveExecuteUnwrap (JsonPathExecContext * cxt ,
109122 JsonPathItem * jsp , JsonbValue * jb , JsonValueList * found );
110123
@@ -244,6 +257,20 @@ JsonbWrapInBinary(JsonbValue *jbv, JsonbValue *out)
244257 return JsonbInitBinary (out , jb );
245258}
246259
260+ static inline void
261+ pushJsonItem (JsonItemStack * stack , JsonItemStackEntry * entry , JsonbValue * item )
262+ {
263+ entry -> item = item ;
264+ entry -> parent = * stack ;
265+ * stack = entry ;
266+ }
267+
268+ static inline void
269+ popJsonItem (JsonItemStack * stack )
270+ {
271+ * stack = (* stack )-> parent ;
272+ }
273+
247274/********************Execute functions for JsonPath***************************/
248275
249276/*
@@ -1053,7 +1080,7 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
10531080 JsonbValue * jbv ;
10541081 JsonValueList found = { 0 };
10551082 JsonbValue tmp ;
1056- JsonPathExecResult res = recursiveExecute (cxt , jsp , jb , & found );
1083+ JsonPathExecResult res = recursiveExecuteNested (cxt , jsp , jb , & found );
10571084
10581085 if (jperIsError (res ))
10591086 return res ;
@@ -1201,6 +1228,25 @@ appendBoolResult(JsonPathExecContext *cxt, JsonPathItem *jsp,
12011228 return recursiveExecuteNext (cxt , jsp , & next , & jbv , found , true);
12021229}
12031230
1231+ static inline JsonPathExecResult
1232+ recursiveExecuteNested (JsonPathExecContext * cxt , JsonPathItem * jsp ,
1233+ JsonbValue * jb , JsonValueList * found )
1234+ {
1235+ JsonItemStackEntry current ;
1236+ JsonPathExecResult res ;
1237+
1238+ pushJsonItem (& cxt -> stack , & current , jb );
1239+
1240+ /* found == NULL is used here when executing boolean filter expressions */
1241+ res = found
1242+ ? recursiveExecute (cxt , jsp , jb , found )
1243+ : recursiveExecuteBool (cxt , jsp , jb );
1244+
1245+ popJsonItem (& cxt -> stack );
1246+
1247+ return res ;
1248+ }
1249+
12041250/*
12051251 * Main executor function: walks on jsonpath structure and tries to find
12061252 * correspoding parts of jsonb. Note, jsonb and jsonpath values should be
@@ -1307,11 +1353,29 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
13071353 jb = cxt -> root ;
13081354 /* fall through */
13091355 case jpiCurrent :
1356+ case jpiCurrentN :
13101357 {
13111358 JsonbValue * v ;
13121359 JsonbValue vbuf ;
13131360 bool copy = true;
13141361
1362+ if (jsp -> type == jpiCurrentN )
1363+ {
1364+ int i ;
1365+ JsonItemStackEntry * current = cxt -> stack ;
1366+
1367+ for (i = 0 ; i < jsp -> content .current .level ; i ++ )
1368+ {
1369+ current = current -> parent ;
1370+
1371+ if (!current )
1372+ elog (ERROR ,
1373+ "invalid jsonpath current item reference" );
1374+ }
1375+
1376+ jb = current -> item ;
1377+ }
1378+
13151379 if (JsonbType (jb ) == jbvScalar )
13161380 {
13171381 if (jspHasNext (jsp ))
@@ -1517,7 +1581,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
15171581 continue ;
15181582 }
15191583
1520- res = recursiveExecute (cxt , & from , jb , & keys );
1584+ res = recursiveExecuteNested (cxt , & from , jb , & keys );
15211585
15221586 if (jperIsError (res ))
15231587 return res ;
@@ -1665,7 +1729,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
16651729 break ;
16661730 case jpiFilter :
16671731 jspGetArg (jsp , & elem );
1668- res = recursiveExecuteBool (cxt , & elem , jb );
1732+ res = recursiveExecuteNested (cxt , & elem , jb , NULL );
16691733 if (res != jperOk )
16701734 res = jperNotFound ;
16711735 else
@@ -2075,9 +2139,14 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
20752139 if (cxt -> lax )
20762140 {
20772141 JsonValueList reslist = { 0 };
2142+ JsonItemStackEntry entry ;
20782143
20792144 jspGetArg (jsp , & elem );
2080- res = recursiveExecute (cxt , & elem , jb , & reslist );
2145+
2146+ /* push additional stack entry for the whole item */
2147+ pushJsonItem (& cxt -> stack , & entry , jb );
2148+ res = recursiveExecuteNested (cxt , & elem , jb , & reslist );
2149+ popJsonItem (& cxt -> stack );
20812150
20822151 if (jperIsError (res ))
20832152 return res ;
@@ -2099,6 +2168,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
20992168 JsonbIterator * it = NULL ;
21002169 JsonbIteratorToken tok ;
21012170 JsonValueList result = { 0 };
2171+ JsonItemStackEntry entry ;
21022172 int size = JsonbArraySize (jb );
21032173 int i ;
21042174
@@ -2113,6 +2183,9 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
21132183 elog (ERROR , "unexpected jsonb token at the array start" );
21142184 }
21152185
2186+ /* push additional stack entry for the whole array */
2187+ pushJsonItem (& cxt -> stack , & entry , jb );
2188+
21162189 for (i = 0 ; i < size ; i ++ )
21172190 {
21182191 JsonValueList reslist = { 0 };
@@ -2126,7 +2199,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
21262199 else
21272200 element = & jb -> val .array .elems [i ];
21282201
2129- res = recursiveExecute (cxt , & elem , element , & reslist );
2202+ res = recursiveExecuteNested (cxt , & elem , element , & reslist );
21302203
21312204 if (jperIsError (res ))
21322205 break ;
@@ -2140,6 +2213,8 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
21402213 JsonValueListConcat (& result , reslist );
21412214 }
21422215
2216+ popJsonItem (& cxt -> stack );
2217+
21432218 if (jperIsError (res ))
21442219 break ;
21452220
@@ -2407,7 +2482,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
24072482 v1 -> cb_arg = result ;
24082483 v2 -> cb_arg = element ;
24092484
2410- res = recursiveExecute (cxt , & elem , jb , & reslist );
2485+ res = recursiveExecuteNested (cxt , & elem , jb , & reslist );
24112486
24122487 if (jperIsError (res ))
24132488 return res ;
@@ -2656,14 +2731,18 @@ executeJsonPath(JsonPath *path, List *vars, Jsonb *json, JsonValueList *foundJso
26562731 JsonPathExecContext cxt ;
26572732 JsonPathItem jsp ;
26582733 JsonbValue jbv ;
2734+ JsonItemStackEntry root ;
26592735
26602736 jspInit (& jsp , path );
26612737
26622738 cxt .vars = vars ;
26632739 cxt .lax = (path -> header & JSONPATH_LAX ) != 0 ;
26642740 cxt .root = JsonbInitBinary (& jbv , json );
2741+ cxt .stack = NULL ;
26652742 cxt .innermostArraySize = -1 ;
26662743
2744+ pushJsonItem (& cxt .stack , & root , cxt .root );
2745+
26672746 return recursiveExecute (& cxt , & jsp , & jbv , foundJson );
26682747}
26692748
0 commit comments