2727/* Special pseudo-ErrorData with zero sqlerrcode for existence queries. */
2828ErrorData jperNotFound [1 ];
2929
30+ typedef struct JsonBaseObjectInfo
31+ {
32+ JsonbContainer * jbc ;
33+ int id ;
34+ } JsonBaseObjectInfo ;
3035
3136typedef struct JsonPathExecContext
3237{
3338 List * vars ;
3439 JsonbValue * root ; /* for $ evaluation */
40+ JsonBaseObjectInfo baseObject ; /* for .keyvalue().id evaluation */
41+ int generatedObjectId ;
3542 int innermostArraySize ; /* for LAST array index evaluation */
3643 bool laxMode ;
3744 bool ignoreStructuralErrors ;
@@ -155,7 +162,7 @@ JsonbWrapInBinary(JsonbValue *jbv, JsonbValue *out)
155162/*
156163 * Find value of jsonpath variable in a list of passing params
157164 */
158- static void
165+ static int
159166computeJsonPathVariable (JsonPathItem * variable , List * vars , JsonbValue * value )
160167{
161168 ListCell * cell ;
@@ -164,6 +171,7 @@ computeJsonPathVariable(JsonPathItem *variable, List *vars, JsonbValue *value)
164171 Datum computedValue ;
165172 char * varName ;
166173 int varNameLength ;
174+ int varId = 1 ;
167175
168176 Assert (variable -> type == jpiVariable );
169177 varName = jspGetString (variable , & varNameLength );
@@ -177,6 +185,7 @@ computeJsonPathVariable(JsonPathItem *variable, List *vars, JsonbValue *value)
177185 break ;
178186
179187 var = NULL ;
188+ varId ++ ;
180189 }
181190
182191 if (var == NULL )
@@ -190,7 +199,7 @@ computeJsonPathVariable(JsonPathItem *variable, List *vars, JsonbValue *value)
190199 if (isNull )
191200 {
192201 value -> type = jbvNull ;
193- return ;
202+ return varId ;
194203 }
195204
196205 switch (var -> typid )
@@ -264,12 +273,14 @@ computeJsonPathVariable(JsonPathItem *variable, List *vars, JsonbValue *value)
264273 (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
265274 errmsg ("only bool, numeric and text types could be casted to supported jsonpath types" )));
266275 }
276+
277+ return varId ;
267278}
268279
269280/*
270281 * Convert jsonpath's scalar or variable node to actual jsonb value
271282 */
272- static void
283+ static int
273284computeJsonPathItem (JsonPathExecContext * cxt , JsonPathItem * item , JsonbValue * value )
274285{
275286 switch (item -> type )
@@ -290,11 +301,12 @@ computeJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item, JsonbValue *va
290301 value -> val .string .val = jspGetString (item , & value -> val .string .len );
291302 break ;
292303 case jpiVariable :
293- computeJsonPathVariable (item , cxt -> vars , value );
294- break ;
304+ return computeJsonPathVariable (item , cxt -> vars , value );
295305 default :
296306 elog (ERROR , "Wrong type" );
297307 }
308+
309+ return 0 ;
298310}
299311
300312
@@ -1397,6 +1409,44 @@ recursiveExecuteBool(JsonPathExecContext *cxt, JsonPathItem *jsp,
13971409 }
13981410}
13991411
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+
14001450/*
14011451 * Main executor function: walks on jsonpath structure and tries to find
14021452 * correspoding parts of jsonb. Note, jsonb and jsonpath values should be
@@ -1414,6 +1464,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
14141464 JsonPathItem elem ;
14151465 JsonPathExecResult res = jperNotFound ;
14161466 bool hasNext ;
1467+ JsonBaseObjectInfo baseObject ;
14171468
14181469 check_stack_depth ();
14191470 CHECK_FOR_INTERRUPTS ();
@@ -1474,33 +1525,18 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
14741525 res = jperMakeError (ERRCODE_JSON_MEMBER_NOT_FOUND );
14751526 }
14761527 break ;
1528+
14771529 case jpiRoot :
14781530 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 ;
14951535
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 ;
15001539
1501- res = recursiveExecuteNext (cxt , jsp , NULL , v , found , copy );
1502- break ;
1503- }
15041540 case jpiAnyArray :
15051541 if (JsonbType (jb ) == jbvArray )
15061542 {
@@ -1762,6 +1798,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
17621798 JsonbValue vbuf ;
17631799 JsonbValue * v ;
17641800 bool hasNext = jspGetNext (jsp , & elem );
1801+ int id ;
17651802
17661803 if (!hasNext && !found )
17671804 {
@@ -1771,9 +1808,11 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
17711808
17721809 v = hasNext ? & vbuf : palloc (sizeof (* v ));
17731810
1774- computeJsonPathItem (cxt , jsp , v );
1811+ id = computeJsonPathItem (cxt , jsp , v );
17751812
1813+ baseObject = setBaseObject (cxt , v , id );
17761814 res = recursiveExecuteNext (cxt , jsp , & elem , v , found , hasNext );
1815+ cxt -> baseObject = baseObject ;
17771816 }
17781817 break ;
17791818 case jpiType :
@@ -2026,11 +2065,14 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
20262065 JsonbValue bin ;
20272066 JsonbValue key ;
20282067 JsonbValue val ;
2068+ JsonbValue idval ;
20292069 JsonbValue obj ;
20302070 JsonbValue keystr ;
20312071 JsonbValue valstr ;
2072+ JsonbValue idstr ;
20322073 JsonbIterator * it ;
20332074 JsonbParseState * ps = NULL ;
2075+ int64 id ;
20342076
20352077 hasNext = jspGetNext (jsp , & elem );
20362078
@@ -2053,9 +2095,21 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
20532095 valstr .val .string .val = "value" ;
20542096 valstr .val .string .len = 5 ;
20552097
2098+ idstr .type = jbvString ;
2099+ idstr .val .string .val = "id" ;
2100+ idstr .val .string .len = 2 ;
2101+
20562102 if (jb -> type == jbvObject )
20572103 jb = JsonbWrapInBinary (jb , & bin );
20582104
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+
20592113 it = JsonbIteratorInit (jb -> val .binary .data );
20602114
20612115 while ((r = JsonbIteratorNext (& it , & key , true)) != WJB_DONE )
@@ -2078,18 +2132,25 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
20782132 pushJsonbValue (& ps , WJB_KEY , & keystr );
20792133 pushJsonbValue (& ps , WJB_VALUE , & key );
20802134
2081-
20822135 pushJsonbValue (& ps , WJB_KEY , & valstr );
20832136 pushJsonbValue (& ps , WJB_VALUE , & val );
20842137
2138+ pushJsonbValue (& ps , WJB_KEY , & idstr );
2139+ pushJsonbValue (& ps , WJB_VALUE , & idval );
2140+
20852141 keyval = pushJsonbValue (& ps , WJB_END_OBJECT , NULL );
20862142
20872143 jsonb = JsonbValueToJsonb (keyval );
20882144
20892145 JsonbInitBinary (& obj , jsonb );
20902146
2147+ baseObject = setBaseObject (cxt , & obj ,
2148+ cxt -> generatedObjectId ++ );
2149+
20912150 res = recursiveExecuteNext (cxt , jsp , & elem , & obj , found , true);
20922151
2152+ cxt -> baseObject = baseObject ;
2153+
20932154 if (jperIsError (res ))
20942155 break ;
20952156
@@ -2254,6 +2315,9 @@ executeJsonPath(JsonPath *path, List *vars, Jsonb *json, JsonValueList *foundJso
22542315 cxt .laxMode = (path -> header & JSONPATH_LAX ) != 0 ;
22552316 cxt .ignoreStructuralErrors = cxt .laxMode ;
22562317 cxt .root = JsonbInitBinary (& jbv , json );
2318+ cxt .baseObject .jbc = NULL ;
2319+ cxt .baseObject .id = 0 ;
2320+ cxt .generatedObjectId = list_length (vars ) + 1 ;
22572321 cxt .innermostArraySize = -1 ;
22582322
22592323 if (jspStrictAbsenseOfErrors (& cxt ) && !foundJson )
0 commit comments