v10-0008-Remove-subsidary-ExprStates-in-SQL-JSON-executio.patch
text/x-patch
Filename: v10-0008-Remove-subsidary-ExprStates-in-SQL-JSON-executio.patch
Type: text/x-patch
Part: 7
Message:
Re: SQL/JSON features for v15
Patch
Format: format-patch
Series: patch v10-0008
Subject: Remove subsidary ExprStates in SQL/JSON execution
| File | + | − |
|---|---|---|
| src/backend/executor/execExpr.c | 71 | 17 |
| src/backend/executor/execExprInterp.c | 92 | 113 |
| src/backend/jit/llvm/llvmjit_expr.c | 65 | 5 |
| src/backend/jit/llvm/llvmjit_types.c | 1 | 0 |
| src/backend/utils/adt/jsonpath_exec.c | 73 | 6 |
| src/include/executor/execExpr.h | 14 | 6 |
| src/include/utils/jsonpath.h | 0 | 4 |
From 7a352784fa98d694d5d5d41cf27c18ca2504cf0d Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Mon, 29 Aug 2022 22:41:08 +0300
Subject: [PATCH v10 08/10] Remove subsidary ExprStates in SQL/JSON execution
---
src/backend/executor/execExpr.c | 88 ++++++++---
src/backend/executor/execExprInterp.c | 205 ++++++++++++--------------
src/backend/jit/llvm/llvmjit_expr.c | 70 ++++++++-
src/backend/jit/llvm/llvmjit_types.c | 1 +
src/backend/utils/adt/jsonpath_exec.c | 79 +++++++++-
src/include/executor/execExpr.h | 20 ++-
src/include/utils/jsonpath.h | 4 -
7 files changed, 316 insertions(+), 151 deletions(-)
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index f50e0d703f8..68227ebee21 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -4159,9 +4159,16 @@ static void
ExecInitJsonExpr(JsonExpr *jexpr, ExprState *state, ExprEvalStep *scratch,
Datum *resv, bool *resnull)
{
+ ExprEvalStep *step;
JsonExprState *jsestate;
ListCell *argexprlc;
ListCell *argnamelc;
+ int skip_step_off;
+ int execpath_step_off;
+ int done_step_off;
+ int default_on_empty_step_off = -1;
+ int default_on_error_step_off = -1;
+ int default_on_empty_jump_off = -1;
/* JSON_TABLE preudo-function returns context item as a result */
if (jexpr->op == JSON_TABLE_OP)
@@ -4174,9 +4181,6 @@ ExecInitJsonExpr(JsonExpr *jexpr, ExprState *state, ExprEvalStep *scratch,
jsestate = palloc0(sizeof(JsonExprState));
jsestate->jsexpr = jexpr;
- scratch->opcode = EEOP_JSONEXPR;
- scratch->d.jsonexpr.jsestate = jsestate;
-
ExecInitExprRec((Expr *) jexpr->formatted_expr, state,
&jsestate->formatted_expr.value,
&jsestate->formatted_expr.isnull);
@@ -4185,15 +4189,12 @@ ExecInitJsonExpr(JsonExpr *jexpr, ExprState *state, ExprEvalStep *scratch,
&jsestate->pathspec.value,
&jsestate->pathspec.isnull);
- if (jexpr->on_empty)
- jsestate->default_on_empty =
- ExecInitExpr((Expr *) jexpr->on_empty->default_expr,
- state->parent);
-
- jsestate->default_on_error =
- ExecInitExpr((Expr *) jexpr->on_error->default_expr,
- state->parent);
+ scratch->opcode = EEOP_JSONEXPR_SKIP;
+ scratch->d.jsonexpr_skip.jsestate = jsestate;
+ skip_step_off = state->steps_len;
+ ExprEvalPushStep(state, scratch);
+ /* PASSING args. */
jsestate->args = NIL;
forboth(argexprlc, jexpr->passing_values,
@@ -4206,16 +4207,69 @@ ExecInitJsonExpr(JsonExpr *jexpr, ExprState *state, ExprEvalStep *scratch,
var->name = pstrdup(argname->sval);
var->typid = exprType((Node *) argexpr);
var->typmod = exprTypmod((Node *) argexpr);
- var->estate = ExecInitExpr(argexpr, state->parent);
+
+ /*
+ * A separate ExprState is not necessary for these expressions
+ * when being evaluated for a JsonExpr, like in this case,
+ * because they will evaluated as the steps of the JsonExpr.
+ */
+ var->estate = NULL;
var->econtext = NULL;
var->mcxt = NULL;
- var->evaluated = false;
- var->value = (Datum) 0;
- var->isnull = true;
- jsestate->args =
- lappend(jsestate->args, var);
+ /*
+ * Mark these as always evaluated because they must have been
+ * evaluated before JSON path evaluation begins, because we
+ * haven't pushed the step for the latter yet.
+ */
+ var->evaluated = true;
+
+ ExecInitExprRec((Expr *) argexpr, state, &var->value, &var->isnull);
+
+ jsestate->args = lappend(jsestate->args, var);
}
+ /* Step for the actual JSON path evaluation. */
+ scratch->opcode = EEOP_JSONEXPR_PATH;
+ scratch->d.jsonexpr.jsestate = jsestate;
+ execpath_step_off = state->steps_len;
ExprEvalPushStep(state, scratch);
+
+ if (jexpr->on_empty && jexpr->on_empty->default_expr)
+ {
+ default_on_empty_step_off = state->steps_len;
+ ExecInitExprRec((Expr *) jexpr->on_empty->default_expr, state, resv, resnull);
+
+ scratch->opcode = EEOP_JUMP;
+ default_on_empty_jump_off = state->steps_len;
+ ExprEvalPushStep(state, scratch);
+ }
+
+ if (jexpr->on_error->default_expr)
+ {
+ default_on_error_step_off = state->steps_len;
+ ExecInitExprRec((Expr *) jexpr->on_error->default_expr, state, resv, resnull);
+ }
+
+ /* Adjust jump locations */
+ done_step_off = state->steps_len;
+
+ /* EEOP_JSONEXPR_SKIP */
+ step = &state->steps[skip_step_off];
+ step->d.jsonexpr_skip.jump_done = done_step_off;
+
+ /* EEOP_JSONEXPR_PATH */
+ step = &state->steps[execpath_step_off];
+ step->d.jsonexpr.jump_done = done_step_off;
+ step->d.jsonexpr.jump_default_on_empty =
+ default_on_empty_step_off > 0 ? default_on_empty_step_off : done_step_off;
+ step->d.jsonexpr.jump_default_on_error =
+ default_on_error_step_off > 0 ? default_on_error_step_off : done_step_off;
+
+ /* EEOP_JUMP */
+ if (default_on_empty_jump_off > 0)
+ {
+ step = &state->steps[default_on_empty_jump_off];
+ step->d.jump.jumpdone = done_step_off;
+ }
}
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 56f7bd2a5ac..22959ae569c 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -491,7 +491,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
&&CASE_EEOP_SUBPLAN,
&&CASE_EEOP_JSON_CONSTRUCTOR,
&&CASE_EEOP_IS_JSON,
- &&CASE_EEOP_JSONEXPR,
+ &&CASE_EEOP_JSONEXPR_SKIP,
+ &&CASE_EEOP_JSONEXPR_PATH,
&&CASE_EEOP_AGG_STRICT_DESERIALIZE,
&&CASE_EEOP_AGG_DESERIALIZE,
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
@@ -1842,11 +1843,26 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_NEXT();
}
- EEO_CASE(EEOP_JSONEXPR)
+ EEO_CASE(EEOP_JSONEXPR_SKIP)
{
/* too complex for an inline implementation */
- ExecEvalJsonExpr(state, op, econtext);
- EEO_NEXT();
+ if (ExecEvalJsonExprSkip(state, op))
+ EEO_JUMP(op->d.jsonexpr_skip.jump_done);
+ else
+ EEO_NEXT();
+ }
+
+ EEO_CASE(EEOP_JSONEXPR_PATH)
+ {
+ /* too complex for an inline implementation */
+ int res = ExecEvalJsonExpr(state, op);
+
+ if (res == 0)
+ EEO_JUMP(op->d.jsonexpr.jump_default_on_empty);
+ else if (res == -1)
+ EEO_JUMP(op->d.jsonexpr.jump_default_on_error);
+ else
+ EEO_JUMP(op->d.jsonexpr.jump_done);
}
EEO_CASE(EEOP_LAST)
@@ -4701,59 +4717,6 @@ ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
*op->resnull = isnull;
}
-/*
- * Evaluate a JSON path variable caching computed value.
- */
-int
-EvalJsonPathVar(void *cxt, char *varName, int varNameLen,
- JsonbValue *val, JsonbValue *baseObject)
-{
- JsonPathVariableEvalContext *var = NULL;
- List *vars = cxt;
- ListCell *lc;
- int id = 1;
-
- if (!varName)
- return list_length(vars);
-
- foreach(lc, vars)
- {
- var = lfirst(lc);
-
- if (!strncmp(var->name, varName, varNameLen))
- break;
-
- var = NULL;
- id++;
- }
-
- if (!var)
- return -1;
-
- if (!var->evaluated)
- {
- MemoryContext oldcxt = var->mcxt ?
- MemoryContextSwitchTo(var->mcxt) : NULL;
-
- var->value = ExecEvalExpr(var->estate, var->econtext, &var->isnull);
- var->evaluated = true;
-
- if (oldcxt)
- MemoryContextSwitchTo(oldcxt);
- }
-
- if (var->isnull)
- {
- val->type = jbvNull;
- return 0;
- }
-
- JsonItemFromDatum(var->value, var->typid, var->typmod, val);
-
- *baseObject = *val;
- return id;
-}
-
/* Coerce C string to text, varchar(N), or bpchar(N) */
static Datum
ExecJsonCoerceCStringToText(const char *str, int32 len,
@@ -5275,9 +5238,8 @@ ExecJsonQueryCoercion(JsonExpr *jexpr, Oid typid, int32 typmod,
* type.
*/
static Datum
-ExecEvalJsonBehavior(ExprContext *econtext, JsonBehavior *behavior,
- ExprState *default_estate,
- Oid ret_typid, int32 ret_typmod, bool *is_null)
+ExecEvalJsonBehavior(JsonBehavior *behavior, Oid ret_typid,
+ int32 ret_typmod, bool *is_null)
{
*is_null = false;
@@ -5327,12 +5289,8 @@ ExecEvalJsonBehavior(ExprContext *econtext, JsonBehavior *behavior,
return (Datum) 0;
case JSON_BEHAVIOR_DEFAULT:
- /*
- * Execute DEFAULT expression.
- * Coercion is not needed here, because expression is
- * already coerced to the target type by the parser.
- */
- return ExecEvalExpr(default_estate, econtext, is_null);
+ Assert(0);
+ return (Datum) 0; /* must be handled by caller */
default:
elog(ERROR, "unrecognized SQL/JSON behavior %d", behavior->btype);
@@ -5341,28 +5299,27 @@ ExecEvalJsonBehavior(ExprContext *econtext, JsonBehavior *behavior,
}
static Datum
-ExecEvalJsonExprInternal(ExprState *state,
- JsonExprState *jsestate, ExprContext *econtext,
+ExecEvalJsonExprInternal(ExprState *state, JsonExprState *jsestate,
JsonPath *path, Datum item, bool *resnull,
- bool *error)
+ bool *empty, bool *error)
{
JsonExpr *jexpr = jsestate->jsexpr;
- bool empty = false;
Datum res = (Datum) 0;
Oid ret_typid = jexpr->returning->typid;
int32 ret_typmod = jexpr->returning->typmod;
*resnull = true;
+ *empty = false;
switch (jexpr->op)
{
case JSON_QUERY_OP:
- res = JsonPathQuery(item, path, jexpr->wrapper, &empty, error,
+ res = JsonPathQuery(item, path, jexpr->wrapper, empty, error,
jsestate->args);
if (error && *error)
return (Datum) 0;
- if (empty)
+ if (*empty)
break;
Assert(DatumGetPointer(res));
@@ -5373,13 +5330,13 @@ ExecEvalJsonExprInternal(ExprState *state,
case JSON_VALUE_OP:
{
- JsonbValue *jbv = JsonPathValue(item, path, &empty, error,
+ JsonbValue *jbv = JsonPathValue(item, path, empty, error,
jsestate->args);
if (error && *error)
return (Datum) 0;
- if (empty)
+ if (*empty)
break;
if (!jbv)
@@ -5412,78 +5369,100 @@ ExecEvalJsonExprInternal(ExprState *state,
return (Datum) 0;
}
- Assert(empty);
- Assert(jexpr->on_empty); /* it is not JSON_EXISTS */
+ Assert(*empty);
- if (jexpr->on_empty->btype == JSON_BEHAVIOR_ERROR)
- {
- if (error)
- {
- *error = true;
- return (Datum) 0;
- }
+ return (Datum) 0;
+}
- ereport(ERROR,
- (errcode(ERRCODE_NO_SQL_JSON_ITEM),
- errmsg("no SQL/JSON item")));
+bool
+ExecEvalJsonExprSkip(ExprState *state, ExprEvalStep *op)
+{
+ JsonExprState *jsestate = op->d.jsonexpr_skip.jsestate;
+
+ /*
+ * Skip if either of the input expressions has turned out to be
+ * NULL.
+ */
+ if (jsestate->formatted_expr.isnull ||
+ jsestate->pathspec.isnull)
+ {
+ *op->resvalue = (Datum) 0;
+ *op->resnull = true;
+ return true;
}
- /* Execute ON EMPTY behavior */
- return ExecEvalJsonBehavior(econtext, jexpr->on_empty,
- jsestate->default_on_empty,
- ret_typid, ret_typmod, resnull);
+ /*
+ * Go evaluate the PASSING args if any and subsequently JSON path
+ * itself.
+ */
+ return false;
}
/* ----------------------------------------------------------------
* ExecEvalJsonExpr
* ----------------------------------------------------------------
+ *
+ * Return value:
+ * 1 - Ok, jump to the end of JsonExpr
+ * 0 - empty result, need to execute DEFAULT ON EMPTY expression
+ * -1 - error occured, need to execute DEFAULT ON ERROR expression
*/
-void
-ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
+int
+ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op)
{
JsonExprState *jsestate = op->d.jsonexpr.jsestate;
JsonExpr *jexpr = jsestate->jsexpr;
Datum item;
Datum res;
JsonPath *path;
- ListCell *lc;
+ bool empty = false;
bool error = false;
- bool throwErrors = jexpr->on_error->btype == JSON_BEHAVIOR_ERROR;
-
- if (jsestate->formatted_expr.isnull || jsestate->pathspec.isnull)
- {
- *op->resnull = true;
- *op->resvalue = (Datum) 0;
- return;
- }
+ bool throw_errors = jexpr->on_error->btype == JSON_BEHAVIOR_ERROR;
item = jsestate->formatted_expr.value;
path = DatumGetJsonPathP(jsestate->pathspec.value);
- /* reset JSON path variable contexts */
- foreach(lc, jsestate->args)
+ res = ExecEvalJsonExprInternal(state, jsestate, path, item,
+ op->resnull, &empty,
+ throw_errors ? NULL : &error);
+
+ if (empty && !error)
{
- JsonPathVariableEvalContext *var = lfirst(lc);
+ Assert(jexpr->on_empty); /* it is not JSON_EXISTS */
- var->econtext = econtext;
- var->evaluated = false;
- }
+ if (jexpr->on_empty->btype == JSON_BEHAVIOR_ERROR)
+ {
+ if (throw_errors)
+ ereport(ERROR,
+ (errcode(ERRCODE_NO_SQL_JSON_ITEM),
+ errmsg("no SQL/JSON item")));
- res = ExecEvalJsonExprInternal(state, jsestate, econtext,
- path, item, op->resnull,
- throwErrors ? NULL : &error);
+ error = true; /* fallback to error behavior */
+ }
+ else if (jexpr->on_empty->btype == JSON_BEHAVIOR_DEFAULT)
+ return 0; /* jump to DEFAULT ON EMPTY expression */
+ else
+ /* Execute ON EMPTY behavior */
+ res = ExecEvalJsonBehavior(jexpr->on_empty,
+ jexpr->returning->typid,
+ jexpr->returning->typmod,
+ op->resnull);
+ }
if (error)
{
- Assert(!throwErrors);
+ Assert(!throw_errors);
+
+ if (jexpr->on_error->btype == JSON_BEHAVIOR_DEFAULT)
+ return -1; /* jump to DEFAULT ON ERROR expression */
/* Execute ON ERROR behavior */
- res = ExecEvalJsonBehavior(econtext, jexpr->on_error,
- jsestate->default_on_error,
+ res = ExecEvalJsonBehavior(jexpr->on_error,
jexpr->returning->typid,
jexpr->returning->typmod,
op->resnull);
}
*op->resvalue = res;
+ return 1; /* jump to the end of expression */
}
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index fd72630f5e6..ed53ad93443 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -2407,11 +2407,71 @@ llvm_compile_expr(ExprState *state)
LLVMBuildBr(b, opblocks[opno + 1]);
break;
- case EEOP_JSONEXPR:
- build_EvalXFunc(b, mod, "ExecEvalJsonExpr",
- v_state, op, v_econtext);
- LLVMBuildBr(b, opblocks[opno + 1]);
- break;
+ case EEOP_JSONEXPR_SKIP:
+ {
+ LLVMValueRef v_ret;
+
+ /*
+ * Call ExecEvalJsonExprSkip() to decide if JSON
+ * path evaluation can be skipped. This returns
+ * boolean "skip" flag.
+ */
+ v_ret = build_EvalXFunc(b, mod, "ExecEvalJsonExprSkip",
+ v_state, op);
+ v_ret = LLVMBuildZExt(b, v_ret, TypeStorageBool, "");
+
+ /*
+ * Jump to end if true was returned, which signifies
+ * skipping of JSON path evaluation, else to the
+ * next step which must point to the steps to
+ * evaluate PASSING args, if any, or to the JSON
+ * path evaluation.
+ */
+ LLVMBuildCondBr(b,
+ LLVMBuildICmp(b,
+ LLVMIntEQ,
+ v_ret,
+ l_sbool_const(0),
+ ""),
+ opblocks[opno + 1],
+ opblocks[op->d.jsonexpr_skip.jump_done]);
+ break;
+ }
+
+ case EEOP_JSONEXPR_PATH:
+ {
+ LLVMValueRef v_ret;
+ LLVMValueRef v_switch;
+ int n_jumps = 0;
+
+ v_ret = build_EvalXFunc(b, mod, "ExecEvalJsonExpr",
+ v_state, op);
+
+ if (op->d.jsonexpr.jump_default_on_empty != op->d.jsonexpr.jump_done)
+ n_jumps++;
+
+ if (op->d.jsonexpr.jump_default_on_error != op->d.jsonexpr.jump_done)
+ n_jumps++;
+
+ if (!n_jumps)
+ LLVMBuildBr(b, opblocks[op->d.jsonexpr.jump_done]);
+ else
+ {
+ v_switch = LLVMBuildSwitch(b, v_ret,
+ opblocks[op->d.jsonexpr.jump_done],
+ n_jumps);
+
+ if (op->d.jsonexpr.jump_default_on_empty != op->d.jsonexpr.jump_done)
+ LLVMAddCase(v_switch, l_int32_const(0),
+ opblocks[op->d.jsonexpr.jump_default_on_empty]);
+
+ if (op->d.jsonexpr.jump_default_on_error != op->d.jsonexpr.jump_done)
+ LLVMAddCase(v_switch, l_int32_const(-1),
+ opblocks[op->d.jsonexpr.jump_default_on_error]);
+ }
+
+ break;
+ }
case EEOP_LAST:
Assert(false);
diff --git a/src/backend/jit/llvm/llvmjit_types.c b/src/backend/jit/llvm/llvmjit_types.c
index 37fe64654b6..b9148ce515c 100644
--- a/src/backend/jit/llvm/llvmjit_types.c
+++ b/src/backend/jit/llvm/llvmjit_types.c
@@ -136,6 +136,7 @@ void *referenced_functions[] =
ExecEvalJsonConstructor,
ExecEvalJsonIsPredicate,
ExecEvalJsonExpr,
+ ExecEvalJsonExprSkip,
MakeExpandedObjectReadOnlyInternal,
slot_getmissingattrs,
slot_getsomeattrs_int,
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index 5b6a4805721..b8949789710 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -286,6 +286,8 @@ static JsonPathExecResult appendBoolResult(JsonPathExecContext *cxt,
JsonPathItem *jsp, JsonValueList *found, JsonPathBool res);
static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
JsonbValue *value);
+static int evalJsonPathVariable(void *cxt, char *varName, int varNameLen,
+ JsonbValue *val, JsonbValue *baseObject);
static void getJsonPathVariable(JsonPathExecContext *cxt,
JsonPathItem *variable, JsonbValue *value);
static int getJsonPathVariableFromJsonb(void *varsJsonb, char *varName,
@@ -2172,6 +2174,71 @@ getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
}
}
+/*
+ * Evaluate a JSON path variable caching computed value.
+ */
+static int
+evalJsonPathVariable(void *cxt, char *varName, int varNameLen,
+ JsonbValue *val, JsonbValue *baseObject)
+{
+ JsonPathVariableEvalContext *var = NULL;
+ List *vars = cxt;
+ ListCell *lc;
+ int id = 1;
+
+ if (!varName)
+ return list_length(vars);
+
+ foreach(lc, vars)
+ {
+ var = lfirst(lc);
+
+ if (!strncmp(var->name, varName, varNameLen))
+ break;
+
+ var = NULL;
+ id++;
+ }
+
+ if (!var)
+ return -1;
+
+ /*
+ * When belonging to a JsonExpr, path variables are computed with the
+ * JsonExpr's ExprState (var->estate is NULL), so don't need to be computed
+ * here. In some other cases, such as when the path variables belonging
+ * to a JsonTable instead, those variables must be evaluated on their own,
+ * without the enclosing JsonExpr itself needing to be evaluated, so must
+ * be handled here.
+ */
+ if (!var->estate)
+ {
+ Assert(var->evaluated);
+ }
+ else if (!var->evaluated)
+ {
+ MemoryContext oldcxt = var->mcxt ? MemoryContextSwitchTo(var->mcxt) : NULL;
+
+ Assert(var->econtext);
+ var->value = ExecEvalExpr(var->estate, var->econtext, &var->isnull);
+ var->evaluated = true;
+
+ if (oldcxt)
+ MemoryContextSwitchTo(oldcxt);
+ }
+
+ if (var->isnull)
+ {
+ val->type = jbvNull;
+ return 0;
+ }
+
+ JsonItemFromDatum(var->value, var->typid, var->typmod, val);
+
+ *baseObject = *val;
+ return id;
+}
+
/*
* Get the value of variable passed to jsonpath executor
*/
@@ -2903,7 +2970,7 @@ compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2,
bool
JsonPathExists(Datum jb, JsonPath *jp, List *vars, bool *error)
{
- JsonPathExecResult res = executeJsonPath(jp, vars, EvalJsonPathVar,
+ JsonPathExecResult res = executeJsonPath(jp, vars, evalJsonPathVariable,
DatumGetJsonbP(jb), !error, NULL,
true);
@@ -2925,8 +2992,8 @@ JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty,
JsonPathExecResult res PG_USED_FOR_ASSERTS_ONLY;
int count;
- res = executeJsonPath(jp, vars, EvalJsonPathVar, DatumGetJsonbP(jb), !error,
- &found, true);
+ res = executeJsonPath(jp, vars, evalJsonPathVariable,
+ DatumGetJsonbP(jb), !error, &found, true);
Assert(error || !jperIsError(res));
@@ -2992,8 +3059,8 @@ JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars)
JsonPathExecResult jper PG_USED_FOR_ASSERTS_ONLY;
int count;
- jper = executeJsonPath(jp, vars, EvalJsonPathVar, DatumGetJsonbP(jb), !error,
- &found, true);
+ jper = executeJsonPath(jp, vars, evalJsonPathVariable,
+ DatumGetJsonbP(jb), !error, &found, true);
Assert(error || !jperIsError(jper));
@@ -3306,7 +3373,7 @@ JsonTableResetContextItem(JsonTableScanState *scan, Datum item)
oldcxt = MemoryContextSwitchTo(scan->mcxt);
- res = executeJsonPath(scan->path, scan->args, EvalJsonPathVar, js,
+ res = executeJsonPath(scan->path, scan->args, evalJsonPathVariable, js,
scan->errorOnError, &scan->found, false /* FIXME */ );
MemoryContextSwitchTo(oldcxt);
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index adabf57c97b..b005bf440dd 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -244,7 +244,8 @@ typedef enum ExprEvalOp
EEOP_SUBPLAN,
EEOP_JSON_CONSTRUCTOR,
EEOP_IS_JSON,
- EEOP_JSONEXPR,
+ EEOP_JSONEXPR_SKIP,
+ EEOP_JSONEXPR_PATH,
/* aggregation related nodes */
EEOP_AGG_STRICT_DESERIALIZE,
@@ -696,8 +697,18 @@ typedef struct ExprEvalStep
struct
{
struct JsonExprState *jsestate;
+ int jump_done;
+ int jump_default_on_empty; /* ON EMPTY DEFAULT expression */
+ int jump_default_on_error; /* ON ERROR DEFAULT expression */
} jsonexpr;
+ /* for EEOP_JSONEXPR_SKIP */
+ struct
+ {
+ struct JsonExprState *jsestate;
+ int jump_done;
+ } jsonexpr_skip;
+
} d;
} ExprEvalStep;
@@ -764,11 +775,8 @@ typedef struct JsonExprState
NullableDatum
formatted_expr, /* formatted context item value */
- coercion_expr, /* input for JSON item coercion */
pathspec; /* path specification value */
- ExprState *default_on_empty; /* ON EMPTY DEFAULT expression */
- ExprState *default_on_error; /* ON ERROR DEFAULT expression */
List *args; /* passing arguments */
} JsonExprState;
@@ -831,8 +839,8 @@ extern void ExecEvalSysVar(ExprState *state, ExprEvalStep *op,
ExprContext *econtext, TupleTableSlot *slot);
extern void ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
-extern void ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op,
- ExprContext *econtext);
+extern int ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op);
+extern bool ExecEvalJsonExprSkip(ExprState *state, ExprEvalStep *op);
extern void ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup,
ExprContext *aggcontext);
diff --git a/src/include/utils/jsonpath.h b/src/include/utils/jsonpath.h
index e9134b7eab4..a33a770f7aa 100644
--- a/src/include/utils/jsonpath.h
+++ b/src/include/utils/jsonpath.h
@@ -280,10 +280,6 @@ extern Datum JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper,
bool *empty, bool *error, List *vars);
extern JsonbValue *JsonPathValue(Datum jb, JsonPath *jp, bool *empty,
bool *error, List *vars);
-
-extern int EvalJsonPathVar(void *vars, char *varName, int varNameLen,
- JsonbValue *val, JsonbValue *baseObject);
-
extern PGDLLIMPORT const TableFuncRoutine JsonbTableRoutine;
#endif
--
2.17.1