@@ -87,12 +87,19 @@ typedef struct JsonBaseObjectInfo
8787 int id ;
8888} JsonBaseObjectInfo ;
8989
90+ /* Callbacks for executeJsonPath() */
91+ typedef JsonbValue * (* JsonPathGetVarCallback ) (void * vars , char * varName , int varNameLen ,
92+ JsonbValue * baseObject , int * baseObjectId );
93+ typedef int (* JsonPathCountVarsCallback ) (void * vars );
94+
9095/*
9196 * Context of jsonpath execution.
9297 */
9398typedef struct JsonPathExecContext
9499{
95- Jsonb * vars ; /* variables to substitute into jsonpath */
100+ void * vars ; /* variables to substitute into jsonpath */
101+ JsonPathGetVarCallback getVar ; /* callback to extract a given variable
102+ * from 'vars' */
96103 JsonbValue * root ; /* for $ evaluation */
97104 JsonbValue * current ; /* for @ evaluation */
98105 JsonBaseObjectInfo baseObject ; /* "base object" for .keyvalue()
@@ -174,7 +181,9 @@ typedef JsonPathBool (*JsonPathPredicateCallback) (JsonPathItem *jsp,
174181 void * param );
175182typedef Numeric (* BinaryArithmFunc ) (Numeric num1 , Numeric num2 , bool * error );
176183
177- static JsonPathExecResult executeJsonPath (JsonPath * path , Jsonb * vars ,
184+ static JsonPathExecResult executeJsonPath (JsonPath * path , void * vars ,
185+ JsonPathGetVarCallback getVar ,
186+ JsonPathCountVarsCallback countVars ,
178187 Jsonb * json , bool throwErrors ,
179188 JsonValueList * result , bool useTz );
180189static JsonPathExecResult executeItem (JsonPathExecContext * cxt ,
@@ -226,7 +235,12 @@ static JsonPathExecResult appendBoolResult(JsonPathExecContext *cxt,
226235static void getJsonPathItem (JsonPathExecContext * cxt , JsonPathItem * item ,
227236 JsonbValue * value );
228237static void getJsonPathVariable (JsonPathExecContext * cxt ,
229- JsonPathItem * variable , Jsonb * vars , JsonbValue * value );
238+ JsonPathItem * variable , JsonbValue * value );
239+ static int countVariablesFromJsonb (void * varsJsonb );
240+ static JsonbValue * getJsonPathVariableFromJsonb (void * varsJsonb , char * varName ,
241+ int varNameLen ,
242+ JsonbValue * baseObject ,
243+ int * baseObjectId );
230244static int JsonbArraySize (JsonbValue * jb );
231245static JsonPathBool executeComparison (JsonPathItem * cmp , JsonbValue * lv ,
232246 JsonbValue * rv , void * p );
@@ -284,7 +298,9 @@ jsonb_path_exists_internal(FunctionCallInfo fcinfo, bool tz)
284298 silent = PG_GETARG_BOOL (3 );
285299 }
286300
287- res = executeJsonPath (jp , vars , jb , !silent , NULL , tz );
301+ res = executeJsonPath (jp , vars , getJsonPathVariableFromJsonb ,
302+ countVariablesFromJsonb ,
303+ jb , !silent , NULL , tz );
288304
289305 PG_FREE_IF_COPY (jb , 0 );
290306 PG_FREE_IF_COPY (jp , 1 );
@@ -339,7 +355,9 @@ jsonb_path_match_internal(FunctionCallInfo fcinfo, bool tz)
339355 silent = PG_GETARG_BOOL (3 );
340356 }
341357
342- (void ) executeJsonPath (jp , vars , jb , !silent , & found , tz );
358+ (void ) executeJsonPath (jp , vars , getJsonPathVariableFromJsonb ,
359+ countVariablesFromJsonb ,
360+ jb , !silent , & found , tz );
343361
344362 PG_FREE_IF_COPY (jb , 0 );
345363 PG_FREE_IF_COPY (jp , 1 );
@@ -417,7 +435,9 @@ jsonb_path_query_internal(FunctionCallInfo fcinfo, bool tz)
417435 vars = PG_GETARG_JSONB_P_COPY (2 );
418436 silent = PG_GETARG_BOOL (3 );
419437
420- (void ) executeJsonPath (jp , vars , jb , !silent , & found , tz );
438+ (void ) executeJsonPath (jp , vars , getJsonPathVariableFromJsonb ,
439+ countVariablesFromJsonb ,
440+ jb , !silent , & found , tz );
421441
422442 funcctx -> user_fctx = JsonValueListGetList (& found );
423443
@@ -464,7 +484,9 @@ jsonb_path_query_array_internal(FunctionCallInfo fcinfo, bool tz)
464484 Jsonb * vars = PG_GETARG_JSONB_P (2 );
465485 bool silent = PG_GETARG_BOOL (3 );
466486
467- (void ) executeJsonPath (jp , vars , jb , !silent , & found , tz );
487+ (void ) executeJsonPath (jp , vars , getJsonPathVariableFromJsonb ,
488+ countVariablesFromJsonb ,
489+ jb , !silent , & found , tz );
468490
469491 PG_RETURN_JSONB_P (JsonbValueToJsonb (wrapItemsInArray (& found )));
470492}
@@ -495,7 +517,9 @@ jsonb_path_query_first_internal(FunctionCallInfo fcinfo, bool tz)
495517 Jsonb * vars = PG_GETARG_JSONB_P (2 );
496518 bool silent = PG_GETARG_BOOL (3 );
497519
498- (void ) executeJsonPath (jp , vars , jb , !silent , & found , tz );
520+ (void ) executeJsonPath (jp , vars , getJsonPathVariableFromJsonb ,
521+ countVariablesFromJsonb ,
522+ jb , !silent , & found , tz );
499523
500524 if (JsonValueListLength (& found ) >= 1 )
501525 PG_RETURN_JSONB_P (JsonbValueToJsonb (JsonValueListHead (& found )));
@@ -522,6 +546,9 @@ jsonb_path_query_first_tz(PG_FUNCTION_ARGS)
522546 *
523547 * 'path' - jsonpath to be executed
524548 * 'vars' - variables to be substituted to jsonpath
549+ * 'getVar' - callback used by getJsonPathVariable() to extract variables from
550+ * 'vars'
551+ * 'countVars' - callback to count the number of jsonpath variables in 'vars'
525552 * 'json' - target document for jsonpath evaluation
526553 * 'throwErrors' - whether we should throw suppressible errors
527554 * 'result' - list to store result items into
@@ -537,8 +564,10 @@ jsonb_path_query_first_tz(PG_FUNCTION_ARGS)
537564 * In other case it tries to find all the satisfied result items.
538565 */
539566static JsonPathExecResult
540- executeJsonPath (JsonPath * path , Jsonb * vars , Jsonb * json , bool throwErrors ,
541- JsonValueList * result , bool useTz )
567+ executeJsonPath (JsonPath * path , void * vars , JsonPathGetVarCallback getVar ,
568+ JsonPathCountVarsCallback countVars ,
569+ Jsonb * json , bool throwErrors , JsonValueList * result ,
570+ bool useTz )
542571{
543572 JsonPathExecContext cxt ;
544573 JsonPathExecResult res ;
@@ -550,22 +579,16 @@ executeJsonPath(JsonPath *path, Jsonb *vars, Jsonb *json, bool throwErrors,
550579 if (!JsonbExtractScalar (& json -> root , & jbv ))
551580 JsonbInitBinary (& jbv , json );
552581
553- if (vars && !JsonContainerIsObject (& vars -> root ))
554- {
555- ereport (ERROR ,
556- (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
557- errmsg ("\"vars\" argument is not an object" ),
558- errdetail ("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object." )));
559- }
560-
561582 cxt .vars = vars ;
583+ cxt .getVar = getVar ;
562584 cxt .laxMode = (path -> header & JSONPATH_LAX ) != 0 ;
563585 cxt .ignoreStructuralErrors = cxt .laxMode ;
564586 cxt .root = & jbv ;
565587 cxt .current = & jbv ;
566588 cxt .baseObject .jbc = NULL ;
567589 cxt .baseObject .id = 0 ;
568- cxt .lastGeneratedObjectId = vars ? 2 : 1 ;
590+ /* 1 + number of base objects in vars */
591+ cxt .lastGeneratedObjectId = 1 + countVars (vars );
569592 cxt .innermostArraySize = -1 ;
570593 cxt .throwErrors = throwErrors ;
571594 cxt .useTz = useTz ;
@@ -2108,7 +2131,7 @@ getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
21082131 & value -> val .string .len );
21092132 break ;
21102133 case jpiVariable :
2111- getJsonPathVariable (cxt , item , cxt -> vars , value );
2134+ getJsonPathVariable (cxt , item , value );
21122135 return ;
21132136 default :
21142137 elog (ERROR , "unexpected jsonpath item type" );
@@ -2120,42 +2143,81 @@ getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
21202143 */
21212144static void
21222145getJsonPathVariable (JsonPathExecContext * cxt , JsonPathItem * variable ,
2123- Jsonb * vars , JsonbValue * value )
2146+ JsonbValue * value )
21242147{
21252148 char * varName ;
21262149 int varNameLength ;
2127- JsonbValue tmp ;
2150+ JsonbValue baseObject ;
2151+ int baseObjectId ;
21282152 JsonbValue * v ;
21292153
2130- if (!vars )
2154+ Assert (variable -> type == jpiVariable );
2155+ varName = jspGetString (variable , & varNameLength );
2156+
2157+ if (cxt -> vars == NULL ||
2158+ (v = cxt -> getVar (cxt -> vars , varName , varNameLength ,
2159+ & baseObject , & baseObjectId )) == NULL )
2160+ ereport (ERROR ,
2161+ (errcode (ERRCODE_UNDEFINED_OBJECT ),
2162+ errmsg ("could not find jsonpath variable \"%s\"" ,
2163+ pnstrdup (varName , varNameLength ))));
2164+
2165+ if (baseObjectId > 0 )
21312166 {
2132- value -> type = jbvNull ;
2133- return ;
2167+ * value = * v ;
2168+ setBaseObject ( cxt , & baseObject , baseObjectId ) ;
21342169 }
2170+ }
2171+
2172+ /*
2173+ * Definition of JsonPathGetVarCallback for when JsonPathExecContext.vars
2174+ * is specified as a jsonb value.
2175+ */
2176+ static JsonbValue *
2177+ getJsonPathVariableFromJsonb (void * varsJsonb , char * varName , int varNameLength ,
2178+ JsonbValue * baseObject , int * baseObjectId )
2179+ {
2180+ Jsonb * vars = varsJsonb ;
2181+ JsonbValue tmp ;
2182+ JsonbValue * result ;
21352183
2136- Assert (variable -> type == jpiVariable );
2137- varName = jspGetString (variable , & varNameLength );
21382184 tmp .type = jbvString ;
21392185 tmp .val .string .val = varName ;
21402186 tmp .val .string .len = varNameLength ;
21412187
2142- v = findJsonbValueFromContainer (& vars -> root , JB_FOBJECT , & tmp );
2188+ result = findJsonbValueFromContainer (& vars -> root , JB_FOBJECT , & tmp );
21432189
2144- if (v )
2190+ if (result == NULL )
21452191 {
2146- * value = * v ;
2147- pfree ( v ) ;
2192+ * baseObjectId = -1 ;
2193+ return NULL ;
21482194 }
2149- else
2195+
2196+ * baseObjectId = 1 ;
2197+ JsonbInitBinary (baseObject , vars );
2198+
2199+ return result ;
2200+ }
2201+
2202+ /*
2203+ * Definition of JsonPathCountVarsCallback for when JsonPathExecContext.vars
2204+ * is specified as a jsonb value.
2205+ */
2206+ static int
2207+ countVariablesFromJsonb (void * varsJsonb )
2208+ {
2209+ Jsonb * vars = varsJsonb ;
2210+
2211+ if (vars && !JsonContainerIsObject (& vars -> root ))
21502212 {
21512213 ereport (ERROR ,
2152- ( errcode (ERRCODE_UNDEFINED_OBJECT ),
2153- errmsg ("could not find jsonpath variable \"%s\"" ,
2154- pnstrdup ( varName , varNameLength )) ));
2214+ errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
2215+ errmsg ("\"vars\" argument is not an object" ) ,
2216+ errdetail ( "Jsonpath parameters should be encoded as key-value pairs of \"vars\" object." ));
21552217 }
21562218
2157- JsonbInitBinary ( & tmp , vars );
2158- setBaseObject ( cxt , & tmp , 1 ) ;
2219+ /* count of base objects */
2220+ return vars != NULL ? 1 : 0 ;
21592221}
21602222
21612223/**************** Support functions for JsonPath execution *****************/
0 commit comments