3333#define JSONXOID JSONBOID
3434#endif
3535
36+ typedef struct JsonItemStackEntry
37+ {
38+ JsonbValue * item ;
39+ struct JsonItemStackEntry * parent ;
40+ } JsonItemStackEntry ;
41+
42+ typedef JsonItemStackEntry * JsonItemStack ;
43+
3644typedef struct JsonPathExecContext
3745{
3846 List * vars ;
3947 bool lax ;
4048 JsonbValue * root ; /* for $ evaluation */
49+ JsonItemStack stack ; /* for @N evaluation */
4150 int innermostArraySize ; /* for LAST array index evaluation */
4251} JsonPathExecContext ;
4352
@@ -106,6 +115,10 @@ static inline JsonPathExecResult recursiveExecute(JsonPathExecContext *cxt,
106115static inline JsonPathExecResult recursiveExecuteBool (JsonPathExecContext * cxt ,
107116 JsonPathItem * jsp , JsonbValue * jb );
108117
118+ static inline JsonPathExecResult recursiveExecuteNested (JsonPathExecContext * cxt ,
119+ JsonPathItem * jsp , JsonbValue * jb ,
120+ JsonValueList * found );
121+
109122static inline JsonPathExecResult recursiveExecuteUnwrap (JsonPathExecContext * cxt ,
110123 JsonPathItem * jsp , JsonbValue * jb , JsonValueList * found );
111124
@@ -245,6 +258,20 @@ JsonbWrapInBinary(JsonbValue *jbv, JsonbValue *out)
245258 return JsonbInitBinary (out , jb );
246259}
247260
261+ static inline void
262+ pushJsonItem (JsonItemStack * stack , JsonItemStackEntry * entry , JsonbValue * item )
263+ {
264+ entry -> item = item ;
265+ entry -> parent = * stack ;
266+ * stack = entry ;
267+ }
268+
269+ static inline void
270+ popJsonItem (JsonItemStack * stack )
271+ {
272+ * stack = (* stack )-> parent ;
273+ }
274+
248275/********************Execute functions for JsonPath***************************/
249276
250277/*
@@ -1131,7 +1158,7 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
11311158 JsonbValue * jbv ;
11321159 JsonValueList found = { 0 };
11331160 JsonbValue tmp ;
1134- JsonPathExecResult res = recursiveExecute (cxt , jsp , jb , & found );
1161+ JsonPathExecResult res = recursiveExecuteNested (cxt , jsp , jb , & found );
11351162
11361163 if (jperIsError (res ))
11371164 return res ;
@@ -1345,6 +1372,25 @@ appendBoolResult(JsonPathExecContext *cxt, JsonPathItem *jsp,
13451372 return recursiveExecuteNext (cxt , jsp , & next , & jbv , found , true);
13461373}
13471374
1375+ static inline JsonPathExecResult
1376+ recursiveExecuteNested (JsonPathExecContext * cxt , JsonPathItem * jsp ,
1377+ JsonbValue * jb , JsonValueList * found )
1378+ {
1379+ JsonItemStackEntry current ;
1380+ JsonPathExecResult res ;
1381+
1382+ pushJsonItem (& cxt -> stack , & current , jb );
1383+
1384+ /* found == NULL is used here when executing boolean filter expressions */
1385+ res = found
1386+ ? recursiveExecute (cxt , jsp , jb , found )
1387+ : recursiveExecuteBool (cxt , jsp , jb );
1388+
1389+ popJsonItem (& cxt -> stack );
1390+
1391+ return res ;
1392+ }
1393+
13481394/*
13491395 * Main executor function: walks on jsonpath structure and tries to find
13501396 * correspoding parts of jsonb. Note, jsonb and jsonpath values should be
@@ -1457,11 +1503,29 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
14571503 jb = cxt -> root ;
14581504 /* fall through */
14591505 case jpiCurrent :
1506+ case jpiCurrentN :
14601507 {
14611508 JsonbValue * v ;
14621509 JsonbValue vbuf ;
14631510 bool copy = true;
14641511
1512+ if (jsp -> type == jpiCurrentN )
1513+ {
1514+ int i ;
1515+ JsonItemStackEntry * current = cxt -> stack ;
1516+
1517+ for (i = 0 ; i < jsp -> content .current .level ; i ++ )
1518+ {
1519+ current = current -> parent ;
1520+
1521+ if (!current )
1522+ elog (ERROR ,
1523+ "invalid jsonpath current item reference" );
1524+ }
1525+
1526+ jb = current -> item ;
1527+ }
1528+
14651529 if (JsonbType (jb ) == jbvScalar )
14661530 {
14671531 if (jspHasNext (jsp ))
@@ -1667,7 +1731,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
16671731 continue ;
16681732 }
16691733
1670- res = recursiveExecute (cxt , & from , jb , & keys );
1734+ res = recursiveExecuteNested (cxt , & from , jb , & keys );
16711735
16721736 if (jperIsError (res ))
16731737 return res ;
@@ -1818,7 +1882,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
18181882 break ;
18191883 case jpiFilter :
18201884 jspGetArg (jsp , & elem );
1821- res = recursiveExecuteBool (cxt , & elem , jb );
1885+ res = recursiveExecuteNested (cxt , & elem , jb , NULL );
18221886 if (res != jperOk )
18231887 res = jperNotFound ;
18241888 else
@@ -2248,9 +2312,14 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
22482312 if (cxt -> lax )
22492313 {
22502314 JsonValueList reslist = { 0 };
2315+ JsonItemStackEntry entry ;
22512316
22522317 jspGetArg (jsp , & elem );
2253- res = recursiveExecute (cxt , & elem , jb , & reslist );
2318+
2319+ /* push additional stack entry for the whole item */
2320+ pushJsonItem (& cxt -> stack , & entry , jb );
2321+ res = recursiveExecuteNested (cxt , & elem , jb , & reslist );
2322+ popJsonItem (& cxt -> stack );
22542323
22552324 if (jperIsError (res ))
22562325 return res ;
@@ -2272,6 +2341,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
22722341 JsonbIterator * it = NULL ;
22732342 JsonbIteratorToken tok ;
22742343 JsonValueList result = { 0 };
2344+ JsonItemStackEntry entry ;
22752345 int size = JsonbArraySize (jb );
22762346 int i ;
22772347
@@ -2286,6 +2356,9 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
22862356 elog (ERROR , "unexpected jsonb token at the array start" );
22872357 }
22882358
2359+ /* push additional stack entry for the whole array */
2360+ pushJsonItem (& cxt -> stack , & entry , jb );
2361+
22892362 for (i = 0 ; i < size ; i ++ )
22902363 {
22912364 JsonValueList reslist = { 0 };
@@ -2299,7 +2372,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
22992372 else
23002373 element = & jb -> val .array .elems [i ];
23012374
2302- res = recursiveExecute (cxt , & elem , element , & reslist );
2375+ res = recursiveExecuteNested (cxt , & elem , element , & reslist );
23032376
23042377 if (jperIsError (res ))
23052378 break ;
@@ -2313,6 +2386,8 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
23132386 JsonValueListConcat (& result , reslist );
23142387 }
23152388
2389+ popJsonItem (& cxt -> stack );
2390+
23162391 if (jperIsError (res ))
23172392 break ;
23182393
@@ -2580,7 +2655,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
25802655 v1 -> cb_arg = result ;
25812656 v2 -> cb_arg = element ;
25822657
2583- res = recursiveExecute (cxt , & elem , jb , & reslist );
2658+ res = recursiveExecuteNested (cxt , & elem , jb , & reslist );
25842659
25852660 if (jperIsError (res ))
25862661 return res ;
@@ -2847,14 +2922,18 @@ executeJsonPath(JsonPath *path, List *vars, Jsonb *json, JsonValueList *foundJso
28472922 JsonPathExecContext cxt ;
28482923 JsonPathItem jsp ;
28492924 JsonbValue jbv ;
2925+ JsonItemStackEntry root ;
28502926
28512927 jspInit (& jsp , path );
28522928
28532929 cxt .vars = vars ;
28542930 cxt .lax = (path -> header & JSONPATH_LAX ) != 0 ;
28552931 cxt .root = JsonbInitBinary (& jbv , json );
2932+ cxt .stack = NULL ;
28562933 cxt .innermostArraySize = -1 ;
28572934
2935+ pushJsonItem (& cxt .stack , & root , cxt .root );
2936+
28582937 if (!cxt .lax && !foundJson )
28592938 {
28602939 /*
0 commit comments