mirror of
https://github.com/postgres/postgres.git
synced 2025-07-07 00:36:50 +03: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:
@ -4510,39 +4510,40 @@ ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
|
||||
ExprContext *econtext)
|
||||
{
|
||||
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 isnull = false;
|
||||
|
||||
if (ctor->type == JSCTOR_JSON_ARRAY)
|
||||
res = (is_jsonb ?
|
||||
jsonb_build_array_worker :
|
||||
json_build_array_worker) (op->d.json_constructor.nargs,
|
||||
op->d.json_constructor.arg_values,
|
||||
op->d.json_constructor.arg_nulls,
|
||||
op->d.json_constructor.arg_types,
|
||||
op->d.json_constructor.constructor->absent_on_null);
|
||||
json_build_array_worker) (jcstate->nargs,
|
||||
jcstate->arg_values,
|
||||
jcstate->arg_nulls,
|
||||
jcstate->arg_types,
|
||||
ctor->absent_on_null);
|
||||
else if (ctor->type == JSCTOR_JSON_OBJECT)
|
||||
res = (is_jsonb ?
|
||||
jsonb_build_object_worker :
|
||||
json_build_object_worker) (op->d.json_constructor.nargs,
|
||||
op->d.json_constructor.arg_values,
|
||||
op->d.json_constructor.arg_nulls,
|
||||
op->d.json_constructor.arg_types,
|
||||
op->d.json_constructor.constructor->absent_on_null,
|
||||
op->d.json_constructor.constructor->unique);
|
||||
json_build_object_worker) (jcstate->nargs,
|
||||
jcstate->arg_values,
|
||||
jcstate->arg_nulls,
|
||||
jcstate->arg_types,
|
||||
ctor->absent_on_null,
|
||||
ctor->unique);
|
||||
else if (ctor->type == JSCTOR_JSON_SCALAR)
|
||||
{
|
||||
if (op->d.json_constructor.arg_nulls[0])
|
||||
if (jcstate->arg_nulls[0])
|
||||
{
|
||||
res = (Datum) 0;
|
||||
isnull = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Datum value = op->d.json_constructor.arg_values[0];
|
||||
int category = op->d.json_constructor.arg_type_cache[0].category;
|
||||
Oid outfuncid = op->d.json_constructor.arg_type_cache[0].outfuncid;
|
||||
Datum value = jcstate->arg_values[0];
|
||||
int category = jcstate->arg_type_cache[0].category;
|
||||
Oid outfuncid = jcstate->arg_type_cache[0].outfuncid;
|
||||
|
||||
if (is_jsonb)
|
||||
res = to_jsonb_worker(value, category, outfuncid);
|
||||
@ -4552,14 +4553,14 @@ ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
|
||||
}
|
||||
else if (ctor->type == JSCTOR_JSON_PARSE)
|
||||
{
|
||||
if (op->d.json_constructor.arg_nulls[0])
|
||||
if (jcstate->arg_nulls[0])
|
||||
{
|
||||
res = (Datum) 0;
|
||||
isnull = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Datum value = op->d.json_constructor.arg_values[0];
|
||||
Datum value = jcstate->arg_values[0];
|
||||
text *js = DatumGetTextP(value);
|
||||
|
||||
if (is_jsonb)
|
||||
@ -4627,14 +4628,17 @@ ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext,
|
||||
Datum res, bool *isNull, void *p, bool *error)
|
||||
{
|
||||
ExprState *estate = p;
|
||||
JsonExprState *jsestate;
|
||||
|
||||
if (estate) /* coerce using specified expression */
|
||||
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;
|
||||
JsonExpr *jexpr = op->d.jsonexpr.jsexpr;
|
||||
JsonCoercion *coercion = jsestate->jsexpr->result_coercion;
|
||||
JsonExpr *jexpr = jsestate->jsexpr;
|
||||
Jsonb *jb = *isNull ? NULL : DatumGetJsonbP(res);
|
||||
|
||||
if ((coercion && coercion->via_io) ||
|
||||
@ -4644,25 +4648,25 @@ ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext,
|
||||
/* strip quotes and call typinput function */
|
||||
char *str = *isNull ? NULL : JsonbUnquote(jb);
|
||||
|
||||
return InputFunctionCall(&op->d.jsonexpr.input.func, str,
|
||||
op->d.jsonexpr.input.typioparam,
|
||||
return InputFunctionCall(&jsestate->input.func, str,
|
||||
jsestate->input.typioparam,
|
||||
jexpr->returning->typmod);
|
||||
}
|
||||
else if (coercion && coercion->via_populate)
|
||||
return json_populate_type(res, JSONBOID,
|
||||
jexpr->returning->typid,
|
||||
jexpr->returning->typmod,
|
||||
&op->d.jsonexpr.cache,
|
||||
&jsestate->cache,
|
||||
econtext->ecxt_per_query_memory,
|
||||
isNull);
|
||||
}
|
||||
|
||||
if (op->d.jsonexpr.result_expr)
|
||||
if (jsestate->result_expr)
|
||||
{
|
||||
op->d.jsonexpr.res_expr->value = res;
|
||||
op->d.jsonexpr.res_expr->isnull = *isNull;
|
||||
jsestate->res_expr->value = res;
|
||||
jsestate->res_expr->isnull = *isNull;
|
||||
|
||||
res = ExecEvalExpr(op->d.jsonexpr.result_expr, econtext, isNull);
|
||||
res = ExecEvalExpr(jsestate->result_expr, econtext, isNull);
|
||||
}
|
||||
|
||||
return res;
|
||||
@ -4895,7 +4899,8 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
|
||||
{
|
||||
ExecEvalJsonExprContext *cxt = pcxt;
|
||||
JsonPath *path = cxt->path;
|
||||
JsonExpr *jexpr = op->d.jsonexpr.jsexpr;
|
||||
JsonExprState *jsestate = op->d.jsonexpr.jsestate;
|
||||
JsonExpr *jexpr = jsestate->jsexpr;
|
||||
ExprState *estate = NULL;
|
||||
bool empty = false;
|
||||
Datum res = (Datum) 0;
|
||||
@ -4904,7 +4909,7 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
|
||||
{
|
||||
case JSON_QUERY_OP:
|
||||
res = JsonPathQuery(item, path, jexpr->wrapper, &empty, error,
|
||||
op->d.jsonexpr.args);
|
||||
jsestate->args);
|
||||
if (error && *error)
|
||||
{
|
||||
*resnull = true;
|
||||
@ -4917,7 +4922,7 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
|
||||
{
|
||||
struct JsonCoercionState *jcstate;
|
||||
JsonbValue *jbv = JsonPathValue(item, path, &empty, error,
|
||||
op->d.jsonexpr.args);
|
||||
jsestate->args);
|
||||
|
||||
if (error && *error)
|
||||
return (Datum) 0;
|
||||
@ -4940,8 +4945,8 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
|
||||
|
||||
/* Use coercion from SQL/JSON item type to the output type */
|
||||
res = ExecPrepareJsonItemCoercion(jbv,
|
||||
op->d.jsonexpr.jsexpr->returning,
|
||||
&op->d.jsonexpr.coercions,
|
||||
jsestate->jsexpr->returning,
|
||||
&jsestate->coercions,
|
||||
&jcstate);
|
||||
|
||||
if (jcstate->coercion &&
|
||||
@ -4973,27 +4978,27 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
|
||||
|
||||
/* coerce using specific expression */
|
||||
estate = jcstate->estate;
|
||||
op->d.jsonexpr.coercion_expr->value = res;
|
||||
op->d.jsonexpr.coercion_expr->isnull = *resnull;
|
||||
jsestate->coercion_expr->value = res;
|
||||
jsestate->coercion_expr->isnull = *resnull;
|
||||
break;
|
||||
}
|
||||
|
||||
case JSON_EXISTS_OP:
|
||||
{
|
||||
bool exists = JsonPathExists(item, path,
|
||||
op->d.jsonexpr.args,
|
||||
jsestate->args,
|
||||
error);
|
||||
|
||||
*resnull = error && *error;
|
||||
res = BoolGetDatum(exists);
|
||||
|
||||
if (!op->d.jsonexpr.result_expr)
|
||||
if (!jsestate->result_expr)
|
||||
return res;
|
||||
|
||||
/* coerce using result expression */
|
||||
estate = op->d.jsonexpr.result_expr;
|
||||
op->d.jsonexpr.res_expr->value = res;
|
||||
op->d.jsonexpr.res_expr->isnull = *resnull;
|
||||
estate = jsestate->result_expr;
|
||||
jsestate->res_expr->value = res;
|
||||
jsestate->res_expr->isnull = *resnull;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -5029,11 +5034,11 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
|
||||
* Execute DEFAULT expression as a coercion expression, because
|
||||
* its result is already coerced to the target type.
|
||||
*/
|
||||
estate = op->d.jsonexpr.default_on_empty;
|
||||
estate = jsestate->default_on_empty;
|
||||
else
|
||||
/* Execute ON EMPTY behavior */
|
||||
res = ExecEvalJsonBehavior(econtext, jexpr->on_empty,
|
||||
op->d.jsonexpr.default_on_empty,
|
||||
jsestate->default_on_empty,
|
||||
resnull);
|
||||
}
|
||||
|
||||
@ -5066,7 +5071,8 @@ void
|
||||
ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
|
||||
{
|
||||
ExecEvalJsonExprContext cxt;
|
||||
JsonExpr *jexpr = op->d.jsonexpr.jsexpr;
|
||||
JsonExprState *jsestate = op->d.jsonexpr.jsestate;
|
||||
JsonExpr *jexpr = jsestate->jsexpr;
|
||||
Datum item;
|
||||
Datum res = (Datum) 0;
|
||||
JsonPath *path;
|
||||
@ -5078,7 +5084,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
|
||||
*op->resnull = true; /* until we get a result */
|
||||
*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 */
|
||||
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull,
|
||||
@ -5088,11 +5094,11 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
|
||||
return;
|
||||
}
|
||||
|
||||
item = op->d.jsonexpr.formatted_expr->value;
|
||||
path = DatumGetJsonPathP(op->d.jsonexpr.pathspec->value);
|
||||
item = jsestate->formatted_expr->value;
|
||||
path = DatumGetJsonPathP(jsestate->pathspec->value);
|
||||
|
||||
/* reset JSON path variable contexts */
|
||||
foreach(lc, op->d.jsonexpr.args)
|
||||
foreach(lc, jsestate->args)
|
||||
{
|
||||
JsonPathVariableEvalContext *var = lfirst(lc);
|
||||
|
||||
@ -5100,7 +5106,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
|
||||
var->evaluated = false;
|
||||
}
|
||||
|
||||
needSubtrans = ExecEvalJsonNeedsSubTransaction(jexpr, &op->d.jsonexpr.coercions);
|
||||
needSubtrans = ExecEvalJsonNeedsSubTransaction(jexpr, &jsestate->coercions);
|
||||
|
||||
cxt.path = path;
|
||||
cxt.error = throwErrors ? NULL : &error;
|
||||
@ -5115,7 +5121,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
|
||||
{
|
||||
/* Execute ON ERROR behavior */
|
||||
res = ExecEvalJsonBehavior(econtext, jexpr->on_error,
|
||||
op->d.jsonexpr.default_on_error,
|
||||
jsestate->default_on_error,
|
||||
op->resnull);
|
||||
|
||||
/* result is already coerced in DEFAULT behavior case */
|
||||
|
Reference in New Issue
Block a user