mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-20 14:53:23 +02:00
expression eval: Fix EEOP_JSON_CONSTRUCTOR and EEOP_JSONEXPR size.
The new expression step types increased the size of ExprEvalStep by ~4 for all types of expression steps, slowing down expression evaluation noticeably. Move them out of line. There's other issues with these expression steps, but addressing them is largely independent of this aspect. Author: Andres Freund <andres@anarazel.de> Reviewed-By: Andrew Dunstan <andrew@dunslane.net> Discussion: https://postgr.es/m/20220616233130.rparivafipt6doj3@alap3.anarazel.de Backpatch: 15-
This commit is contained in:
parent
49ddd98763
commit
5a1ab894f7
@ -2470,32 +2470,38 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
JsonConstructorExprState *jcstate;
|
||||||
|
|
||||||
|
jcstate = palloc0(sizeof(JsonConstructorExprState));
|
||||||
|
|
||||||
scratch.opcode = EEOP_JSON_CONSTRUCTOR;
|
scratch.opcode = EEOP_JSON_CONSTRUCTOR;
|
||||||
scratch.d.json_constructor.constructor = ctor;
|
scratch.d.json_constructor.jcstate = jcstate;
|
||||||
scratch.d.json_constructor.arg_values = palloc(sizeof(Datum) * nargs);
|
|
||||||
scratch.d.json_constructor.arg_nulls = palloc(sizeof(bool) * nargs);
|
jcstate->constructor = ctor;
|
||||||
scratch.d.json_constructor.arg_types = palloc(sizeof(Oid) * nargs);
|
jcstate->arg_values = palloc(sizeof(Datum) * nargs);
|
||||||
scratch.d.json_constructor.nargs = nargs;
|
jcstate->arg_nulls = palloc(sizeof(bool) * nargs);
|
||||||
|
jcstate->arg_types = palloc(sizeof(Oid) * nargs);
|
||||||
|
jcstate->nargs = nargs;
|
||||||
|
|
||||||
foreach(lc, args)
|
foreach(lc, args)
|
||||||
{
|
{
|
||||||
Expr *arg = (Expr *) lfirst(lc);
|
Expr *arg = (Expr *) lfirst(lc);
|
||||||
|
|
||||||
scratch.d.json_constructor.arg_types[argno] = exprType((Node *) arg);
|
jcstate->arg_types[argno] = exprType((Node *) arg);
|
||||||
|
|
||||||
if (IsA(arg, Const))
|
if (IsA(arg, Const))
|
||||||
{
|
{
|
||||||
/* Don't evaluate const arguments every round */
|
/* Don't evaluate const arguments every round */
|
||||||
Const *con = (Const *) arg;
|
Const *con = (Const *) arg;
|
||||||
|
|
||||||
scratch.d.json_constructor.arg_values[argno] = con->constvalue;
|
jcstate->arg_values[argno] = con->constvalue;
|
||||||
scratch.d.json_constructor.arg_nulls[argno] = con->constisnull;
|
jcstate->arg_nulls[argno] = con->constisnull;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ExecInitExprRec(arg, state,
|
ExecInitExprRec(arg, state,
|
||||||
&scratch.d.json_constructor.arg_values[argno],
|
&jcstate->arg_values[argno],
|
||||||
&scratch.d.json_constructor.arg_nulls[argno]);
|
&jcstate->arg_nulls[argno]);
|
||||||
}
|
}
|
||||||
argno++;
|
argno++;
|
||||||
}
|
}
|
||||||
@ -2506,14 +2512,14 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
bool is_jsonb =
|
bool is_jsonb =
|
||||||
ctor->returning->format->format_type == JS_FORMAT_JSONB;
|
ctor->returning->format->format_type == JS_FORMAT_JSONB;
|
||||||
|
|
||||||
scratch.d.json_constructor.arg_type_cache =
|
jcstate->arg_type_cache =
|
||||||
palloc(sizeof(*scratch.d.json_constructor.arg_type_cache) * nargs);
|
palloc(sizeof(*jcstate->arg_type_cache) * nargs);
|
||||||
|
|
||||||
for (int i = 0; i < nargs; i++)
|
for (int i = 0; i < nargs; i++)
|
||||||
{
|
{
|
||||||
int category;
|
int category;
|
||||||
Oid outfuncid;
|
Oid outfuncid;
|
||||||
Oid typid = scratch.d.json_constructor.arg_types[i];
|
Oid typid = jcstate->arg_types[i];
|
||||||
|
|
||||||
if (is_jsonb)
|
if (is_jsonb)
|
||||||
{
|
{
|
||||||
@ -2532,8 +2538,8 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
category = (int) jscat;
|
category = (int) jscat;
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch.d.json_constructor.arg_type_cache[i].outfuncid = outfuncid;
|
jcstate->arg_type_cache[i].outfuncid = outfuncid;
|
||||||
scratch.d.json_constructor.arg_type_cache[i].category = category;
|
jcstate->arg_type_cache[i].category = category;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2572,41 +2578,44 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
case T_JsonExpr:
|
case T_JsonExpr:
|
||||||
{
|
{
|
||||||
JsonExpr *jexpr = castNode(JsonExpr, node);
|
JsonExpr *jexpr = castNode(JsonExpr, node);
|
||||||
|
JsonExprState *jsestate = palloc0(sizeof(JsonExprState));
|
||||||
ListCell *argexprlc;
|
ListCell *argexprlc;
|
||||||
ListCell *argnamelc;
|
ListCell *argnamelc;
|
||||||
|
|
||||||
scratch.opcode = EEOP_JSONEXPR;
|
scratch.opcode = EEOP_JSONEXPR;
|
||||||
scratch.d.jsonexpr.jsexpr = jexpr;
|
scratch.d.jsonexpr.jsestate = jsestate;
|
||||||
|
|
||||||
scratch.d.jsonexpr.formatted_expr =
|
jsestate->jsexpr = jexpr;
|
||||||
palloc(sizeof(*scratch.d.jsonexpr.formatted_expr));
|
|
||||||
|
jsestate->formatted_expr =
|
||||||
|
palloc(sizeof(*jsestate->formatted_expr));
|
||||||
|
|
||||||
ExecInitExprRec((Expr *) jexpr->formatted_expr, state,
|
ExecInitExprRec((Expr *) jexpr->formatted_expr, state,
|
||||||
&scratch.d.jsonexpr.formatted_expr->value,
|
&jsestate->formatted_expr->value,
|
||||||
&scratch.d.jsonexpr.formatted_expr->isnull);
|
&jsestate->formatted_expr->isnull);
|
||||||
|
|
||||||
scratch.d.jsonexpr.pathspec =
|
jsestate->pathspec =
|
||||||
palloc(sizeof(*scratch.d.jsonexpr.pathspec));
|
palloc(sizeof(*jsestate->pathspec));
|
||||||
|
|
||||||
ExecInitExprRec((Expr *) jexpr->path_spec, state,
|
ExecInitExprRec((Expr *) jexpr->path_spec, state,
|
||||||
&scratch.d.jsonexpr.pathspec->value,
|
&jsestate->pathspec->value,
|
||||||
&scratch.d.jsonexpr.pathspec->isnull);
|
&jsestate->pathspec->isnull);
|
||||||
|
|
||||||
scratch.d.jsonexpr.res_expr =
|
jsestate->res_expr =
|
||||||
palloc(sizeof(*scratch.d.jsonexpr.res_expr));
|
palloc(sizeof(*jsestate->res_expr));
|
||||||
|
|
||||||
scratch.d.jsonexpr.result_expr = jexpr->result_coercion
|
jsestate->result_expr = jexpr->result_coercion
|
||||||
? ExecInitExprWithCaseValue((Expr *) jexpr->result_coercion->expr,
|
? ExecInitExprWithCaseValue((Expr *) jexpr->result_coercion->expr,
|
||||||
state->parent,
|
state->parent,
|
||||||
&scratch.d.jsonexpr.res_expr->value,
|
&jsestate->res_expr->value,
|
||||||
&scratch.d.jsonexpr.res_expr->isnull)
|
&jsestate->res_expr->isnull)
|
||||||
: NULL;
|
: NULL;
|
||||||
|
|
||||||
scratch.d.jsonexpr.default_on_empty = !jexpr->on_empty ? NULL :
|
jsestate->default_on_empty = !jexpr->on_empty ? NULL :
|
||||||
ExecInitExpr((Expr *) jexpr->on_empty->default_expr,
|
ExecInitExpr((Expr *) jexpr->on_empty->default_expr,
|
||||||
state->parent);
|
state->parent);
|
||||||
|
|
||||||
scratch.d.jsonexpr.default_on_error =
|
jsestate->default_on_error =
|
||||||
ExecInitExpr((Expr *) jexpr->on_error->default_expr,
|
ExecInitExpr((Expr *) jexpr->on_error->default_expr,
|
||||||
state->parent);
|
state->parent);
|
||||||
|
|
||||||
@ -2617,11 +2626,11 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
|
|
||||||
/* lookup the result type's input function */
|
/* lookup the result type's input function */
|
||||||
getTypeInputInfo(jexpr->returning->typid, &typinput,
|
getTypeInputInfo(jexpr->returning->typid, &typinput,
|
||||||
&scratch.d.jsonexpr.input.typioparam);
|
&jsestate->input.typioparam);
|
||||||
fmgr_info(typinput, &scratch.d.jsonexpr.input.func);
|
fmgr_info(typinput, &jsestate->input.func);
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch.d.jsonexpr.args = NIL;
|
jsestate->args = NIL;
|
||||||
|
|
||||||
forboth(argexprlc, jexpr->passing_values,
|
forboth(argexprlc, jexpr->passing_values,
|
||||||
argnamelc, jexpr->passing_names)
|
argnamelc, jexpr->passing_names)
|
||||||
@ -2640,11 +2649,11 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
var->value = (Datum) 0;
|
var->value = (Datum) 0;
|
||||||
var->isnull = true;
|
var->isnull = true;
|
||||||
|
|
||||||
scratch.d.jsonexpr.args =
|
jsestate->args =
|
||||||
lappend(scratch.d.jsonexpr.args, var);
|
lappend(jsestate->args, var);
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch.d.jsonexpr.cache = NULL;
|
jsestate->cache = NULL;
|
||||||
|
|
||||||
if (jexpr->coercions)
|
if (jexpr->coercions)
|
||||||
{
|
{
|
||||||
@ -2653,13 +2662,13 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
Datum *caseval;
|
Datum *caseval;
|
||||||
bool *casenull;
|
bool *casenull;
|
||||||
|
|
||||||
scratch.d.jsonexpr.coercion_expr =
|
jsestate->coercion_expr =
|
||||||
palloc(sizeof(*scratch.d.jsonexpr.coercion_expr));
|
palloc(sizeof(*jsestate->coercion_expr));
|
||||||
|
|
||||||
caseval = &scratch.d.jsonexpr.coercion_expr->value;
|
caseval = &jsestate->coercion_expr->value;
|
||||||
casenull = &scratch.d.jsonexpr.coercion_expr->isnull;
|
casenull = &jsestate->coercion_expr->isnull;
|
||||||
|
|
||||||
for (cstate = &scratch.d.jsonexpr.coercions.null,
|
for (cstate = &jsestate->coercions.null,
|
||||||
coercion = &jexpr->coercions->null;
|
coercion = &jexpr->coercions->null;
|
||||||
coercion <= &jexpr->coercions->composite;
|
coercion <= &jexpr->coercions->composite;
|
||||||
coercion++, cstate++)
|
coercion++, cstate++)
|
||||||
|
@ -4510,39 +4510,40 @@ ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
|
|||||||
ExprContext *econtext)
|
ExprContext *econtext)
|
||||||
{
|
{
|
||||||
Datum res;
|
Datum res;
|
||||||
JsonConstructorExpr *ctor = op->d.json_constructor.constructor;
|
JsonConstructorExprState *jcstate = op->d.json_constructor.jcstate;
|
||||||
|
JsonConstructorExpr *ctor = jcstate->constructor;
|
||||||
bool is_jsonb = ctor->returning->format->format_type == JS_FORMAT_JSONB;
|
bool is_jsonb = ctor->returning->format->format_type == JS_FORMAT_JSONB;
|
||||||
bool isnull = false;
|
bool isnull = false;
|
||||||
|
|
||||||
if (ctor->type == JSCTOR_JSON_ARRAY)
|
if (ctor->type == JSCTOR_JSON_ARRAY)
|
||||||
res = (is_jsonb ?
|
res = (is_jsonb ?
|
||||||
jsonb_build_array_worker :
|
jsonb_build_array_worker :
|
||||||
json_build_array_worker) (op->d.json_constructor.nargs,
|
json_build_array_worker) (jcstate->nargs,
|
||||||
op->d.json_constructor.arg_values,
|
jcstate->arg_values,
|
||||||
op->d.json_constructor.arg_nulls,
|
jcstate->arg_nulls,
|
||||||
op->d.json_constructor.arg_types,
|
jcstate->arg_types,
|
||||||
op->d.json_constructor.constructor->absent_on_null);
|
ctor->absent_on_null);
|
||||||
else if (ctor->type == JSCTOR_JSON_OBJECT)
|
else if (ctor->type == JSCTOR_JSON_OBJECT)
|
||||||
res = (is_jsonb ?
|
res = (is_jsonb ?
|
||||||
jsonb_build_object_worker :
|
jsonb_build_object_worker :
|
||||||
json_build_object_worker) (op->d.json_constructor.nargs,
|
json_build_object_worker) (jcstate->nargs,
|
||||||
op->d.json_constructor.arg_values,
|
jcstate->arg_values,
|
||||||
op->d.json_constructor.arg_nulls,
|
jcstate->arg_nulls,
|
||||||
op->d.json_constructor.arg_types,
|
jcstate->arg_types,
|
||||||
op->d.json_constructor.constructor->absent_on_null,
|
ctor->absent_on_null,
|
||||||
op->d.json_constructor.constructor->unique);
|
ctor->unique);
|
||||||
else if (ctor->type == JSCTOR_JSON_SCALAR)
|
else if (ctor->type == JSCTOR_JSON_SCALAR)
|
||||||
{
|
{
|
||||||
if (op->d.json_constructor.arg_nulls[0])
|
if (jcstate->arg_nulls[0])
|
||||||
{
|
{
|
||||||
res = (Datum) 0;
|
res = (Datum) 0;
|
||||||
isnull = true;
|
isnull = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Datum value = op->d.json_constructor.arg_values[0];
|
Datum value = jcstate->arg_values[0];
|
||||||
int category = op->d.json_constructor.arg_type_cache[0].category;
|
int category = jcstate->arg_type_cache[0].category;
|
||||||
Oid outfuncid = op->d.json_constructor.arg_type_cache[0].outfuncid;
|
Oid outfuncid = jcstate->arg_type_cache[0].outfuncid;
|
||||||
|
|
||||||
if (is_jsonb)
|
if (is_jsonb)
|
||||||
res = to_jsonb_worker(value, category, outfuncid);
|
res = to_jsonb_worker(value, category, outfuncid);
|
||||||
@ -4552,14 +4553,14 @@ ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
|
|||||||
}
|
}
|
||||||
else if (ctor->type == JSCTOR_JSON_PARSE)
|
else if (ctor->type == JSCTOR_JSON_PARSE)
|
||||||
{
|
{
|
||||||
if (op->d.json_constructor.arg_nulls[0])
|
if (jcstate->arg_nulls[0])
|
||||||
{
|
{
|
||||||
res = (Datum) 0;
|
res = (Datum) 0;
|
||||||
isnull = true;
|
isnull = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Datum value = op->d.json_constructor.arg_values[0];
|
Datum value = jcstate->arg_values[0];
|
||||||
text *js = DatumGetTextP(value);
|
text *js = DatumGetTextP(value);
|
||||||
|
|
||||||
if (is_jsonb)
|
if (is_jsonb)
|
||||||
@ -4627,14 +4628,17 @@ ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext,
|
|||||||
Datum res, bool *isNull, void *p, bool *error)
|
Datum res, bool *isNull, void *p, bool *error)
|
||||||
{
|
{
|
||||||
ExprState *estate = p;
|
ExprState *estate = p;
|
||||||
|
JsonExprState *jsestate;
|
||||||
|
|
||||||
if (estate) /* coerce using specified expression */
|
if (estate) /* coerce using specified expression */
|
||||||
return ExecEvalExpr(estate, econtext, isNull);
|
return ExecEvalExpr(estate, econtext, isNull);
|
||||||
|
|
||||||
if (op->d.jsonexpr.jsexpr->op != JSON_EXISTS_OP)
|
jsestate = op->d.jsonexpr.jsestate;
|
||||||
|
|
||||||
|
if (jsestate->jsexpr->op != JSON_EXISTS_OP)
|
||||||
{
|
{
|
||||||
JsonCoercion *coercion = op->d.jsonexpr.jsexpr->result_coercion;
|
JsonCoercion *coercion = jsestate->jsexpr->result_coercion;
|
||||||
JsonExpr *jexpr = op->d.jsonexpr.jsexpr;
|
JsonExpr *jexpr = jsestate->jsexpr;
|
||||||
Jsonb *jb = *isNull ? NULL : DatumGetJsonbP(res);
|
Jsonb *jb = *isNull ? NULL : DatumGetJsonbP(res);
|
||||||
|
|
||||||
if ((coercion && coercion->via_io) ||
|
if ((coercion && coercion->via_io) ||
|
||||||
@ -4644,25 +4648,25 @@ ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext,
|
|||||||
/* strip quotes and call typinput function */
|
/* strip quotes and call typinput function */
|
||||||
char *str = *isNull ? NULL : JsonbUnquote(jb);
|
char *str = *isNull ? NULL : JsonbUnquote(jb);
|
||||||
|
|
||||||
return InputFunctionCall(&op->d.jsonexpr.input.func, str,
|
return InputFunctionCall(&jsestate->input.func, str,
|
||||||
op->d.jsonexpr.input.typioparam,
|
jsestate->input.typioparam,
|
||||||
jexpr->returning->typmod);
|
jexpr->returning->typmod);
|
||||||
}
|
}
|
||||||
else if (coercion && coercion->via_populate)
|
else if (coercion && coercion->via_populate)
|
||||||
return json_populate_type(res, JSONBOID,
|
return json_populate_type(res, JSONBOID,
|
||||||
jexpr->returning->typid,
|
jexpr->returning->typid,
|
||||||
jexpr->returning->typmod,
|
jexpr->returning->typmod,
|
||||||
&op->d.jsonexpr.cache,
|
&jsestate->cache,
|
||||||
econtext->ecxt_per_query_memory,
|
econtext->ecxt_per_query_memory,
|
||||||
isNull);
|
isNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op->d.jsonexpr.result_expr)
|
if (jsestate->result_expr)
|
||||||
{
|
{
|
||||||
op->d.jsonexpr.res_expr->value = res;
|
jsestate->res_expr->value = res;
|
||||||
op->d.jsonexpr.res_expr->isnull = *isNull;
|
jsestate->res_expr->isnull = *isNull;
|
||||||
|
|
||||||
res = ExecEvalExpr(op->d.jsonexpr.result_expr, econtext, isNull);
|
res = ExecEvalExpr(jsestate->result_expr, econtext, isNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -4895,7 +4899,8 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
|
|||||||
{
|
{
|
||||||
ExecEvalJsonExprContext *cxt = pcxt;
|
ExecEvalJsonExprContext *cxt = pcxt;
|
||||||
JsonPath *path = cxt->path;
|
JsonPath *path = cxt->path;
|
||||||
JsonExpr *jexpr = op->d.jsonexpr.jsexpr;
|
JsonExprState *jsestate = op->d.jsonexpr.jsestate;
|
||||||
|
JsonExpr *jexpr = jsestate->jsexpr;
|
||||||
ExprState *estate = NULL;
|
ExprState *estate = NULL;
|
||||||
bool empty = false;
|
bool empty = false;
|
||||||
Datum res = (Datum) 0;
|
Datum res = (Datum) 0;
|
||||||
@ -4904,7 +4909,7 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
|
|||||||
{
|
{
|
||||||
case JSON_QUERY_OP:
|
case JSON_QUERY_OP:
|
||||||
res = JsonPathQuery(item, path, jexpr->wrapper, &empty, error,
|
res = JsonPathQuery(item, path, jexpr->wrapper, &empty, error,
|
||||||
op->d.jsonexpr.args);
|
jsestate->args);
|
||||||
if (error && *error)
|
if (error && *error)
|
||||||
{
|
{
|
||||||
*resnull = true;
|
*resnull = true;
|
||||||
@ -4917,7 +4922,7 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
|
|||||||
{
|
{
|
||||||
struct JsonCoercionState *jcstate;
|
struct JsonCoercionState *jcstate;
|
||||||
JsonbValue *jbv = JsonPathValue(item, path, &empty, error,
|
JsonbValue *jbv = JsonPathValue(item, path, &empty, error,
|
||||||
op->d.jsonexpr.args);
|
jsestate->args);
|
||||||
|
|
||||||
if (error && *error)
|
if (error && *error)
|
||||||
return (Datum) 0;
|
return (Datum) 0;
|
||||||
@ -4940,8 +4945,8 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
|
|||||||
|
|
||||||
/* Use coercion from SQL/JSON item type to the output type */
|
/* Use coercion from SQL/JSON item type to the output type */
|
||||||
res = ExecPrepareJsonItemCoercion(jbv,
|
res = ExecPrepareJsonItemCoercion(jbv,
|
||||||
op->d.jsonexpr.jsexpr->returning,
|
jsestate->jsexpr->returning,
|
||||||
&op->d.jsonexpr.coercions,
|
&jsestate->coercions,
|
||||||
&jcstate);
|
&jcstate);
|
||||||
|
|
||||||
if (jcstate->coercion &&
|
if (jcstate->coercion &&
|
||||||
@ -4973,27 +4978,27 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
|
|||||||
|
|
||||||
/* coerce using specific expression */
|
/* coerce using specific expression */
|
||||||
estate = jcstate->estate;
|
estate = jcstate->estate;
|
||||||
op->d.jsonexpr.coercion_expr->value = res;
|
jsestate->coercion_expr->value = res;
|
||||||
op->d.jsonexpr.coercion_expr->isnull = *resnull;
|
jsestate->coercion_expr->isnull = *resnull;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case JSON_EXISTS_OP:
|
case JSON_EXISTS_OP:
|
||||||
{
|
{
|
||||||
bool exists = JsonPathExists(item, path,
|
bool exists = JsonPathExists(item, path,
|
||||||
op->d.jsonexpr.args,
|
jsestate->args,
|
||||||
error);
|
error);
|
||||||
|
|
||||||
*resnull = error && *error;
|
*resnull = error && *error;
|
||||||
res = BoolGetDatum(exists);
|
res = BoolGetDatum(exists);
|
||||||
|
|
||||||
if (!op->d.jsonexpr.result_expr)
|
if (!jsestate->result_expr)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
/* coerce using result expression */
|
/* coerce using result expression */
|
||||||
estate = op->d.jsonexpr.result_expr;
|
estate = jsestate->result_expr;
|
||||||
op->d.jsonexpr.res_expr->value = res;
|
jsestate->res_expr->value = res;
|
||||||
op->d.jsonexpr.res_expr->isnull = *resnull;
|
jsestate->res_expr->isnull = *resnull;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5029,11 +5034,11 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
|
|||||||
* Execute DEFAULT expression as a coercion expression, because
|
* Execute DEFAULT expression as a coercion expression, because
|
||||||
* its result is already coerced to the target type.
|
* its result is already coerced to the target type.
|
||||||
*/
|
*/
|
||||||
estate = op->d.jsonexpr.default_on_empty;
|
estate = jsestate->default_on_empty;
|
||||||
else
|
else
|
||||||
/* Execute ON EMPTY behavior */
|
/* Execute ON EMPTY behavior */
|
||||||
res = ExecEvalJsonBehavior(econtext, jexpr->on_empty,
|
res = ExecEvalJsonBehavior(econtext, jexpr->on_empty,
|
||||||
op->d.jsonexpr.default_on_empty,
|
jsestate->default_on_empty,
|
||||||
resnull);
|
resnull);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5066,7 +5071,8 @@ void
|
|||||||
ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
|
ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
|
||||||
{
|
{
|
||||||
ExecEvalJsonExprContext cxt;
|
ExecEvalJsonExprContext cxt;
|
||||||
JsonExpr *jexpr = op->d.jsonexpr.jsexpr;
|
JsonExprState *jsestate = op->d.jsonexpr.jsestate;
|
||||||
|
JsonExpr *jexpr = jsestate->jsexpr;
|
||||||
Datum item;
|
Datum item;
|
||||||
Datum res = (Datum) 0;
|
Datum res = (Datum) 0;
|
||||||
JsonPath *path;
|
JsonPath *path;
|
||||||
@ -5078,7 +5084,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
|
|||||||
*op->resnull = true; /* until we get a result */
|
*op->resnull = true; /* until we get a result */
|
||||||
*op->resvalue = (Datum) 0;
|
*op->resvalue = (Datum) 0;
|
||||||
|
|
||||||
if (op->d.jsonexpr.formatted_expr->isnull || op->d.jsonexpr.pathspec->isnull)
|
if (jsestate->formatted_expr->isnull || jsestate->pathspec->isnull)
|
||||||
{
|
{
|
||||||
/* execute domain checks for NULLs */
|
/* execute domain checks for NULLs */
|
||||||
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull,
|
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull,
|
||||||
@ -5088,11 +5094,11 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
item = op->d.jsonexpr.formatted_expr->value;
|
item = jsestate->formatted_expr->value;
|
||||||
path = DatumGetJsonPathP(op->d.jsonexpr.pathspec->value);
|
path = DatumGetJsonPathP(jsestate->pathspec->value);
|
||||||
|
|
||||||
/* reset JSON path variable contexts */
|
/* reset JSON path variable contexts */
|
||||||
foreach(lc, op->d.jsonexpr.args)
|
foreach(lc, jsestate->args)
|
||||||
{
|
{
|
||||||
JsonPathVariableEvalContext *var = lfirst(lc);
|
JsonPathVariableEvalContext *var = lfirst(lc);
|
||||||
|
|
||||||
@ -5100,7 +5106,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
|
|||||||
var->evaluated = false;
|
var->evaluated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
needSubtrans = ExecEvalJsonNeedsSubTransaction(jexpr, &op->d.jsonexpr.coercions);
|
needSubtrans = ExecEvalJsonNeedsSubTransaction(jexpr, &jsestate->coercions);
|
||||||
|
|
||||||
cxt.path = path;
|
cxt.path = path;
|
||||||
cxt.error = throwErrors ? NULL : &error;
|
cxt.error = throwErrors ? NULL : &error;
|
||||||
@ -5115,7 +5121,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
|
|||||||
{
|
{
|
||||||
/* Execute ON ERROR behavior */
|
/* Execute ON ERROR behavior */
|
||||||
res = ExecEvalJsonBehavior(econtext, jexpr->on_error,
|
res = ExecEvalJsonBehavior(econtext, jexpr->on_error,
|
||||||
op->d.jsonexpr.default_on_error,
|
jsestate->default_on_error,
|
||||||
op->resnull);
|
op->resnull);
|
||||||
|
|
||||||
/* result is already coerced in DEFAULT behavior case */
|
/* result is already coerced in DEFAULT behavior case */
|
||||||
|
@ -22,6 +22,8 @@ struct ExprEvalStep;
|
|||||||
struct SubscriptingRefState;
|
struct SubscriptingRefState;
|
||||||
struct ScalarArrayOpExprHashTable;
|
struct ScalarArrayOpExprHashTable;
|
||||||
struct JsonbValue;
|
struct JsonbValue;
|
||||||
|
struct JsonExprState;
|
||||||
|
struct JsonConstructorExprState;
|
||||||
|
|
||||||
/* Bits in ExprState->flags (see also execnodes.h for public flag bits): */
|
/* Bits in ExprState->flags (see also execnodes.h for public flag bits): */
|
||||||
/* expression's interpreter has been initialized */
|
/* expression's interpreter has been initialized */
|
||||||
@ -676,16 +678,7 @@ typedef struct ExprEvalStep
|
|||||||
/* for EEOP_JSON_CONSTRUCTOR */
|
/* for EEOP_JSON_CONSTRUCTOR */
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
JsonConstructorExpr *constructor;
|
struct JsonConstructorExprState *jcstate;
|
||||||
Datum *arg_values;
|
|
||||||
bool *arg_nulls;
|
|
||||||
Oid *arg_types;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
int category;
|
|
||||||
Oid outfuncid;
|
|
||||||
} *arg_type_cache; /* cache for datum_to_json[b]() */
|
|
||||||
int nargs;
|
|
||||||
} json_constructor;
|
} json_constructor;
|
||||||
|
|
||||||
/* for EEOP_IS_JSON */
|
/* for EEOP_IS_JSON */
|
||||||
@ -697,45 +690,7 @@ typedef struct ExprEvalStep
|
|||||||
/* for EEOP_JSONEXPR */
|
/* for EEOP_JSONEXPR */
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
JsonExpr *jsexpr; /* original expression node */
|
struct JsonExprState *jsestate;
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
FmgrInfo func; /* typinput function for output type */
|
|
||||||
Oid typioparam;
|
|
||||||
} input; /* I/O info for output type */
|
|
||||||
|
|
||||||
NullableDatum
|
|
||||||
*formatted_expr, /* formatted context item value */
|
|
||||||
*res_expr, /* result item */
|
|
||||||
*coercion_expr, /* input for JSON item coercion */
|
|
||||||
*pathspec; /* path specification value */
|
|
||||||
|
|
||||||
ExprState *result_expr; /* coerced to output type */
|
|
||||||
ExprState *default_on_empty; /* ON EMPTY DEFAULT expression */
|
|
||||||
ExprState *default_on_error; /* ON ERROR DEFAULT expression */
|
|
||||||
List *args; /* passing arguments */
|
|
||||||
|
|
||||||
void *cache; /* cache for json_populate_type() */
|
|
||||||
|
|
||||||
struct JsonCoercionsState
|
|
||||||
{
|
|
||||||
struct JsonCoercionState
|
|
||||||
{
|
|
||||||
JsonCoercion *coercion; /* coercion expression */
|
|
||||||
ExprState *estate; /* coercion expression state */
|
|
||||||
} null,
|
|
||||||
string,
|
|
||||||
numeric ,
|
|
||||||
boolean,
|
|
||||||
date,
|
|
||||||
time,
|
|
||||||
timetz,
|
|
||||||
timestamp,
|
|
||||||
timestamptz,
|
|
||||||
composite;
|
|
||||||
} coercions; /* states for coercion from SQL/JSON item
|
|
||||||
* types directly to the output type */
|
|
||||||
} jsonexpr;
|
} jsonexpr;
|
||||||
|
|
||||||
} d;
|
} d;
|
||||||
@ -782,6 +737,64 @@ typedef struct SubscriptExecSteps
|
|||||||
ExecEvalSubroutine sbs_fetch_old; /* fetch old value for assignment */
|
ExecEvalSubroutine sbs_fetch_old; /* fetch old value for assignment */
|
||||||
} SubscriptExecSteps;
|
} SubscriptExecSteps;
|
||||||
|
|
||||||
|
/* EEOP_JSON_CONSTRUCTOR state, too big to inline */
|
||||||
|
typedef struct JsonConstructorExprState
|
||||||
|
{
|
||||||
|
JsonConstructorExpr *constructor;
|
||||||
|
Datum *arg_values;
|
||||||
|
bool *arg_nulls;
|
||||||
|
Oid *arg_types;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int category;
|
||||||
|
Oid outfuncid;
|
||||||
|
} *arg_type_cache; /* cache for datum_to_json[b]() */
|
||||||
|
int nargs;
|
||||||
|
} JsonConstructorExprState;
|
||||||
|
|
||||||
|
/* EEOP_JSONEXPR state, too big to inline */
|
||||||
|
typedef struct JsonExprState
|
||||||
|
{
|
||||||
|
JsonExpr *jsexpr; /* original expression node */
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
FmgrInfo func; /* typinput function for output type */
|
||||||
|
Oid typioparam;
|
||||||
|
} input; /* I/O info for output type */
|
||||||
|
|
||||||
|
NullableDatum
|
||||||
|
*formatted_expr, /* formatted context item value */
|
||||||
|
*res_expr, /* result item */
|
||||||
|
*coercion_expr, /* input for JSON item coercion */
|
||||||
|
*pathspec; /* path specification value */
|
||||||
|
|
||||||
|
ExprState *result_expr; /* coerced to output type */
|
||||||
|
ExprState *default_on_empty; /* ON EMPTY DEFAULT expression */
|
||||||
|
ExprState *default_on_error; /* ON ERROR DEFAULT expression */
|
||||||
|
List *args; /* passing arguments */
|
||||||
|
|
||||||
|
void *cache; /* cache for json_populate_type() */
|
||||||
|
|
||||||
|
struct JsonCoercionsState
|
||||||
|
{
|
||||||
|
struct JsonCoercionState
|
||||||
|
{
|
||||||
|
JsonCoercion *coercion; /* coercion expression */
|
||||||
|
ExprState *estate; /* coercion expression state */
|
||||||
|
} null,
|
||||||
|
string,
|
||||||
|
numeric ,
|
||||||
|
boolean,
|
||||||
|
date,
|
||||||
|
time,
|
||||||
|
timetz,
|
||||||
|
timestamp,
|
||||||
|
timestamptz,
|
||||||
|
composite;
|
||||||
|
} coercions; /* states for coercion from SQL/JSON item
|
||||||
|
* types directly to the output type */
|
||||||
|
} JsonExprState;
|
||||||
|
|
||||||
/* functions in execExpr.c */
|
/* functions in execExpr.c */
|
||||||
extern void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s);
|
extern void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s);
|
||||||
|
@ -1237,10 +1237,12 @@ JsonBehaviorType
|
|||||||
JsonCoercion
|
JsonCoercion
|
||||||
JsonCommon
|
JsonCommon
|
||||||
JsonConstructorExpr
|
JsonConstructorExpr
|
||||||
|
JsonConstructorExprState
|
||||||
JsonConstructorType
|
JsonConstructorType
|
||||||
JsonEncoding
|
JsonEncoding
|
||||||
JsonExpr
|
JsonExpr
|
||||||
JsonExprOp
|
JsonExprOp
|
||||||
|
JsonExprState
|
||||||
JsonFormat
|
JsonFormat
|
||||||
JsonFormatType
|
JsonFormatType
|
||||||
JsonFunc
|
JsonFunc
|
||||||
|
Loading…
Reference in New Issue
Block a user