1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

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.
This commit is contained in:
Tom Lane
2010-07-12 17:01:06 +00:00
parent 5a3489357f
commit 53e757689c
76 changed files with 802 additions and 700 deletions

View File

@ -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);
@ -133,17 +136,34 @@ ExecNestLoop(NestLoopState *node)
node->nl_NeedNewOuter = false;
node->nl_MatchedOuter = false;
/*
* fetch the values of any outer Vars that must be passed to
* the inner scan, and store them in the appropriate PARAM_EXEC
* slots.
*/
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);
}
/*
* now rescan the inner plan
*/
ENL1_printf("rescanning inner plan");
/*
* 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.
*/
ExecReScan(innerPlan, econtext);
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;