diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execExprInterp.c | 27 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 40 | ||||
-rw-r--r-- | src/backend/executor/execParallel.c | 24 | ||||
-rw-r--r-- | src/backend/executor/nodeSubplan.c | 42 |
4 files changed, 97 insertions, 36 deletions
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 9d6e25aae5f..f597363eb10 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -2253,33 +2253,6 @@ ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext) } /* - * ExecEvalParamExecParams - * - * Execute the subplan stored in PARAM_EXEC initplans params, if not executed - * till now. - */ -void -ExecEvalParamExecParams(Bitmapset *params, EState *estate) -{ - ParamExecData *prm; - int paramid; - - paramid = -1; - while ((paramid = bms_next_member(params, paramid)) >= 0) - { - prm = &(estate->es_param_exec_vals[paramid]); - - if (prm->execPlan != NULL) - { - /* Parameter not evaluated yet, so go do it */ - ExecSetParamPlan(prm->execPlan, GetPerTupleExprContext(estate)); - /* ExecSetParamPlan should have processed this param... */ - Assert(prm->execPlan == NULL); - } - } -} - -/* * Evaluate a PARAM_EXTERN parameter. * * PARAM_EXTERN parameters must be sought in ecxt_param_list_info. diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index c583e020a0e..85d980356b7 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -46,6 +46,7 @@ #include "commands/matview.h" #include "commands/trigger.h" #include "executor/execdebug.h" +#include "executor/nodeSubplan.h" #include "foreign/fdwapi.h" #include "mb/pg_wchar.h" #include "miscadmin.h" @@ -1727,8 +1728,8 @@ ExecutePlan(EState *estate, if (TupIsNull(slot)) { /* - * If we know we won't need to back up, we can release - * resources at this point. + * If we know we won't need to back up, we can release resources + * at this point. */ if (!(estate->es_top_eflags & EXEC_FLAG_BACKWARD)) (void) ExecShutdownNode(planstate); @@ -1778,8 +1779,8 @@ ExecutePlan(EState *estate, if (numberTuples && numberTuples == current_tuple_count) { /* - * If we know we won't need to back up, we can release - * resources at this point. + * If we know we won't need to back up, we can release resources + * at this point. */ if (!(estate->es_top_eflags & EXEC_FLAG_BACKWARD)) (void) ExecShutdownNode(planstate); @@ -3078,6 +3079,14 @@ EvalPlanQualBegin(EPQState *epqstate, EState *parentestate) { int i; + /* + * Force evaluation of any InitPlan outputs that could be needed + * by the subplan, just in case they got reset since + * EvalPlanQualStart (see comments therein). + */ + ExecSetParamPlanMulti(planstate->plan->extParam, + GetPerTupleExprContext(parentestate)); + i = list_length(parentestate->es_plannedstmt->paramExecTypes); while (--i >= 0) @@ -3170,9 +3179,32 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree) { int i; + /* + * Force evaluation of any InitPlan outputs that could be needed by + * the subplan. (With more complexity, maybe we could postpone this + * till the subplan actually demands them, but it doesn't seem worth + * the trouble; this is a corner case already, since usually the + * InitPlans would have been evaluated before reaching EvalPlanQual.) + * + * This will not touch output params of InitPlans that occur somewhere + * within the subplan tree, only those that are attached to the + * ModifyTable node or above it and are referenced within the subplan. + * That's OK though, because the planner would only attach such + * InitPlans to a lower-level SubqueryScan node, and EPQ execution + * will not descend into a SubqueryScan. + * + * The EState's per-output-tuple econtext is sufficiently short-lived + * for this, since it should get reset before there is any chance of + * doing EvalPlanQual again. + */ + ExecSetParamPlanMulti(planTree->extParam, + GetPerTupleExprContext(parentestate)); + + /* now make the internal param workspace ... */ i = list_length(parentestate->es_plannedstmt->paramExecTypes); estate->es_param_exec_vals = (ParamExecData *) palloc0(i * sizeof(ParamExecData)); + /* ... and copy down all values, whether really needed or not */ while (--i >= 0) { /* copy value if any, but not execPlan link */ diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index ee0f07a81e9..c93084e4d2a 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -23,7 +23,6 @@ #include "postgres.h" -#include "executor/execExpr.h" #include "executor/execParallel.h" #include "executor/executor.h" #include "executor/nodeAppend.h" @@ -36,6 +35,7 @@ #include "executor/nodeIndexonlyscan.h" #include "executor/nodeSeqscan.h" #include "executor/nodeSort.h" +#include "executor/nodeSubplan.h" #include "executor/tqueue.h" #include "nodes/nodeFuncs.h" #include "optimizer/planmain.h" @@ -581,8 +581,18 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate, char *query_string; int query_len; - /* Force parameters we're going to pass to workers to be evaluated. */ - ExecEvalParamExecParams(sendParams, estate); + /* + * Force any initplan outputs that we're going to pass to workers to be + * evaluated, if they weren't already. + * + * For simplicity, we use the EState's per-output-tuple ExprContext here. + * That risks intra-query memory leakage, since we might pass through here + * many times before that ExprContext gets reset; but ExecSetParamPlan + * doesn't normally leak any memory in the context (see its comments), so + * it doesn't seem worth complicating this function's API to pass it a + * shorter-lived ExprContext. This might need to change someday. + */ + ExecSetParamPlanMulti(sendParams, GetPerTupleExprContext(estate)); /* Allocate object for return value. */ pei = palloc0(sizeof(ParallelExecutorInfo)); @@ -831,8 +841,12 @@ ExecParallelReinitialize(PlanState *planstate, /* Old workers must already be shut down */ Assert(pei->finished); - /* Force parameters we're going to pass to workers to be evaluated. */ - ExecEvalParamExecParams(sendParams, estate); + /* + * Force any initplan outputs that we're going to pass to workers to be + * evaluated, if they weren't already (see comments in + * ExecInitParallelPlan). + */ + ExecSetParamPlanMulti(sendParams, GetPerTupleExprContext(estate)); ReinitializeParallelDSM(pei->pcxt); pei->tqueue = ExecParallelSetupTupleQueues(pei->pcxt, true); diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index 6b370750c5b..63de981034d 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -1009,6 +1009,17 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent) * of initplans: we don't run the subplan until/unless we need its output. * Note that this routine MUST clear the execPlan fields of the plan's * output parameters after evaluating them! + * + * The results of this function are stored in the EState associated with the + * ExprContext (particularly, its ecxt_param_exec_vals); any pass-by-ref + * result Datums are allocated in the EState's per-query memory. The passed + * econtext can be any ExprContext belonging to that EState; which one is + * important only to the extent that the ExprContext's per-tuple memory + * context is used to evaluate any parameters passed down to the subplan. + * (Thus in principle, the shorter-lived the ExprContext the better, since + * that data isn't needed after we return. In practice, because initplan + * parameters are never more complex than Vars, Aggrefs, etc, evaluating them + * currently never leaks any memory anyway.) * ---------------------------------------------------------------- */ void @@ -1196,6 +1207,37 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext) } /* + * ExecSetParamPlanMulti + * + * Apply ExecSetParamPlan to evaluate any not-yet-evaluated initplan output + * parameters whose ParamIDs are listed in "params". Any listed params that + * are not initplan outputs are ignored. + * + * As with ExecSetParamPlan, any ExprContext belonging to the current EState + * can be used, but in principle a shorter-lived ExprContext is better than a + * longer-lived one. + */ +void +ExecSetParamPlanMulti(const Bitmapset *params, ExprContext *econtext) +{ + int paramid; + + paramid = -1; + while ((paramid = bms_next_member(params, paramid)) >= 0) + { + ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]); + + if (prm->execPlan != NULL) + { + /* Parameter not evaluated yet, so go do it */ + ExecSetParamPlan(prm->execPlan, econtext); + /* ExecSetParamPlan should have processed this param... */ + Assert(prm->execPlan == NULL); + } + } +} + +/* * Mark an initplan as needing recalculation */ void |