32
32
#define JSONXOID JSONBOID
33
33
#endif
34
34
35
+ typedef struct JsonItemStackEntry
36
+ {
37
+ JsonbValue * item ;
38
+ struct JsonItemStackEntry * parent ;
39
+ } JsonItemStackEntry ;
40
+
41
+ typedef JsonItemStackEntry * JsonItemStack ;
42
+
35
43
typedef struct JsonPathExecContext
36
44
{
37
45
List * vars ;
38
46
bool lax ;
39
47
JsonbValue * root ; /* for $ evaluation */
48
+ JsonItemStack stack ; /* for @N evaluation */
40
49
int innermostArraySize ; /* for LAST array index evaluation */
41
50
} JsonPathExecContext ;
42
51
@@ -105,6 +114,10 @@ static inline JsonPathExecResult recursiveExecute(JsonPathExecContext *cxt,
105
114
static inline JsonPathExecResult recursiveExecuteBool (JsonPathExecContext * cxt ,
106
115
JsonPathItem * jsp , JsonbValue * jb );
107
116
117
+ static inline JsonPathExecResult recursiveExecuteNested (JsonPathExecContext * cxt ,
118
+ JsonPathItem * jsp , JsonbValue * jb ,
119
+ JsonValueList * found );
120
+
108
121
static inline JsonPathExecResult recursiveExecuteUnwrap (JsonPathExecContext * cxt ,
109
122
JsonPathItem * jsp , JsonbValue * jb , JsonValueList * found );
110
123
@@ -244,6 +257,20 @@ JsonbWrapInBinary(JsonbValue *jbv, JsonbValue *out)
244
257
return JsonbInitBinary (out , jb );
245
258
}
246
259
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
+
247
274
/********************Execute functions for JsonPath***************************/
248
275
249
276
/*
@@ -1053,7 +1080,7 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
1053
1080
JsonbValue * jbv ;
1054
1081
JsonValueList found = { 0 };
1055
1082
JsonbValue tmp ;
1056
- JsonPathExecResult res = recursiveExecute (cxt , jsp , jb , & found );
1083
+ JsonPathExecResult res = recursiveExecuteNested (cxt , jsp , jb , & found );
1057
1084
1058
1085
if (jperIsError (res ))
1059
1086
return res ;
@@ -1201,6 +1228,25 @@ appendBoolResult(JsonPathExecContext *cxt, JsonPathItem *jsp,
1201
1228
return recursiveExecuteNext (cxt , jsp , & next , & jbv , found , true);
1202
1229
}
1203
1230
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
+
1204
1250
/*
1205
1251
* Main executor function: walks on jsonpath structure and tries to find
1206
1252
* correspoding parts of jsonb. Note, jsonb and jsonpath values should be
@@ -1307,11 +1353,29 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1307
1353
jb = cxt -> root ;
1308
1354
/* fall through */
1309
1355
case jpiCurrent :
1356
+ case jpiCurrentN :
1310
1357
{
1311
1358
JsonbValue * v ;
1312
1359
JsonbValue vbuf ;
1313
1360
bool copy = true;
1314
1361
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
+
1315
1379
if (JsonbType (jb ) == jbvScalar )
1316
1380
{
1317
1381
if (jspHasNext (jsp ))
@@ -1517,7 +1581,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1517
1581
continue ;
1518
1582
}
1519
1583
1520
- res = recursiveExecute (cxt , & from , jb , & keys );
1584
+ res = recursiveExecuteNested (cxt , & from , jb , & keys );
1521
1585
1522
1586
if (jperIsError (res ))
1523
1587
return res ;
@@ -1665,7 +1729,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1665
1729
break ;
1666
1730
case jpiFilter :
1667
1731
jspGetArg (jsp , & elem );
1668
- res = recursiveExecuteBool (cxt , & elem , jb );
1732
+ res = recursiveExecuteNested (cxt , & elem , jb , NULL );
1669
1733
if (res != jperOk )
1670
1734
res = jperNotFound ;
1671
1735
else
@@ -2075,9 +2139,14 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2075
2139
if (cxt -> lax )
2076
2140
{
2077
2141
JsonValueList reslist = { 0 };
2142
+ JsonItemStackEntry entry ;
2078
2143
2079
2144
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 );
2081
2150
2082
2151
if (jperIsError (res ))
2083
2152
return res ;
@@ -2099,6 +2168,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2099
2168
JsonbIterator * it = NULL ;
2100
2169
JsonbIteratorToken tok ;
2101
2170
JsonValueList result = { 0 };
2171
+ JsonItemStackEntry entry ;
2102
2172
int size = JsonbArraySize (jb );
2103
2173
int i ;
2104
2174
@@ -2113,6 +2183,9 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2113
2183
elog (ERROR , "unexpected jsonb token at the array start" );
2114
2184
}
2115
2185
2186
+ /* push additional stack entry for the whole array */
2187
+ pushJsonItem (& cxt -> stack , & entry , jb );
2188
+
2116
2189
for (i = 0 ; i < size ; i ++ )
2117
2190
{
2118
2191
JsonValueList reslist = { 0 };
@@ -2126,7 +2199,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2126
2199
else
2127
2200
element = & jb -> val .array .elems [i ];
2128
2201
2129
- res = recursiveExecute (cxt , & elem , element , & reslist );
2202
+ res = recursiveExecuteNested (cxt , & elem , element , & reslist );
2130
2203
2131
2204
if (jperIsError (res ))
2132
2205
break ;
@@ -2140,6 +2213,8 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2140
2213
JsonValueListConcat (& result , reslist );
2141
2214
}
2142
2215
2216
+ popJsonItem (& cxt -> stack );
2217
+
2143
2218
if (jperIsError (res ))
2144
2219
break ;
2145
2220
@@ -2407,7 +2482,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2407
2482
v1 -> cb_arg = result ;
2408
2483
v2 -> cb_arg = element ;
2409
2484
2410
- res = recursiveExecute (cxt , & elem , jb , & reslist );
2485
+ res = recursiveExecuteNested (cxt , & elem , jb , & reslist );
2411
2486
2412
2487
if (jperIsError (res ))
2413
2488
return res ;
@@ -2656,14 +2731,18 @@ executeJsonPath(JsonPath *path, List *vars, Jsonb *json, JsonValueList *foundJso
2656
2731
JsonPathExecContext cxt ;
2657
2732
JsonPathItem jsp ;
2658
2733
JsonbValue jbv ;
2734
+ JsonItemStackEntry root ;
2659
2735
2660
2736
jspInit (& jsp , path );
2661
2737
2662
2738
cxt .vars = vars ;
2663
2739
cxt .lax = (path -> header & JSONPATH_LAX ) != 0 ;
2664
2740
cxt .root = JsonbInitBinary (& jbv , json );
2741
+ cxt .stack = NULL ;
2665
2742
cxt .innermostArraySize = -1 ;
2666
2743
2744
+ pushJsonItem (& cxt .stack , & root , cxt .root );
2745
+
2667
2746
return recursiveExecute (& cxt , & jsp , & jbv , foundJson );
2668
2747
}
2669
2748
0 commit comments