@@ -87,12 +87,19 @@ typedef struct JsonBaseObjectInfo
87
87
int id ;
88
88
} JsonBaseObjectInfo ;
89
89
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
+
90
95
/*
91
96
* Context of jsonpath execution.
92
97
*/
93
98
typedef struct JsonPathExecContext
94
99
{
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' */
96
103
JsonbValue * root ; /* for $ evaluation */
97
104
JsonbValue * current ; /* for @ evaluation */
98
105
JsonBaseObjectInfo baseObject ; /* "base object" for .keyvalue()
@@ -174,7 +181,9 @@ typedef JsonPathBool (*JsonPathPredicateCallback) (JsonPathItem *jsp,
174
181
void * param );
175
182
typedef Numeric (* BinaryArithmFunc ) (Numeric num1 , Numeric num2 , bool * error );
176
183
177
- static JsonPathExecResult executeJsonPath (JsonPath * path , Jsonb * vars ,
184
+ static JsonPathExecResult executeJsonPath (JsonPath * path , void * vars ,
185
+ JsonPathGetVarCallback getVar ,
186
+ JsonPathCountVarsCallback countVars ,
178
187
Jsonb * json , bool throwErrors ,
179
188
JsonValueList * result , bool useTz );
180
189
static JsonPathExecResult executeItem (JsonPathExecContext * cxt ,
@@ -226,7 +235,12 @@ static JsonPathExecResult appendBoolResult(JsonPathExecContext *cxt,
226
235
static void getJsonPathItem (JsonPathExecContext * cxt , JsonPathItem * item ,
227
236
JsonbValue * value );
228
237
static 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 );
230
244
static int JsonbArraySize (JsonbValue * jb );
231
245
static JsonPathBool executeComparison (JsonPathItem * cmp , JsonbValue * lv ,
232
246
JsonbValue * rv , void * p );
@@ -284,7 +298,9 @@ jsonb_path_exists_internal(FunctionCallInfo fcinfo, bool tz)
284
298
silent = PG_GETARG_BOOL (3 );
285
299
}
286
300
287
- res = executeJsonPath (jp , vars , jb , !silent , NULL , tz );
301
+ res = executeJsonPath (jp , vars , getJsonPathVariableFromJsonb ,
302
+ countVariablesFromJsonb ,
303
+ jb , !silent , NULL , tz );
288
304
289
305
PG_FREE_IF_COPY (jb , 0 );
290
306
PG_FREE_IF_COPY (jp , 1 );
@@ -339,7 +355,9 @@ jsonb_path_match_internal(FunctionCallInfo fcinfo, bool tz)
339
355
silent = PG_GETARG_BOOL (3 );
340
356
}
341
357
342
- (void ) executeJsonPath (jp , vars , jb , !silent , & found , tz );
358
+ (void ) executeJsonPath (jp , vars , getJsonPathVariableFromJsonb ,
359
+ countVariablesFromJsonb ,
360
+ jb , !silent , & found , tz );
343
361
344
362
PG_FREE_IF_COPY (jb , 0 );
345
363
PG_FREE_IF_COPY (jp , 1 );
@@ -417,7 +435,9 @@ jsonb_path_query_internal(FunctionCallInfo fcinfo, bool tz)
417
435
vars = PG_GETARG_JSONB_P_COPY (2 );
418
436
silent = PG_GETARG_BOOL (3 );
419
437
420
- (void ) executeJsonPath (jp , vars , jb , !silent , & found , tz );
438
+ (void ) executeJsonPath (jp , vars , getJsonPathVariableFromJsonb ,
439
+ countVariablesFromJsonb ,
440
+ jb , !silent , & found , tz );
421
441
422
442
funcctx -> user_fctx = JsonValueListGetList (& found );
423
443
@@ -464,7 +484,9 @@ jsonb_path_query_array_internal(FunctionCallInfo fcinfo, bool tz)
464
484
Jsonb * vars = PG_GETARG_JSONB_P (2 );
465
485
bool silent = PG_GETARG_BOOL (3 );
466
486
467
- (void ) executeJsonPath (jp , vars , jb , !silent , & found , tz );
487
+ (void ) executeJsonPath (jp , vars , getJsonPathVariableFromJsonb ,
488
+ countVariablesFromJsonb ,
489
+ jb , !silent , & found , tz );
468
490
469
491
PG_RETURN_JSONB_P (JsonbValueToJsonb (wrapItemsInArray (& found )));
470
492
}
@@ -495,7 +517,9 @@ jsonb_path_query_first_internal(FunctionCallInfo fcinfo, bool tz)
495
517
Jsonb * vars = PG_GETARG_JSONB_P (2 );
496
518
bool silent = PG_GETARG_BOOL (3 );
497
519
498
- (void ) executeJsonPath (jp , vars , jb , !silent , & found , tz );
520
+ (void ) executeJsonPath (jp , vars , getJsonPathVariableFromJsonb ,
521
+ countVariablesFromJsonb ,
522
+ jb , !silent , & found , tz );
499
523
500
524
if (JsonValueListLength (& found ) >= 1 )
501
525
PG_RETURN_JSONB_P (JsonbValueToJsonb (JsonValueListHead (& found )));
@@ -522,6 +546,9 @@ jsonb_path_query_first_tz(PG_FUNCTION_ARGS)
522
546
*
523
547
* 'path' - jsonpath to be executed
524
548
* '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'
525
552
* 'json' - target document for jsonpath evaluation
526
553
* 'throwErrors' - whether we should throw suppressible errors
527
554
* 'result' - list to store result items into
@@ -537,8 +564,10 @@ jsonb_path_query_first_tz(PG_FUNCTION_ARGS)
537
564
* In other case it tries to find all the satisfied result items.
538
565
*/
539
566
static 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 )
542
571
{
543
572
JsonPathExecContext cxt ;
544
573
JsonPathExecResult res ;
@@ -550,22 +579,16 @@ executeJsonPath(JsonPath *path, Jsonb *vars, Jsonb *json, bool throwErrors,
550
579
if (!JsonbExtractScalar (& json -> root , & jbv ))
551
580
JsonbInitBinary (& jbv , json );
552
581
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
-
561
582
cxt .vars = vars ;
583
+ cxt .getVar = getVar ;
562
584
cxt .laxMode = (path -> header & JSONPATH_LAX ) != 0 ;
563
585
cxt .ignoreStructuralErrors = cxt .laxMode ;
564
586
cxt .root = & jbv ;
565
587
cxt .current = & jbv ;
566
588
cxt .baseObject .jbc = NULL ;
567
589
cxt .baseObject .id = 0 ;
568
- cxt .lastGeneratedObjectId = vars ? 2 : 1 ;
590
+ /* 1 + number of base objects in vars */
591
+ cxt .lastGeneratedObjectId = 1 + countVars (vars );
569
592
cxt .innermostArraySize = -1 ;
570
593
cxt .throwErrors = throwErrors ;
571
594
cxt .useTz = useTz ;
@@ -2108,7 +2131,7 @@ getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
2108
2131
& value -> val .string .len );
2109
2132
break ;
2110
2133
case jpiVariable :
2111
- getJsonPathVariable (cxt , item , cxt -> vars , value );
2134
+ getJsonPathVariable (cxt , item , value );
2112
2135
return ;
2113
2136
default :
2114
2137
elog (ERROR , "unexpected jsonpath item type" );
@@ -2120,42 +2143,81 @@ getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
2120
2143
*/
2121
2144
static void
2122
2145
getJsonPathVariable (JsonPathExecContext * cxt , JsonPathItem * variable ,
2123
- Jsonb * vars , JsonbValue * value )
2146
+ JsonbValue * value )
2124
2147
{
2125
2148
char * varName ;
2126
2149
int varNameLength ;
2127
- JsonbValue tmp ;
2150
+ JsonbValue baseObject ;
2151
+ int baseObjectId ;
2128
2152
JsonbValue * v ;
2129
2153
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 )
2131
2166
{
2132
- value -> type = jbvNull ;
2133
- return ;
2167
+ * value = * v ;
2168
+ setBaseObject ( cxt , & baseObject , baseObjectId ) ;
2134
2169
}
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 ;
2135
2183
2136
- Assert (variable -> type == jpiVariable );
2137
- varName = jspGetString (variable , & varNameLength );
2138
2184
tmp .type = jbvString ;
2139
2185
tmp .val .string .val = varName ;
2140
2186
tmp .val .string .len = varNameLength ;
2141
2187
2142
- v = findJsonbValueFromContainer (& vars -> root , JB_FOBJECT , & tmp );
2188
+ result = findJsonbValueFromContainer (& vars -> root , JB_FOBJECT , & tmp );
2143
2189
2144
- if (v )
2190
+ if (result == NULL )
2145
2191
{
2146
- * value = * v ;
2147
- pfree ( v ) ;
2192
+ * baseObjectId = -1 ;
2193
+ return NULL ;
2148
2194
}
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 ))
2150
2212
{
2151
2213
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." ));
2155
2217
}
2156
2218
2157
- JsonbInitBinary ( & tmp , vars );
2158
- setBaseObject ( cxt , & tmp , 1 ) ;
2219
+ /* count of base objects */
2220
+ return vars != NULL ? 1 : 0 ;
2159
2221
}
2160
2222
2161
2223
/**************** Support functions for JsonPath execution *****************/
0 commit comments