mirror of
https://github.com/postgres/postgres.git
synced 2025-11-22 12:22:45 +03:00
Evaluate arguments of correlated SubPlans in the referencing ExprState
Until now we generated an ExprState for each parameter to a SubPlan and evaluated them one-by-one ExecScanSubPlan. That's sub-optimal as creating lots of small ExprStates a) makes JIT compilation more expensive b) wastes memory c) is a bit slower to execute This commit arranges to evaluate parameters to a SubPlan as part of the ExprState referencing a SubPlan, using the new EEOP_PARAM_SET expression step. We emit one EEOP_PARAM_SET for each argument to a subplan, just before the EEOP_SUBPLAN step. It likely is worth using EEOP_PARAM_SET in other places as well, e.g. for SubPlan outputs, nestloop parameters and - more ambitiously - to get rid of ExprContext->domainValue/caseValue/ecxt_agg*. But that's for later. Author: Andres Freund <andres@anarazel.de> Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Reviewed-by: Alena Rybakina <lena.ribackina@yandex.ru> Discussion: https://postgr.es/m/20230225214401.346ancgjqc3zmvek@awork3.anarazel.de
This commit is contained in:
@@ -69,6 +69,9 @@ static void ExecInitExprRec(Expr *node, ExprState *state,
|
||||
static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args,
|
||||
Oid funcid, Oid inputcollid,
|
||||
ExprState *state);
|
||||
static void ExecInitSubPlanExpr(SubPlan *subplan,
|
||||
ExprState *state,
|
||||
Datum *resv, bool *resnull);
|
||||
static void ExecCreateExprSetupSteps(ExprState *state, Node *node);
|
||||
static void ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info);
|
||||
static bool expr_setup_walker(Node *node, ExprSetupInfo *info);
|
||||
@@ -1406,7 +1409,6 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
||||
case T_SubPlan:
|
||||
{
|
||||
SubPlan *subplan = (SubPlan *) node;
|
||||
SubPlanState *sstate;
|
||||
|
||||
/*
|
||||
* Real execution of a MULTIEXPR SubPlan has already been
|
||||
@@ -1423,19 +1425,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!state->parent)
|
||||
elog(ERROR, "SubPlan found with no parent plan");
|
||||
|
||||
sstate = ExecInitSubPlan(subplan, state->parent);
|
||||
|
||||
/* add SubPlanState nodes to state->parent->subPlan */
|
||||
state->parent->subPlan = lappend(state->parent->subPlan,
|
||||
sstate);
|
||||
|
||||
scratch.opcode = EEOP_SUBPLAN;
|
||||
scratch.d.subplan.sstate = sstate;
|
||||
|
||||
ExprEvalPushStep(state, &scratch);
|
||||
ExecInitSubPlanExpr(subplan, state, resv, resnull);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2715,6 +2705,70 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Append the steps necessary for the evaluation of a SubPlan node to
|
||||
* ExprState->steps.
|
||||
*
|
||||
* subplan - SubPlan expression to evaluate
|
||||
* state - ExprState to whose ->steps to append the necessary operations
|
||||
* resv / resnull - where to store the result of the node into
|
||||
*/
|
||||
static void
|
||||
ExecInitSubPlanExpr(SubPlan *subplan,
|
||||
ExprState *state,
|
||||
Datum *resv, bool *resnull)
|
||||
{
|
||||
ExprEvalStep scratch = {0};
|
||||
SubPlanState *sstate;
|
||||
ListCell *pvar;
|
||||
ListCell *l;
|
||||
|
||||
if (!state->parent)
|
||||
elog(ERROR, "SubPlan found with no parent plan");
|
||||
|
||||
/*
|
||||
* Generate steps to evaluate input arguments for the subplan.
|
||||
*
|
||||
* We evaluate the argument expressions into ExprState's resvalue/resnull,
|
||||
* and then use PARAM_SET to update the parameter. We do that, instead of
|
||||
* evaluating directly into the param, to avoid depending on the pointer
|
||||
* value remaining stable / being included in the generated expression. No
|
||||
* danger of conflicts with other uses of resvalue/resnull as storing and
|
||||
* using the value always is in subsequent steps.
|
||||
*
|
||||
* Any calculation we have to do can be done in the parent econtext, since
|
||||
* the Param values don't need to have per-query lifetime.
|
||||
*/
|
||||
Assert(list_length(subplan->parParam) == list_length(subplan->args));
|
||||
forboth(l, subplan->parParam, pvar, subplan->args)
|
||||
{
|
||||
int paramid = lfirst_int(l);
|
||||
Expr *arg = (Expr *) lfirst(pvar);
|
||||
|
||||
ExecInitExprRec(arg, state,
|
||||
&state->resvalue, &state->resnull);
|
||||
|
||||
scratch.opcode = EEOP_PARAM_SET;
|
||||
scratch.d.param.paramid = paramid;
|
||||
/* paramtype's not actually used, but we might as well fill it */
|
||||
scratch.d.param.paramtype = exprType((Node *) arg);
|
||||
ExprEvalPushStep(state, &scratch);
|
||||
}
|
||||
|
||||
sstate = ExecInitSubPlan(subplan, state->parent);
|
||||
|
||||
/* add SubPlanState nodes to state->parent->subPlan */
|
||||
state->parent->subPlan = lappend(state->parent->subPlan,
|
||||
sstate);
|
||||
|
||||
scratch.opcode = EEOP_SUBPLAN;
|
||||
scratch.resvalue = resv;
|
||||
scratch.resnull = resnull;
|
||||
scratch.d.subplan.sstate = sstate;
|
||||
|
||||
ExprEvalPushStep(state, &scratch);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add expression steps performing setup that's needed before any of the
|
||||
* main execution of the expression.
|
||||
@@ -2789,29 +2843,12 @@ ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info)
|
||||
foreach(lc, info->multiexpr_subplans)
|
||||
{
|
||||
SubPlan *subplan = (SubPlan *) lfirst(lc);
|
||||
SubPlanState *sstate;
|
||||
|
||||
Assert(subplan->subLinkType == MULTIEXPR_SUBLINK);
|
||||
|
||||
/* This should match what ExecInitExprRec does for other SubPlans: */
|
||||
|
||||
if (!state->parent)
|
||||
elog(ERROR, "SubPlan found with no parent plan");
|
||||
|
||||
sstate = ExecInitSubPlan(subplan, state->parent);
|
||||
|
||||
/* add SubPlanState nodes to state->parent->subPlan */
|
||||
state->parent->subPlan = lappend(state->parent->subPlan,
|
||||
sstate);
|
||||
|
||||
scratch.opcode = EEOP_SUBPLAN;
|
||||
scratch.d.subplan.sstate = sstate;
|
||||
|
||||
/* The result can be ignored, but we better put it somewhere */
|
||||
scratch.resvalue = &state->resvalue;
|
||||
scratch.resnull = &state->resnull;
|
||||
|
||||
ExprEvalPushStep(state, &scratch);
|
||||
ExecInitSubPlanExpr(subplan, state,
|
||||
&state->resvalue, &state->resnull);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user