diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2010-07-12 17:01:06 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2010-07-12 17:01:06 +0000 |
commit | 53e757689ce94520f1c53a89dbaa14ea57b09da7 (patch) | |
tree | afa68ba05699223a719104b953bc20f37d4c33d1 /src/backend/executor/nodeNestloop.c | |
parent | 5a3489357fb61f1ea76412ada33549aca152ad55 (diff) | |
download | postgresql-53e757689ce94520f1c53a89dbaa14ea57b09da7.tar.gz postgresql-53e757689ce94520f1c53a89dbaa14ea57b09da7.zip |
Make NestLoop plan nodes pass outer-relation variables into their inner
relation using the general PARAM_EXEC executor parameter mechanism, rather
than the ad-hoc kluge of passing the outer tuple down through ExecReScan.
The previous method was hard to understand and could never be extended to
handle parameters coming from multiple join levels. This patch doesn't
change the set of possible plans nor have any significant performance effect,
but it's necessary infrastructure for future generalization of the concept
of an inner indexscan plan.
ExecReScan's second parameter is now unused, so it's removed.
Diffstat (limited to 'src/backend/executor/nodeNestloop.c')
-rw-r--r-- | src/backend/executor/nodeNestloop.c | 65 |
1 files changed, 46 insertions, 19 deletions
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c index 1bcaef96e60..d59ed92f018 100644 --- a/src/backend/executor/nodeNestloop.c +++ b/src/backend/executor/nodeNestloop.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.55 2010/01/02 16:57:44 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.56 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -59,6 +59,7 @@ TupleTableSlot * ExecNestLoop(NestLoopState *node) { + NestLoop *nl; PlanState *innerPlan; PlanState *outerPlan; TupleTableSlot *outerTupleSlot; @@ -66,12 +67,14 @@ ExecNestLoop(NestLoopState *node) List *joinqual; List *otherqual; ExprContext *econtext; + ListCell *lc; /* * get information from the node */ ENL1_printf("getting info from node"); + nl = (NestLoop *) node->js.ps.plan; joinqual = node->js.joinqual; otherqual = node->js.ps.qual; outerPlan = outerPlanState(node); @@ -134,16 +137,33 @@ ExecNestLoop(NestLoopState *node) node->nl_MatchedOuter = false; /* - * now rescan the inner plan + * fetch the values of any outer Vars that must be passed to + * the inner scan, and store them in the appropriate PARAM_EXEC + * slots. */ - ENL1_printf("rescanning inner plan"); + foreach(lc, nl->nestParams) + { + NestLoopParam *nlp = (NestLoopParam *) lfirst(lc); + int paramno = nlp->paramno; + ParamExecData *prm; + + prm = &(econtext->ecxt_param_exec_vals[paramno]); + /* Param value should be an OUTER var */ + Assert(nlp->paramval->varno == OUTER); + Assert(nlp->paramval->varattno > 0); + prm->value = slot_getattr(outerTupleSlot, + nlp->paramval->varattno, + &(prm->isnull)); + /* Flag parameter value as changed */ + innerPlan->chgParam = bms_add_member(innerPlan->chgParam, + paramno); + } /* - * The scan key of the inner plan might depend on the current - * outer tuple (e.g. in index scans), that's why we pass our expr - * context. + * now rescan the inner plan */ - ExecReScan(innerPlan, econtext); + ENL1_printf("rescanning inner plan"); + ExecReScan(innerPlan); } /* @@ -308,15 +328,18 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags) /* * initialize child nodes * - * Tell the inner child that cheap rescans would be good. (This is - * unnecessary if we are doing nestloop with inner indexscan, because the - * rescan will always be with a fresh parameter --- but since - * nodeIndexscan doesn't actually care about REWIND, there's no point in - * dealing with that refinement.) + * If we have no parameters to pass into the inner rel from the outer, + * tell the inner child that cheap rescans would be good. If we do have + * such parameters, then there is no point in REWIND support at all in + * the inner child, because it will always be rescanned with fresh + * parameter values. */ outerPlanState(nlstate) = ExecInitNode(outerPlan(node), estate, eflags); - innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate, - eflags | EXEC_FLAG_REWIND); + if (node->nestParams == NIL) + eflags |= EXEC_FLAG_REWIND; + else + eflags &= ~EXEC_FLAG_REWIND; + innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate, eflags); /* * tuple table initialization @@ -395,18 +418,22 @@ ExecEndNestLoop(NestLoopState *node) * ---------------------------------------------------------------- */ void -ExecReScanNestLoop(NestLoopState *node, ExprContext *exprCtxt) +ExecReScanNestLoop(NestLoopState *node) { PlanState *outerPlan = outerPlanState(node); /* * If outerPlan->chgParam is not null then plan will be automatically - * re-scanned by first ExecProcNode. innerPlan is re-scanned for each new - * outer tuple and MUST NOT be re-scanned from here or you'll get troubles - * from inner index scans when outer Vars are used as run-time keys... + * re-scanned by first ExecProcNode. */ if (outerPlan->chgParam == NULL) - ExecReScan(outerPlan, exprCtxt); + ExecReScan(outerPlan); + + /* + * innerPlan is re-scanned for each new outer tuple and MUST NOT be + * re-scanned from here or you'll get troubles from inner index scans when + * outer Vars are used as run-time keys... + */ node->js.ps.ps_TupFromTlist = false; node->nl_NeedNewOuter = true; |