PostgreSQL Source Code  git master
nodeNestloop.c File Reference
#include "postgres.h"
#include "executor/execdebug.h"
#include "executor/nodeNestloop.h"
#include "miscadmin.h"
#include "utils/memutils.h"
Include dependency graph for nodeNestloop.c:

Go to the source code of this file.

Functions

static TupleTableSlotExecNestLoop (PlanState *pstate)
 
NestLoopStateExecInitNestLoop (NestLoop *node, EState *estate, int eflags)
 
void ExecEndNestLoop (NestLoopState *node)
 
void ExecReScanNestLoop (NestLoopState *node)
 

Function Documentation

◆ ExecEndNestLoop()

void ExecEndNestLoop ( NestLoopState node)

Definition at line 361 of file nodeNestloop.c.

References ExecClearTuple(), ExecEndNode(), ExecFreeExprContext(), innerPlanState, NestLoopState::js, NL1_printf, outerPlanState, JoinState::ps, and PlanState::ps_ResultTupleSlot.

Referenced by ExecEndNode().

362 {
363  NL1_printf("ExecEndNestLoop: %s\n",
364  "ending node processing");
365 
366  /*
367  * Free the exprcontext
368  */
369  ExecFreeExprContext(&node->js.ps);
370 
371  /*
372  * clean out the tuple table
373  */
375 
376  /*
377  * close down subplans
378  */
381 
382  NL1_printf("ExecEndNestLoop: %s\n",
383  "node processing ended");
384 }
PlanState ps
Definition: execnodes.h:1686
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:539
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:475
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:566
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:945
#define outerPlanState(node)
Definition: execnodes.h:965
#define NL1_printf(s, a)
Definition: execdebug.h:77
JoinState js
Definition: execnodes.h:1703
#define innerPlanState(node)
Definition: execnodes.h:964

◆ ExecInitNestLoop()

NestLoopState* ExecInitNestLoop ( NestLoop node,
EState estate,
int  eflags 
)

Definition at line 263 of file nodeNestloop.c.

References Assert, elog, ERROR, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, EXEC_FLAG_REWIND, ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecGetResultType(), ExecInitNode(), ExecInitNullTupleSlot(), ExecInitQual(), ExecInitResultTupleSlotTL(), ExecNestLoop(), PlanState::ExecProcNode, Join::inner_unique, innerPlan, innerPlanState, NestLoop::join, JOIN_ANTI, JOIN_INNER, JOIN_LEFT, JOIN_SEMI, Join::joinqual, Join::jointype, NestLoopState::js, makeNode, NestLoop::nestParams, NIL, NL1_printf, outerPlan, outerPlanState, Join::plan, PlanState::plan, JoinState::ps, Plan::qual, PlanState::qual, and PlanState::state.

Referenced by ExecInitNode().

