diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 2831e7978b..1f65daf203 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -2470,32 +2470,38 @@ ExecInitExprRec(Expr *node, ExprState *state, } else { + JsonConstructorExprState *jcstate; + + jcstate = palloc0(sizeof(JsonConstructorExprState)); + scratch.opcode = EEOP_JSON_CONSTRUCTOR; - scratch.d.json_constructor.constructor = ctor; - scratch.d.json_constructor.arg_values = palloc(sizeof(Datum) * nargs); - scratch.d.json_constructor.arg_nulls = palloc(sizeof(bool) * nargs); - scratch.d.json_constructor.arg_types = palloc(sizeof(Oid) * nargs); - scratch.d.json_constructor.nargs = nargs; + scratch.d.json_constructor.jcstate = jcstate; + + jcstate->constructor = ctor; + jcstate->arg_values = palloc(sizeof(Datum) * nargs); + jcstate->arg_nulls = palloc(sizeof(bool) * nargs); + jcstate->arg_types = palloc(sizeof(Oid) * nargs); + jcstate->nargs = nargs; foreach(lc, args) { 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)) { /* Don't evaluate const arguments every round */ Const *con = (Const *) arg; - scratch.d.json_constructor.arg_values[argno] = con->constvalue; - scratch.d.json_constructor.arg_nulls[argno] = con->constisnull; + jcstate->arg_values[argno] = con->constvalue; + jcstate->arg_nulls[argno] = con->constisnull; } else { ExecInitExprRec(arg, state, - &scratch.d.json_constructor.arg_values[argno], - &scratch.d.json_constructor.arg_nulls[argno]); + &jcstate->arg_values[argno], + &jcstate->arg_nulls[argno]); } argno++; } @@ -2506,14 +2512,14 @@ ExecInitExprRec(Expr *node, ExprState *state, bool is_jsonb = ctor->returning->format->format_type == JS_FORMAT_JSONB; - scratch.d.json_constructor.arg_type_cache = - palloc(sizeof(*scratch.d.json_constructor.arg_type_cache) * nargs); + jcstate->arg_type_cache = + palloc(sizeof(*jcstate->arg_type_cache) * nargs); for (int i = 0; i < nargs; i++) { int category; Oid outfuncid; - Oid typid = scratch.d.json_constructor.arg_types[i]; + Oid typid = jcstate->arg_types[i]; if (is_jsonb) { @@ -2532,8 +2538,8 @@ ExecInitExprRec(Expr *node, ExprState *state, category = (int) jscat; } - scratch.d.json_constructor.arg_type_cache[i].outfuncid = outfuncid; - scratch.d.json_constructor.arg_type_cache[i].category = category; + jcstate->arg_type_cache[i].outfuncid = outfuncid; + jcstate->arg_type_cache[i].category = category; } } @@ -2572,41 +2578,44 @@ ExecInitExprRec(Expr *node, ExprState *state, case T_JsonExpr: { JsonExpr *jexpr = castNode(JsonExpr, node); + JsonExprState *jsestate = palloc0(sizeof(JsonExprState)); ListCell *argexprlc; ListCell *argnamelc; scratch.opcode = EEOP_JSONEXPR; - scratch.d.jsonexpr.jsexpr = jexpr; + scratch.d.jsonexpr.jsestate = jsestate; - scratch.d.jsonexpr.formatted_expr = - palloc(sizeof(*scratch.d.jsonexpr.formatted_expr)); + jsestate->jsexpr = jexpr; + + jsestate->formatted_expr = + palloc(sizeof(*jsestate->formatted_expr)); ExecInitExprRec((Expr *) jexpr->formatted_expr, state, - &scratch.d.jsonexpr.formatted_expr->value, - &scratch.d.jsonexpr.formatted_expr->isnull); + &jsestate->formatted_expr->value, + &jsestate->formatted_expr->isnull); - scratch.d.jsonexpr.pathspec = - palloc(sizeof(*scratch.d.jsonexpr.pathspec)); + jsestate->pathspec = + palloc(sizeof(*jsestate->pathspec)); ExecInitExprRec((Expr *) jexpr->path_spec, state, - &scratch.d.jsonexpr.pathspec->value, - &scratch.d.jsonexpr.pathspec->isnull); + &jsestate->pathspec->value, + &jsestate->pathspec->isnull); - scratch.d.jsonexpr.res_expr = - palloc(sizeof(*scratch.d.jsonexpr.res_expr)); + jsestate->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, state->parent, - &scratch.d.jsonexpr.res_expr->value, - &scratch.d.jsonexpr.res_expr->isnull) + &jsestate->res_expr->value, + &jsestate->res_expr->isnull) : 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, state->parent); - scratch.d.jsonexpr.default_on_error = + jsestate->default_on_error = ExecInitExpr((Expr *) jexpr->on_error->default_expr, state->parent); @@ -2617,11 +2626,11 @@ ExecInitExprRec(Expr *node, ExprState *state, /* lookup the result type's input function */ getTypeInputInfo(jexpr->returning->typid, &typinput, - &scratch.d.jsonexpr.input.typioparam); - fmgr_info(typinput, &scratch.d.jsonexpr.input.func); + &jsestate->input.typioparam); + fmgr_info(typinput, &jsestate->input.func); } - scratch.d.jsonexpr.args = NIL; + jsestate->args = NIL; forboth(argexprlc, jexpr->passing_values, argnamelc, jexpr->passing_names) @@ -2640,11 +2649,11 @@ ExecInitExprRec(Expr *node, ExprState *state, var->value = (Datum) 0; var->isnull = true; - scratch.d.jsonexpr.args = - lappend(scratch.d.jsonexpr.args, var); + jsestate->args = + lappend(jsestate->args, var); } - scratch.d.jsonexpr.cache = NULL; + jsestate->cache = NULL; if (jexpr->coercions) { @@ -2653,13 +2662,13 @@ ExecInitExprRec(Expr *node, ExprState *state, Datum *caseval; bool *casenull; - scratch.d.jsonexpr.coercion_expr = - palloc(sizeof(*scratch.d.jsonexpr.coercion_expr)); + jsestate->coercion_expr = + palloc(sizeof(*jsestate->coercion_expr)); - caseval = &scratch.d.jsonexpr.coercion_expr->value; - casenull = &scratch.d.jsonexpr.coercion_expr->isnull; + caseval = &jsestate->coercion_expr->value; + casenull = &jsestate->coercion_expr->isnull; - for (cstate = &scratch.d.jsonexpr.coercions.null, + for (cstate = &jsestate->coercions.null, coercion = &jexpr->coercions->null; coercion <= &jexpr->coercions->composite; coercion++, cstate++) diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index eaec697bb3..80c5e04dd5 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -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 */ diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h index e34db8c93c..fa2d9be4c9 100644 --- a/src/include/executor/execExpr.h +++ b/src/include/executor/execExpr.h @@ -22,6 +22,8 @@ struct ExprEvalStep; struct SubscriptingRefState; struct ScalarArrayOpExprHashTable; struct JsonbValue; +struct JsonExprState; +struct JsonConstructorExprState; /* Bits in ExprState->flags (see also execnodes.h for public flag bits): */ /* expression's interpreter has been initialized */ @@ -676,16 +678,7 @@ typedef struct ExprEvalStep /* for EEOP_JSON_CONSTRUCTOR */ struct { - 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; + struct JsonConstructorExprState *jcstate; } json_constructor; /* for EEOP_IS_JSON */ @@ -697,45 +690,7 @@ typedef struct ExprEvalStep /* for EEOP_JSONEXPR */ struct { - 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 */ + struct JsonExprState *jsestate; } jsonexpr; } d; @@ -782,6 +737,64 @@ typedef struct SubscriptExecSteps ExecEvalSubroutine sbs_fetch_old; /* fetch old value for assignment */ } 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 */ extern void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s); diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 4fb746930a..c7f550e822 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -1237,10 +1237,12 @@ JsonBehaviorType JsonCoercion JsonCommon JsonConstructorExpr +JsonConstructorExprState JsonConstructorType JsonEncoding JsonExpr JsonExprOp +JsonExprState JsonFormat JsonFormatType JsonFunc