27
27
/* Special pseudo-ErrorData with zero sqlerrcode for existence queries. */
28
28
ErrorData jperNotFound [1 ];
29
29
30
+ typedef struct JsonBaseObjectInfo
31
+ {
32
+ JsonbContainer * jbc ;
33
+ int id ;
34
+ } JsonBaseObjectInfo ;
30
35
31
36
typedef struct JsonPathExecContext
32
37
{
33
38
List * vars ;
34
39
JsonbValue * root ; /* for $ evaluation */
40
+ JsonBaseObjectInfo baseObject ; /* for .keyvalue().id evaluation */
41
+ int generatedObjectId ;
35
42
int innermostArraySize ; /* for LAST array index evaluation */
36
43
bool laxMode ;
37
44
bool ignoreStructuralErrors ;
@@ -155,7 +162,7 @@ JsonbWrapInBinary(JsonbValue *jbv, JsonbValue *out)
155
162
/*
156
163
* Find value of jsonpath variable in a list of passing params
157
164
*/
158
- static void
165
+ static int
159
166
computeJsonPathVariable (JsonPathItem * variable , List * vars , JsonbValue * value )
160
167
{
161
168
ListCell * cell ;
@@ -164,6 +171,7 @@ computeJsonPathVariable(JsonPathItem *variable, List *vars, JsonbValue *value)
164
171
Datum computedValue ;
165
172
char * varName ;
166
173
int varNameLength ;
174
+ int varId = 1 ;
167
175
168
176
Assert (variable -> type == jpiVariable );
169
177
varName = jspGetString (variable , & varNameLength );
@@ -177,6 +185,7 @@ computeJsonPathVariable(JsonPathItem *variable, List *vars, JsonbValue *value)
177
185
break ;
178
186
179
187
var = NULL ;
188
+ varId ++ ;
180
189
}
181
190
182
191
if (var == NULL )
@@ -190,7 +199,7 @@ computeJsonPathVariable(JsonPathItem *variable, List *vars, JsonbValue *value)
190
199
if (isNull )
191
200
{
192
201
value -> type = jbvNull ;
193
- return ;
202
+ return varId ;
194
203
}
195
204
196
205
switch (var -> typid )
@@ -264,12 +273,14 @@ computeJsonPathVariable(JsonPathItem *variable, List *vars, JsonbValue *value)
264
273
(errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
265
274
errmsg ("only bool, numeric and text types could be casted to supported jsonpath types" )));
266
275
}
276
+
277
+ return varId ;
267
278
}
268
279
269
280
/*
270
281
* Convert jsonpath's scalar or variable node to actual jsonb value
271
282
*/
272
- static void
283
+ static int
273
284
computeJsonPathItem (JsonPathExecContext * cxt , JsonPathItem * item , JsonbValue * value )
274
285
{
275
286
switch (item -> type )
@@ -290,11 +301,12 @@ computeJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item, JsonbValue *va
290
301
value -> val .string .val = jspGetString (item , & value -> val .string .len );
291
302
break ;
292
303
case jpiVariable :
293
- computeJsonPathVariable (item , cxt -> vars , value );
294
- break ;
304
+ return computeJsonPathVariable (item , cxt -> vars , value );
295
305
default :
296
306
elog (ERROR , "Wrong type" );
297
307
}
308
+
309
+ return 0 ;
298
310
}
299
311
300
312
@@ -1397,6 +1409,44 @@ recursiveExecuteBool(JsonPathExecContext *cxt, JsonPathItem *jsp,
1397
1409
}
1398
1410
}
1399
1411
1412
+ static inline JsonPathExecResult
1413
+ recursiveExecuteBase (JsonPathExecContext * cxt , JsonPathItem * jsp ,
1414
+ JsonbValue * jbv , JsonValueList * found )
1415
+ {
1416
+ JsonbValue * v ;
1417
+ JsonbValue vbuf ;
1418
+ bool copy = true;
1419
+
1420
+ if (JsonbType (jbv ) == jbvScalar )
1421
+ {
1422
+ if (jspHasNext (jsp ))
1423
+ v = & vbuf ;
1424
+ else
1425
+ {
1426
+ v = palloc (sizeof (* v ));
1427
+ copy = false;
1428
+ }
1429
+
1430
+ JsonbExtractScalar (jbv -> val .binary .data , v );
1431
+ }
1432
+ else
1433
+ v = jbv ;
1434
+
1435
+ return recursiveExecuteNext (cxt , jsp , NULL , v , found , copy );
1436
+ }
1437
+
1438
+ static inline JsonBaseObjectInfo
1439
+ setBaseObject (JsonPathExecContext * cxt , JsonbValue * jbv , int32 id )
1440
+ {
1441
+ JsonBaseObjectInfo baseObject = cxt -> baseObject ;
1442
+
1443
+ cxt -> baseObject .jbc = jbv -> type != jbvBinary ? NULL :
1444
+ (JsonbContainer * ) jbv -> val .binary .data ;
1445
+ cxt -> baseObject .id = id ;
1446
+
1447
+ return baseObject ;
1448
+ }
1449
+
1400
1450
/*
1401
1451
* Main executor function: walks on jsonpath structure and tries to find
1402
1452
* correspoding parts of jsonb. Note, jsonb and jsonpath values should be
@@ -1414,6 +1464,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1414
1464
JsonPathItem elem ;
1415
1465
JsonPathExecResult res = jperNotFound ;
1416
1466
bool hasNext ;
1467
+ JsonBaseObjectInfo baseObject ;
1417
1468
1418
1469
check_stack_depth ();
1419
1470
CHECK_FOR_INTERRUPTS ();
@@ -1474,33 +1525,18 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1474
1525
res = jperMakeError (ERRCODE_JSON_MEMBER_NOT_FOUND );
1475
1526
}
1476
1527
break ;
1528
+
1477
1529
case jpiRoot :
1478
1530
jb = cxt -> root ;
1479
- /* fall through */
1480
- case jpiCurrent :
1481
- {
1482
- JsonbValue * v ;
1483
- JsonbValue vbuf ;
1484
- bool copy = true;
1485
-
1486
- if (JsonbType (jb ) == jbvScalar )
1487
- {
1488
- if (jspHasNext (jsp ))
1489
- v = & vbuf ;
1490
- else
1491
- {
1492
- v = palloc (sizeof (* v ));
1493
- copy = false;
1494
- }
1531
+ baseObject = setBaseObject (cxt , jb , 0 );
1532
+ res = recursiveExecuteBase (cxt , jsp , jb , found );
1533
+ cxt -> baseObject = baseObject ;
1534
+ break ;
1495
1535
1496
- JsonbExtractScalar (jb -> val .binary .data , v );
1497
- }
1498
- else
1499
- v = jb ;
1536
+ case jpiCurrent :
1537
+ res = recursiveExecuteBase (cxt , jsp , jb , found );
1538
+ break ;
1500
1539
1501
- res = recursiveExecuteNext (cxt , jsp , NULL , v , found , copy );
1502
- break ;
1503
- }
1504
1540
case jpiAnyArray :
1505
1541
if (JsonbType (jb ) == jbvArray )
1506
1542
{
@@ -1762,6 +1798,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1762
1798
JsonbValue vbuf ;
1763
1799
JsonbValue * v ;
1764
1800
bool hasNext = jspGetNext (jsp , & elem );
1801
+ int id ;
1765
1802
1766
1803
if (!hasNext && !found )
1767
1804
{
@@ -1771,9 +1808,11 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
1771
1808
1772
1809
v = hasNext ? & vbuf : palloc (sizeof (* v ));
1773
1810
1774
- computeJsonPathItem (cxt , jsp , v );
1811
+ id = computeJsonPathItem (cxt , jsp , v );
1775
1812
1813
+ baseObject = setBaseObject (cxt , v , id );
1776
1814
res = recursiveExecuteNext (cxt , jsp , & elem , v , found , hasNext );
1815
+ cxt -> baseObject = baseObject ;
1777
1816
}
1778
1817
break ;
1779
1818
case jpiType :
@@ -2026,11 +2065,14 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2026
2065
JsonbValue bin ;
2027
2066
JsonbValue key ;
2028
2067
JsonbValue val ;
2068
+ JsonbValue idval ;
2029
2069
JsonbValue obj ;
2030
2070
JsonbValue keystr ;
2031
2071
JsonbValue valstr ;
2072
+ JsonbValue idstr ;
2032
2073
JsonbIterator * it ;
2033
2074
JsonbParseState * ps = NULL ;
2075
+ int64 id ;
2034
2076
2035
2077
hasNext = jspGetNext (jsp , & elem );
2036
2078
@@ -2053,9 +2095,21 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2053
2095
valstr .val .string .val = "value" ;
2054
2096
valstr .val .string .len = 5 ;
2055
2097
2098
+ idstr .type = jbvString ;
2099
+ idstr .val .string .val = "id" ;
2100
+ idstr .val .string .len = 2 ;
2101
+
2056
2102
if (jb -> type == jbvObject )
2057
2103
jb = JsonbWrapInBinary (jb , & bin );
2058
2104
2105
+ id = jb -> type != jbvBinary ? 0 :
2106
+ (int64 )((char * ) jb -> val .binary .data -
2107
+ (char * ) cxt -> baseObject .jbc );
2108
+ id += (int64 ) cxt -> baseObject .id * INT64CONST (10000000000 );
2109
+
2110
+ idval .type = jbvNumeric ;
2111
+ idval .val .numeric = DatumGetNumeric (DirectFunctionCall1 (int8_numeric , Int64GetDatum (id )));
2112
+
2059
2113
it = JsonbIteratorInit (jb -> val .binary .data );
2060
2114
2061
2115
while ((r = JsonbIteratorNext (& it , & key , true)) != WJB_DONE )
@@ -2078,18 +2132,25 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
2078
2132
pushJsonbValue (& ps , WJB_KEY , & keystr );
2079
2133
pushJsonbValue (& ps , WJB_VALUE , & key );
2080
2134
2081
-
2082
2135
pushJsonbValue (& ps , WJB_KEY , & valstr );
2083
2136
pushJsonbValue (& ps , WJB_VALUE , & val );
2084
2137
2138
+ pushJsonbValue (& ps , WJB_KEY , & idstr );
2139
+ pushJsonbValue (& ps , WJB_VALUE , & idval );
2140
+
2085
2141
keyval = pushJsonbValue (& ps , WJB_END_OBJECT , NULL );
2086
2142
2087
2143
jsonb = JsonbValueToJsonb (keyval );
2088
2144
2089
2145
JsonbInitBinary (& obj , jsonb );
2090
2146
2147
+ baseObject = setBaseObject (cxt , & obj ,
2148
+ cxt -> generatedObjectId ++ );
2149
+
2091
2150
res = recursiveExecuteNext (cxt , jsp , & elem , & obj , found , true);
2092
2151
2152
+ cxt -> baseObject = baseObject ;
2153
+
2093
2154
if (jperIsError (res ))
2094
2155
break ;
2095
2156
@@ -2254,6 +2315,9 @@ executeJsonPath(JsonPath *path, List *vars, Jsonb *json, JsonValueList *foundJso
2254
2315
cxt .laxMode = (path -> header & JSONPATH_LAX ) != 0 ;
2255
2316
cxt .ignoreStructuralErrors = cxt .laxMode ;
2256
2317
cxt .root = JsonbInitBinary (& jbv , json );
2318
+ cxt .baseObject .jbc = NULL ;
2319
+ cxt .baseObject .id = 0 ;
2320
+ cxt .generatedObjectId = list_length (vars ) + 1 ;
2257
2321
cxt .innermostArraySize = -1 ;
2258
2322
2259
2323
if (jspStrictAbsenseOfErrors (& cxt ) && !foundJson )
0 commit comments