264 {
265  NestLoopState *nlstate;
266 
267  /* check for unsupported flags */
268  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
269 
270  NL1_printf("ExecInitNestLoop: %s\n",
271  "initializing node");
272 
273  /*
274  * create state structure
275  */
276  nlstate = makeNode(NestLoopState);
277  nlstate->js.ps.plan = (Plan *) node;
278  nlstate->js.ps.state = estate;
279  nlstate->js.ps.ExecProcNode = ExecNestLoop;
280 
281  /*
282  * Miscellaneous initialization
283  *
284  * create expression context for node
285  */
286  ExecAssignExprContext(estate, &nlstate->js.ps);
287 
288  /*
289  * initialize child nodes
290  *
291  * If we have no parameters to pass into the inner rel from the outer,
292  * tell the inner child that cheap rescans would be good. If we do have
293  * such parameters, then there is no point in REWIND support at all in the
294  * inner child, because it will always be rescanned with fresh parameter
295  * values.
296  */
297  outerPlanState(nlstate) = ExecInitNode(outerPlan(node), estate, eflags);
298  if (node->nestParams == NIL)
299  eflags |= EXEC_FLAG_REWIND;
300  else
301  eflags &= ~EXEC_FLAG_REWIND;
302  innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate, eflags);
303 
304  /*
305  * Initialize result slot, type and projection.
306  */
307  ExecInitResultTupleSlotTL(estate, &nlstate->js.ps);
308  ExecAssignProjectionInfo(&nlstate->js.ps, NULL);
309 
310  /*
311  * initialize child expressions
312  */
313  nlstate->js.ps.qual =
314  ExecInitQual(node->join.plan.qual, (PlanState *) nlstate);
315  nlstate->js.jointype = node->join.jointype;
316  nlstate->js.joinqual =
317  ExecInitQual(node->join.joinqual, (PlanState *) nlstate);
318 
319  /*
320  * detect whether we need only consider the first matching inner tuple
321  */
322  nlstate->js.single_match = (node->join.inner_unique ||
323  node->join.jointype == JOIN_SEMI);
324 
325  /* set up null tuples for outer joins, if needed */
326  switch (node->join.jointype)
327  {
328  case JOIN_INNER:
329  case JOIN_SEMI:
330  break;
331  case JOIN_LEFT:
332  case JOIN_ANTI:
333  nlstate->nl_NullInnerTupleSlot =
334  ExecInitNullTupleSlot(estate,
336  break;
337  default:
338  elog(ERROR, "unrecognized join type: %d",
339  (int) node->join.jointype);
340  }
341 
342  /*
343  * finally, wipe the current outer tuple clean.
344  */
345  nlstate->nl_NeedNewOuter = true;
346  nlstate->nl_MatchedOuter = false;
347 
348  NL1_printf("ExecInitNestLoop: %s\n",
349  "node initialized");
350 
351  return nlstate;
352 }
JoinType jointype
Definition: execnodes.h:1687
#define NIL
Definition: pg_list.h:69
List * qual
Definition: plannodes.h:147
bool nl_MatchedOuter
Definition: execnodes.h:1705
ExprState * joinqual
Definition: execnodes.h:1690
List * nestParams
Definition: plannodes.h:700
PlanState ps
Definition: execnodes.h:1686
bool nl_NeedNewOuter
Definition: execnodes.h:1704
bool single_match
Definition: execnodes.h:1688
EState * state
Definition: execnodes.h:913
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:205
JoinType jointype
Definition: plannodes.h:681
TupleTableSlot * ExecInitNullTupleSlot(EState *estate, TupleDesc tupType)
Definition: execTuples.c:945
Join join
Definition: plannodes.h:699
#define ERROR
Definition: elog.h:43
#define EXEC_FLAG_BACKWARD
Definition: executor.h:60
#define outerPlanState(node)
Definition: execnodes.h:965
#define innerPlan(node)
Definition: plannodes.h:175
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:456
#define EXEC_FLAG_REWIND
Definition: executor.h:59
#define outerPlan(node)
Definition: plannodes.h:176
static TupleTableSlot * ExecNestLoop(PlanState *pstate)
Definition: nodeNestloop.c:61
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:917
void ExecInitResultTupleSlotTL(EState *estate, PlanState *planstate)
Definition: execTuples.c:890
TupleTableSlot * nl_NullInnerTupleSlot
Definition: execnodes.h:1706
Plan * plan
Definition: execnodes.h:911
#define makeNode(_type_)
Definition: nodes.h:565
#define Assert(condition)
Definition: c.h:699
#define EXEC_FLAG_MARK
Definition: executor.h:61
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:428
#define NL1_printf(s, a)
Definition: execdebug.h:77
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:438
ExprState * qual
Definition: execnodes.h:929
JoinState js
Definition: execnodes.h:1703
#define elog
Definition: elog.h:219
bool inner_unique
Definition: plannodes.h:682
#define innerPlanState(node)
Definition: execnodes.h:964
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
List * joinqual
Definition: plannodes.h:683
Plan plan
Definition: plannodes.h:680

◆ ExecNestLoop()

static TupleTableSlot* ExecNestLoop ( PlanState pstate)
static

Definition at line 61 of file nodeNestloop.c.

References Assert, bms_add_member(), castNode, CHECK_FOR_INTERRUPTS, PlanState::chgParam, ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, ExprContext::ecxt_param_exec_vals, ENL1_printf, ExecProcNode(), ExecProject(), ExecQual(), ExecReScan(), innerPlan, innerPlanState, InstrCountFiltered1, InstrCountFiltered2, IsA, ParamExecData::isnull, JOIN_ANTI, JOIN_LEFT, JoinState::joinqual, JoinState::jointype, NestLoopState::js, lfirst, NestLoop::nestParams, NestLoopState::nl_MatchedOuter, NestLoopState::nl_NeedNewOuter, NestLoopState::nl_NullInnerTupleSlot, OUTER_VAR, outerPlan, outerPlanState, NestLoopParam::paramno, NestLoopParam::paramval, PlanState::plan, JoinState::ps, PlanState::ps_ExprContext, PlanState::ps_ProjInfo, PlanState::qual, ResetExprContext, JoinState::single_match, slot_getattr(), TupIsNull, ParamExecData::value, Var::varattno, and Var::varno.

Referenced by ExecInitNestLoop().

