Skip to content

Commit c35370f

Browse files
author
Nikita Glukhov
committed
Refactor jsonpath variables execution
1 parent 99c01d3 commit c35370f

File tree

1 file changed

+69
-40
lines changed

1 file changed

+69
-40
lines changed

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 69 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,16 @@ typedef struct JsonBaseObjectInfo
8686
int id;
8787
} JsonBaseObjectInfo;
8888

89+
typedef int (*JsonPathVarCallback) (void *vars, char *varName, int varNameLen,
90+
JsonbValue *val, JsonbValue *baseObject);
91+
8992
/*
9093
* Context of jsonpath execution.
9194
*/
9295
typedef struct JsonPathExecContext
9396
{
94-
Jsonb *vars; /* variables to substitute into jsonpath */
97+
void *vars; /* variables to substitute into jsonpath */
98+
JsonPathVarCallback getVar;
9599
JsonbValue *root; /* for $ evaluation */
96100
JsonbValue *current; /* for @ evaluation */
97101
JsonBaseObjectInfo baseObject; /* "base object" for .keyvalue()
@@ -173,7 +177,8 @@ typedef JsonPathBool (*JsonPathPredicateCallback) (JsonPathItem *jsp,
173177
void *param);
174178
typedef Numeric (*BinaryArithmFunc) (Numeric num1, Numeric num2, bool *error);
175179

176-
static JsonPathExecResult executeJsonPath(JsonPath *path, Jsonb *vars,
180+
static JsonPathExecResult executeJsonPath(JsonPath *path, void *vars,
181+
JsonPathVarCallback getVar,
177182
Jsonb *json, bool throwErrors,
178183
JsonValueList *result, bool useTz);
179184
static JsonPathExecResult executeItem(JsonPathExecContext *cxt,
@@ -225,7 +230,10 @@ static JsonPathExecResult appendBoolResult(JsonPathExecContext *cxt,
225230
static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
226231
JsonbValue *value);
227232
static void getJsonPathVariable(JsonPathExecContext *cxt,
228-
JsonPathItem *variable, Jsonb *vars, JsonbValue *value);
233+
JsonPathItem *variable, JsonbValue *value);
234+
static int getJsonPathVariableFromJsonb(void *varsJsonb, char *varName,
235+
int varNameLen, JsonbValue *val,
236+
JsonbValue *baseObject);
229237
static int JsonbArraySize(JsonbValue *jb);
230238
static JsonPathBool executeComparison(JsonPathItem *cmp, JsonbValue *lv,
231239
JsonbValue *rv, void *p);
@@ -283,7 +291,8 @@ jsonb_path_exists_internal(FunctionCallInfo fcinfo, bool tz)
283291
silent = PG_GETARG_BOOL(3);
284292
}
285293

286-
res = executeJsonPath(jp, vars, jb, !silent, NULL, tz);
294+
res = executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
295+
jb, !silent, NULL, tz);
287296

288297
PG_FREE_IF_COPY(jb, 0);
289298
PG_FREE_IF_COPY(jp, 1);
@@ -338,7 +347,8 @@ jsonb_path_match_internal(FunctionCallInfo fcinfo, bool tz)
338347
silent = PG_GETARG_BOOL(3);
339348
}
340349

341-
(void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
350+
(void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
351+
jb, !silent, &found, tz);
342352

343353
PG_FREE_IF_COPY(jb, 0);
344354
PG_FREE_IF_COPY(jp, 1);
@@ -416,7 +426,8 @@ jsonb_path_query_internal(FunctionCallInfo fcinfo, bool tz)
416426
vars = PG_GETARG_JSONB_P_COPY(2);
417427
silent = PG_GETARG_BOOL(3);
418428

419-
(void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
429+
(void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
430+
jb, !silent, &found, tz);
420431

421432
funcctx->user_fctx = JsonValueListGetList(&found);
422433

@@ -463,7 +474,8 @@ jsonb_path_query_array_internal(FunctionCallInfo fcinfo, bool tz)
463474
Jsonb *vars = PG_GETARG_JSONB_P(2);
464475
bool silent = PG_GETARG_BOOL(3);
465476

466-
(void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
477+
(void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
478+
jb, !silent, &found, tz);
467479

468480
PG_RETURN_JSONB_P(JsonbValueToJsonb(wrapItemsInArray(&found)));
469481
}
@@ -494,7 +506,8 @@ jsonb_path_query_first_internal(FunctionCallInfo fcinfo, bool tz)
494506
Jsonb *vars = PG_GETARG_JSONB_P(2);
495507
bool silent = PG_GETARG_BOOL(3);
496508

497-
(void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
509+
(void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
510+
jb, !silent, &found, tz);
498511

499512
if (JsonValueListLength(&found) >= 1)
500513
PG_RETURN_JSONB_P(JsonbValueToJsonb(JsonValueListHead(&found)));
@@ -536,8 +549,9 @@ jsonb_path_query_first_tz(PG_FUNCTION_ARGS)
536549
* In other case it tries to find all the satisfied result items.
537550
*/
538551
static JsonPathExecResult
539-
executeJsonPath(JsonPath *path, Jsonb *vars, Jsonb *json, bool throwErrors,
540-
JsonValueList *result, bool useTz)
552+
executeJsonPath(JsonPath *path, void *vars, JsonPathVarCallback getVar,
553+
Jsonb *json, bool throwErrors, JsonValueList *result,
554+
bool useTz)
541555
{
542556
JsonPathExecContext cxt;
543557
JsonPathExecResult res;
@@ -549,22 +563,16 @@ executeJsonPath(JsonPath *path, Jsonb *vars, Jsonb *json, bool throwErrors,
549563
if (!JsonbExtractScalar(&json->root, &jbv))
550564
JsonbInitBinary(&jbv, json);
551565

552-
if (vars && !JsonContainerIsObject(&vars->root))
553-
{
554-
ereport(ERROR,
555-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
556-
errmsg("\"vars\" argument is not an object"),
557-
errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object.")));
558-
}
559-
560566
cxt.vars = vars;
567+
cxt.getVar = getVar;
561568
cxt.laxMode = (path->header & JSONPATH_LAX) != 0;
562569
cxt.ignoreStructuralErrors = cxt.laxMode;
563570
cxt.root = &jbv;
564571
cxt.current = &jbv;
565572
cxt.baseObject.jbc = NULL;
566573
cxt.baseObject.id = 0;
567-
cxt.lastGeneratedObjectId = vars ? 2 : 1;
574+
/* 1 + number of base objects in vars */
575+
cxt.lastGeneratedObjectId = 1 + getVar(vars, NULL, 0, NULL, NULL);
568576
cxt.innermostArraySize = -1;
569577
cxt.throwErrors = throwErrors;
570578
cxt.useTz = useTz;
@@ -2092,7 +2100,7 @@ getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
20922100
&value->val.string.len);
20932101
break;
20942102
case jpiVariable:
2095-
getJsonPathVariable(cxt, item, cxt->vars, value);
2103+
getJsonPathVariable(cxt, item, value);
20962104
return;
20972105
default:
20982106
elog(ERROR, "unexpected jsonpath item type");
@@ -2104,42 +2112,63 @@ getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
21042112
*/
21052113
static void
21062114
getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable,
2107-
Jsonb *vars, JsonbValue *value)
2115+
JsonbValue *value)
21082116
{
21092117
char *varName;
21102118
int varNameLength;
2119+
JsonbValue baseObject;
2120+
int baseObjectId;
2121+
2122+
Assert(variable->type == jpiVariable);
2123+
varName = jspGetString(variable, &varNameLength);
2124+
2125+
if (!cxt->vars ||
2126+
(baseObjectId = cxt->getVar(cxt->vars, varName, varNameLength, value,
2127+
&baseObject)) < 0)
2128+
ereport(ERROR,
2129+
(errcode(ERRCODE_UNDEFINED_OBJECT),
2130+
errmsg("could not find jsonpath variable \"%s\"",
2131+
pnstrdup(varName, varNameLength))));
2132+
2133+
if (baseObjectId > 0)
2134+
setBaseObject(cxt, &baseObject, baseObjectId);
2135+
}
2136+
2137+
static int
2138+
getJsonPathVariableFromJsonb(void *varsJsonb, char *varName, int varNameLength,
2139+
JsonbValue *value, JsonbValue *baseObject)
2140+
{
2141+
Jsonb *vars = varsJsonb;
21112142
JsonbValue tmp;
21122143
JsonbValue *v;
21132144

2114-
if (!vars)
2145+
if (!varName)
21152146
{
2116-
value->type = jbvNull;
2117-
return;
2147+
if (vars && !JsonContainerIsObject(&vars->root))
2148+
{
2149+
ereport(ERROR,
2150+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2151+
errmsg("\"vars\" argument is not an object"),
2152+
errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object.")));
2153+
}
2154+
2155+
return vars ? 1 : 0; /* count of base objects */
21182156
}
21192157

2120-
Assert(variable->type == jpiVariable);
2121-
varName = jspGetString(variable, &varNameLength);
21222158
tmp.type = jbvString;
21232159
tmp.val.string.val = varName;
21242160
tmp.val.string.len = varNameLength;
21252161

21262162
v = findJsonbValueFromContainer(&vars->root, JB_FOBJECT, &tmp);
21272163

2128-
if (v)
2129-
{
2130-
*value = *v;
2131-
pfree(v);
2132-
}
2133-
else
2134-
{
2135-
ereport(ERROR,
2136-
(errcode(ERRCODE_UNDEFINED_OBJECT),
2137-
errmsg("could not find jsonpath variable \"%s\"",
2138-
pnstrdup(varName, varNameLength))));
2139-
}
2164+
if (!v)
2165+
return -1;
2166+
2167+
*value = *v;
2168+
pfree(v);
21402169

2141-
JsonbInitBinary(&tmp, vars);
2142-
setBaseObject(cxt, &tmp, 1);
2170+
JsonbInitBinary(baseObject, vars);
2171+
return 1;
21432172
}
21442173

21452174
/**************** Support functions for JsonPath execution *****************/

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy