33
33
#define JSONXOID JSONBOID
34
34
#endif
35
35
36
+ typedef struct JsonItemStackEntry
37
+ {
38
+ JsonbValue * item ;
39
+ struct JsonItemStackEntry * parent ;
40
+ } JsonItemStackEntry ;
41
+
42
+ typedef JsonItemStackEntry * JsonItemStack ;
43
+
36
44
typedef struct JsonPathExecContext
37
45
{
38
46
List * vars ;
39
47
bool lax ;
40
48
JsonbValue * root ; /* for $ evaluation */
49
+ JsonItemStack stack ; /* for @N evaluation */
41
50
int innermostArraySize ; /* for LAST array index evaluation */
42
51
} JsonPathExecContext ;
43
52
@@ -106,6 +115,10 @@ static inline JsonPathExecResult recursiveExecute(JsonPathExecContext *cxt,
106
115
static inline JsonPathExecResult recursiveExecuteBool (JsonPathExecContext * cxt ,
107
116
JsonPathItem * jsp , JsonbValue * jb );
108
117
118
+ static inline JsonPathExecResult recursiveExecuteNested (JsonPathExecContext * cxt ,
119
+ JsonPathItem * jsp , JsonbValue * jb ,
120
+ JsonValueList * found );
121
+
109
122
static inline JsonPathExecResult recursiveExecuteUnwrap (JsonPathExecContext * cxt ,
110
123
JsonPathItem * jsp , JsonbValue * jb , JsonValueList * found );
111
124
@@ -245,6 +258,20 @@ JsonbWrapInBinary(JsonbValue *jbv, JsonbValue *out)
245
258
return JsonbInitBinary (out , jb );
246
259
}
247
260
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
+
248
275
/********************Execute functions for JsonPath***************************/
249
276
250
277
/*
@@ -1131,7 +1158,7 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
1131
1158
JsonbValue * jbv ;
1132
1159
JsonValueList found = { 0 };
1133
1160
JsonbValue tmp ;
1134
- JsonPathExecResult res = recursiveExecute (cxt , jsp , jb , & found );
1161
+ JsonPathExecResult res = recursiveExecuteNested (cxt , jsp , jb , & found );
1135
1162
1136
1163
if (jperIsError (res ))
1137
1164
return res ;
@@ -1345,6 +1372,25 @@ appendBoolResult(JsonPathExecContext *cxt, JsonPathItem *jsp,
1345
1372
return recursiveExecuteNext (cxt , jsp , & next , & jbv , found , true);
1346
1373
}
1347
1374
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
+
1348
1394
/*
1349
1395
* Main executor function: walks on jsonpath structure and tries to find
1350
1396
* correspoding parts of jsonb. Note, jsonb and jsonpath values should be
@@ -1457,11 +1503,29 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1457
1503
jb = cxt -> root ;
1458
1504
/* fall through */
1459
1505
case jpiCurrent :
1506
+ case jpiCurrentN :
1460
1507
{
1461
1508
JsonbValue * v ;
1462
1509
JsonbValue vbuf ;
1463
1510
bool copy = true;
1464
1511
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
+
1465
1529
if (JsonbType (jb ) == jbvScalar )
1466
1530
{
1467
1531
if (jspHasNext (jsp ))
@@ -1667,7 +1731,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1667
1731
continue ;
1668
1732
}
1669
1733
1670
- res = recursiveExecute (cxt , & from , jb , & keys );
1734
+ res = recursiveExecuteNested (cxt , & from , jb , & keys );
1671
1735
1672
1736
if (jperIsError (res ))
1673
1737
return res ;
@@ -1818,7 +1882,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1818
1882
break ;
1819
1883
case jpiFilter :
1820
1884
jspGetArg (jsp , & elem );
1821
- res = recursiveExecuteBool (cxt , & elem , jb );
1885
+ res = recursiveExecuteNested (cxt , & elem , jb , NULL );
1822
1886
if (res != jperOk )
1823
1887
res = jperNotFound ;
1824
1888
else
@@ -2248,9 +2312,14 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2248
2312
if (cxt -> lax )
2249
2313
{
2250
2314
JsonValueList reslist = { 0 };
2315
+ JsonItemStackEntry entry ;
2251
2316
2252
2317
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 );
2254
2323
2255
2324
if (jperIsError (res ))
2256
2325
return res ;
@@ -2272,6 +2341,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2272
2341
JsonbIterator * it = NULL ;
2273
2342
JsonbIteratorToken tok ;
2274
2343
JsonValueList result = { 0 };
2344
+ JsonItemStackEntry entry ;
2275
2345
int size = JsonbArraySize (jb );
2276
2346
int i ;
2277
2347
@@ -2286,6 +2356,9 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2286
2356
elog (ERROR , "unexpected jsonb token at the array start" );
2287
2357
}
2288
2358
2359
+ /* push additional stack entry for the whole array */
2360
+ pushJsonItem (& cxt -> stack , & entry , jb );
2361
+
2289
2362
for (i = 0 ; i < size ; i ++ )
2290
2363
{
2291
2364
JsonValueList reslist = { 0 };
@@ -2299,7 +2372,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2299
2372
else
2300
2373
element = & jb -> val .array .elems [i ];
2301
2374
2302
- res = recursiveExecute (cxt , & elem , element , & reslist );
2375
+ res = recursiveExecuteNested (cxt , & elem , element , & reslist );
2303
2376
2304
2377
if (jperIsError (res ))
2305
2378
break ;
@@ -2313,6 +2386,8 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2313
2386
JsonValueListConcat (& result , reslist );
2314
2387
}
2315
2388
2389
+ popJsonItem (& cxt -> stack );
2390
+
2316
2391
if (jperIsError (res ))
2317
2392
break ;
2318
2393
@@ -2580,7 +2655,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2580
2655
v1 -> cb_arg = result ;
2581
2656
v2 -> cb_arg = element ;
2582
2657
2583
- res = recursiveExecute (cxt , & elem , jb , & reslist );
2658
+ res = recursiveExecuteNested (cxt , & elem , jb , & reslist );
2584
2659
2585
2660
if (jperIsError (res ))
2586
2661
return res ;
@@ -2847,14 +2922,18 @@ executeJsonPath(JsonPath *path, List *vars, Jsonb *json, JsonValueList *foundJso
2847
2922
JsonPathExecContext cxt ;
2848
2923
JsonPathItem jsp ;
2849
2924
JsonbValue jbv ;
2925
+ JsonItemStackEntry root ;
2850
2926
2851
2927
jspInit (& jsp , path );
2852
2928
2853
2929
cxt .vars = vars ;
2854
2930
cxt .lax = (path -> header & JSONPATH_LAX ) != 0 ;
2855
2931
cxt .root = JsonbInitBinary (& jbv , json );
2932
+ cxt .stack = NULL ;
2856
2933
cxt .innermostArraySize = -1 ;
2857
2934
2935
+ pushJsonItem (& cxt .stack , & root , cxt .root );
2936
+
2858
2937
if (!cxt .lax && !foundJson )
2859
2938
{
2860
2939
/*
0 commit comments