62 {
63  NestLoopState *node = castNode(NestLoopState, pstate);
64  NestLoop *nl;
67  TupleTableSlot *outerTupleSlot;
68  TupleTableSlot *innerTupleSlot;
69  ExprState *joinqual;
70  ExprState *otherqual;
71  ExprContext *econtext;
72  ListCell *lc;
73 
75 
76  /*
77  * get information from the node
78  */
79  ENL1_printf("getting info from node");
80 
81  nl = (NestLoop *) node->js.ps.plan;
82  joinqual = node->js.joinqual;
83  otherqual = node->js.ps.qual;
84  outerPlan = outerPlanState(node);
85  innerPlan = innerPlanState(node);
86  econtext = node->js.ps.ps_ExprContext;
87 
88  /*
89  * Reset per-tuple memory context to free any expression evaluation
90  * storage allocated in the previous tuple cycle.
91  */
92  ResetExprContext(econtext);
93 
94  /*
95  * Ok, everything is setup for the join so now loop until we return a
96  * qualifying join tuple.
97  */
98  ENL1_printf("entering main loop");
99 
100  for (;;)
101  {
102  /*
103  * If we don't have an outer tuple, get the next one and reset the
104  * inner scan.
105  */
106  if (node->nl_NeedNewOuter)
107  {
108  ENL1_printf("getting new outer tuple");
109  outerTupleSlot = ExecProcNode(outerPlan);
110 
111  /*
112  * if there are no more outer tuples, then the join is complete..
113  */
114  if (TupIsNull(outerTupleSlot))
115  {
116  ENL1_printf("no outer tuple, ending join");
117  return NULL;
118  }
119 
120  ENL1_printf("saving new outer tuple information");
121  econtext->ecxt_outertuple = outerTupleSlot;
122  node->nl_NeedNewOuter = false;
123  node->nl_MatchedOuter = false;
124 
125  /*
126  * fetch the values of any outer Vars that must be passed to the
127  * inner scan, and store them in the appropriate PARAM_EXEC slots.
128  */
129  foreach(lc, nl->nestParams)
130  {
131  NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
132  int paramno = nlp->paramno;
133  ParamExecData *prm;
134 
135  prm = &(econtext->ecxt_param_exec_vals[paramno]);
136  /* Param value should be an OUTER_VAR var */
137  Assert(IsA(nlp->paramval, Var));
138  Assert(nlp->paramval->varno == OUTER_VAR);
139  Assert(nlp->paramval->varattno > 0);
140  prm->value = slot_getattr(outerTupleSlot,
141  nlp->paramval->varattno,
142  &(prm->isnull));
143  /* Flag parameter value as changed */
144  innerPlan->chgParam = bms_add_member(innerPlan->chgParam,
145  paramno);
146  }
147 
148  /*
149  * now rescan the inner plan
150  */
151  ENL1_printf("rescanning inner plan");
152  ExecReScan(innerPlan);
153  }
154 
155  /*
156  * we have an outerTuple, try to get the next inner tuple.
157  */
158  ENL1_printf("getting new inner tuple");
159 
160  innerTupleSlot = ExecProcNode(innerPlan);
161  econtext->ecxt_innertuple = innerTupleSlot;
162 
163  if (TupIsNull(innerTupleSlot))
164  {
165  ENL1_printf("no inner tuple, need new outer tuple");
166 
167  node->nl_NeedNewOuter = true;
168 
169  if (!node->nl_MatchedOuter &&
170  (node->js.jointype == JOIN_LEFT ||
171  node->js.jointype == JOIN_ANTI))
172  {
173  /*
174  * We are doing an outer join and there were no join matches
175  * for this outer tuple. Generate a fake join tuple with
176  * nulls for the inner tuple, and return it if it passes the
177  * non-join quals.
178  */
179  econtext->ecxt_innertuple = node->nl_NullInnerTupleSlot;
180 
181  ENL1_printf("testing qualification for outer-join tuple");
182 
183  if (otherqual == NULL || ExecQual(otherqual, econtext))
184  {
185  /*
186  * qualification was satisfied so we project and return
187  * the slot containing the result tuple using
188  * ExecProject().
189  */
190  ENL1_printf("qualification succeeded, projecting tuple");
191 
192  return ExecProject(node->js.ps.ps_ProjInfo);
193  }
194  else
195  InstrCountFiltered2(node, 1);
196  }
197 
198  /*
199  * Otherwise just return to top of loop for a new outer tuple.
200  */
201  continue;
202  }
203 
204  /*
205  * at this point we have a new pair of inner and outer tuples so we
206  * test the inner and outer tuples to see if they satisfy the node's
207  * qualification.
208  *
209  * Only the joinquals determine MatchedOuter status, but all quals
210  * must pass to actually return the tuple.
211  */
212  ENL1_printf("testing qualification");
213 
214  if (ExecQual(joinqual, econtext))
215  {
216  node->nl_MatchedOuter = true;
217 
218  /* In an antijoin, we never return a matched tuple */
219  if (node->js.jointype == JOIN_ANTI)
220  {
221  node->nl_NeedNewOuter = true;
222  continue; /* return to top of loop */
223  }
224 
225  /*
226  * If we only need to join to the first matching inner tuple, then
227  * consider returning this one, but after that continue with next
228  * outer tuple.
229  */
230  if (node->js.single_match)
231  node->nl_NeedNewOuter = true;
232 
233  if (otherqual == NULL || ExecQual(otherqual, econtext))
234  {
235  /*
236  * qualification was satisfied so we project and return the
237  * slot containing the result tuple using ExecProject().
238  */
239  ENL1_printf("qualification succeeded, projecting tuple");
240 
241  return ExecProject(node->js.ps.ps_ProjInfo);
242  }
243  else
244  InstrCountFiltered2(node, 1);
245  }
246  else
247  InstrCountFiltered1(node, 1);
248 
249  /*
250  * Tuple fails qual, so free per-tuple memory and try again.
251  */
252  ResetExprContext(econtext);
253 
254  ENL1_printf("qualification failed, looping");
255  }
256 }
JoinType jointype
Definition: execnodes.h:1687
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
bool nl_MatchedOuter
Definition: execnodes.h:1705
ExprState * joinqual
Definition: execnodes.h:1690
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:947
List * nestParams
Definition: plannodes.h:700
PlanState ps
Definition: execnodes.h:1686
#define castNode(_type_, nodeptr)
Definition: nodes.h:586
bool nl_NeedNewOuter
Definition: execnodes.h:1704
ExprContext * ps_ExprContext
Definition: execnodes.h:946
bool single_match
Definition: execnodes.h:1688
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
AttrNumber varattno
Definition: primnodes.h:169
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:361
Definition: primnodes.h:164
Var * paramval
Definition: plannodes.h:707
#define ENL1_printf(message)
Definition: execdebug.h:78
bool isnull
Definition: params.h:149
#define outerPlanState(node)
Definition: execnodes.h:965
#define innerPlan(node)
Definition: plannodes.h:175
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:220
ParamExecData * ecxt_param_exec_vals
Definition: execnodes.h:229
#define TupIsNull(slot)
Definition: tuptable.h:146
#define InstrCountFiltered1(node, delta)
Definition: execnodes.h:973
Bitmapset * chgParam
Definition: execnodes.h:940
#define outerPlan(node)
Definition: plannodes.h:176
Index varno
Definition: primnodes.h:167
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:233
TupleTableSlot * nl_NullInnerTupleSlot
Definition: execnodes.h:1706
Plan * plan
Definition: execnodes.h:911
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:222
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
#define InstrCountFiltered2(node, delta)
Definition: execnodes.h:978
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:764
ExprState * qual
Definition: execnodes.h:929
JoinState js
Definition: execnodes.h:1703
Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: heaptuple.c:1518
Datum value
Definition: params.h:148
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define innerPlanState(node)
Definition: execnodes.h:964
#define OUTER_VAR
Definition: primnodes.h:155
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:324
#define ResetExprContext(econtext)
Definition: executor.h:483

◆ ExecReScanNestLoop()

void ExecReScanNestLoop ( NestLoopState node)

Definition at line 391 of file nodeNestloop.c.

References PlanState::chgParam, ExecReScan(), NestLoopState::nl_MatchedOuter, NestLoopState::nl_NeedNewOuter, outerPlan, and outerPlanState.

Referenced by ExecReScan().

392 {
394 
395  /*
396  * If outerPlan->chgParam is not null then plan will be automatically
397  * re-scanned by first ExecProcNode.
398  */
399  if (outerPlan->chgParam == NULL)
400  ExecReScan(outerPlan);
401 
402  /*
403  * innerPlan is re-scanned for each new outer tuple and MUST NOT be
404  * re-scanned from here or you'll get troubles from inner index scans when
405  * outer Vars are used as run-time keys...
406  */
407 
408  node->nl_NeedNewOuter = true;
409  node->nl_MatchedOuter = false;
410 }
bool nl_MatchedOuter
Definition: execnodes.h:1705
bool nl_NeedNewOuter
Definition: execnodes.h:1704
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
#define outerPlanState(node)
Definition: execnodes.h:965
Bitmapset * chgParam
Definition: execnodes.h:940
#define outerPlan(node)
Definition: plannodes.h:176