PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
nodeNestloop.c File Reference
#include "postgres.h"
#include "executor/execdebug.h"
#include "executor/nodeNestloop.h"
#include "utils/memutils.h"
Include dependency graph for nodeNestloop.c:

Go to the source code of this file.

Functions

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

Function Documentation

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:1564
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:654
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:516
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:861
#define outerPlanState(node)
Definition: execnodes.h:874
#define NL1_printf(s, a)
Definition: execdebug.h:77
JoinState js
Definition: execnodes.h:1581
#define innerPlanState(node)
Definition: execnodes.h:873
NestLoopState* ExecInitNestLoop ( NestLoop node,
EState estate,
int  eflags 
)

Definition at line 259 of file nodeNestloop.c.

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

Referenced by ExecInitNode().

260 {
261  NestLoopState *nlstate;
262 
263  /* check for unsupported flags */
264  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
265 
266  NL1_printf("ExecInitNestLoop: %s\n",
267  "initializing node");
268 
269  /*
270  * create state structure
271  */
272  nlstate = makeNode(NestLoopState);
273  nlstate->js.ps.plan = (Plan *) node;
274  nlstate->js.ps.state = estate;
275 
276  /*
277  * Miscellaneous initialization
278  *
279  * create expression context for node
280  */
281  ExecAssignExprContext(estate, &nlstate->js.ps);
282 
283  /*
284  * initialize child expressions
285  */
286  nlstate->js.ps.qual =
287  ExecInitQual(node->join.plan.qual, (PlanState *) nlstate);
288  nlstate->js.jointype = node->join.jointype;
289  nlstate->js.joinqual =
290  ExecInitQual(node->join.joinqual, (PlanState *) nlstate);
291 
292  /*
293  * initialize child nodes
294  *
295  * If we have no parameters to pass into the inner rel from the outer,
296  * tell the inner child that cheap rescans would be good. If we do have
297  * such parameters, then there is no point in REWIND support at all in the
298  * inner child, because it will always be rescanned with fresh parameter
299  * values.
300  */
301  outerPlanState(nlstate) = ExecInitNode(outerPlan(node), estate, eflags);
302  if (node->nestParams == NIL)
303  eflags |= EXEC_FLAG_REWIND;
304  else
305  eflags &= ~EXEC_FLAG_REWIND;
306  innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate, eflags);
307 
308  /*
309  * tuple table initialization
310  */
311  ExecInitResultTupleSlot(estate, &nlstate->js.ps);
312 
313  /*
314  * detect whether we need only consider the first matching inner tuple
315  */
316  nlstate->js.single_match = (node->join.inner_unique ||
317  node->join.jointype == JOIN_SEMI);
318 
319  /* set up null tuples for outer joins, if needed */
320  switch (node->join.jointype)
321  {
322  case JOIN_INNER:
323  case JOIN_SEMI:
324  break;
325  case JOIN_LEFT:
326  case JOIN_ANTI:
327  nlstate->nl_NullInnerTupleSlot =
328  ExecInitNullTupleSlot(estate,
330  break;
331  default:
332  elog(ERROR, "unrecognized join type: %d",
333  (int) node->join.jointype);
334  }
335 
336  /*
337  * initialize tuple type and projection info
338  */
339  ExecAssignResultTypeFromTL(&nlstate->js.ps);
340  ExecAssignProjectionInfo(&nlstate->js.ps, NULL);
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:1565
#define NIL
Definition: pg_list.h:69
List * qual
Definition: plannodes.h:145
bool nl_MatchedOuter
Definition: execnodes.h:1583
ExprState * joinqual
Definition: execnodes.h:1568
List * nestParams
Definition: plannodes.h:686
PlanState ps
Definition: execnodes.h:1564
bool nl_NeedNewOuter
Definition: execnodes.h:1582
bool single_match
Definition: execnodes.h:1566
EState * state
Definition: execnodes.h:834
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:160
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:440
JoinType jointype
Definition: plannodes.h:667
TupleTableSlot * ExecInitNullTupleSlot(EState *estate, TupleDesc tupType)
Definition: execTuples.c:866
Join join
Definition: plannodes.h:685
#define ERROR
Definition: elog.h:43
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
#define EXEC_FLAG_BACKWARD
Definition: executor.h:60
#define outerPlanState(node)
Definition: execnodes.h:874
#define innerPlan(node)
Definition: plannodes.h:173
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:487
#define EXEC_FLAG_REWIND
Definition: executor.h:59
#define outerPlan(node)
Definition: plannodes.h:174
TupleTableSlot * nl_NullInnerTupleSlot
Definition: execnodes.h:1584
Plan * plan
Definition: execnodes.h:832
#define makeNode(_type_)
Definition: nodes.h:557
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define EXEC_FLAG_MARK
Definition: executor.h:61
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:418
#define NL1_printf(s, a)
Definition: execdebug.h:77
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:469
ExprState * qual
Definition: execnodes.h:846
JoinState js
Definition: execnodes.h:1581
#define elog
Definition: elog.h:219
bool inner_unique
Definition: plannodes.h:668
#define innerPlanState(node)
Definition: execnodes.h:873
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:140
List * joinqual
Definition: plannodes.h:669
Plan plan
Definition: plannodes.h:666
TupleTableSlot* ExecNestLoop ( NestLoopState node)

Definition at line 60 of file nodeNestloop.c.

References Assert, bms_add_member(), 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, NULL, 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 ExecProcNode().

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

Definition at line 391 of file nodeNestloop.c.

References PlanState::chgParam, ExecReScan(), NestLoopState::nl_MatchedOuter, NestLoopState::nl_NeedNewOuter, NULL, 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:1583
bool nl_NeedNewOuter
Definition: execnodes.h:1582
void ExecReScan(PlanState *node)
Definition: execAmi.c:75
#define outerPlanState(node)
Definition: execnodes.h:874
Bitmapset * chgParam
Definition: execnodes.h:856
#define outerPlan(node)
Definition: plannodes.h:174
#define NULL
Definition: c.h:229