]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeNestloop.c
Final cleanup.
[postgresql] / src / backend / executor / nodeNestloop.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeNestloop.c
4  *        routines to support nest-loop joins
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.13 1999/07/16 04:58:51 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 /*
15  *       INTERFACE ROUTINES
16  *              ExecNestLoop     - process a nestloop join of two plans
17  *              ExecInitNestLoop - initialize the join
18  *              ExecEndNestLoop  - shut down the join
19  */
20 #include "postgres.h"
21
22 #include "executor/execdebug.h"
23 #include "executor/executor.h"
24 #include "executor/nodeNestloop.h"
25
26 /* ----------------------------------------------------------------
27  *              ExecNestLoop(node)
28  *
29  * old comments
30  *              Returns the tuple joined from inner and outer tuples which
31  *              satisfies the qualification clause.
32  *
33  *              It scans the inner relation to join with current outer tuple.
34  *
35  *              If none is found, next tuple form the outer relation is retrieved
36  *              and the inner relation is scanned from the beginning again to join
37  *              with the outer tuple.
38  *
39  *              Nil is returned if all the remaining outer tuples are tried and
40  *              all fail to join with the inner tuples.
41  *
42  *              Nil is also returned if there is no tuple from inner realtion.
43  *
44  *              Conditions:
45  *                -- outerTuple contains current tuple from outer relation and
46  *                       the right son(inner realtion) maintains "cursor" at the tuple
47  *                       returned previously.
48  *                              This is achieved by maintaining a scan position on the outer
49  *                              relation.
50  *
51  *              Initial States:
52  *                -- the outer child and the inner child
53  *                         are prepared to return the first tuple.
54  * ----------------------------------------------------------------
55  */
56 TupleTableSlot *
57 ExecNestLoop(NestLoop *node, Plan *parent)
58 {
59         NestLoopState *nlstate;
60         Plan       *innerPlan;
61         Plan       *outerPlan;
62         bool            needNewOuterTuple;
63
64         TupleTableSlot *outerTupleSlot;
65         TupleTableSlot *innerTupleSlot;
66
67         List       *qual;
68         bool            qualResult;
69         ExprContext *econtext;
70
71         /* ----------------
72          *      get information from the node
73          * ----------------
74          */
75         ENL1_printf("getting info from node");
76
77         nlstate = node->nlstate;
78         qual = node->join.qual;
79         outerPlan = outerPlan(&node->join);
80         innerPlan = innerPlan(&node->join);
81
82         /* ----------------
83          *      initialize expression context
84          * ----------------
85          */
86         econtext = nlstate->jstate.cs_ExprContext;
87
88         /* ----------------
89          * get the current outer tuple
90          * ----------------
91          */
92         outerTupleSlot = nlstate->jstate.cs_OuterTupleSlot;
93         econtext->ecxt_outertuple = outerTupleSlot;
94
95         /* ----------------
96          *      Ok, everything is setup for the join so now loop until
97          *      we return a qualifying join tuple..
98          * ----------------
99          */
100
101         if (nlstate->jstate.cs_TupFromTlist)
102         {
103                 TupleTableSlot *result;
104                 bool            isDone;
105
106                 result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
107                 if (!isDone)
108                         return result;
109         }
110
111         ENL1_printf("entering main loop");
112         for (;;)
113         {
114                 /* ----------------
115                  *      The essential idea now is to get the next inner tuple
116                  *      and join it with the current outer tuple.
117                  * ----------------
118                  */
119                 needNewOuterTuple = false;
120
121                 if (!TupIsNull(outerTupleSlot))
122                         ENL1_printf("have outer tuple, deal with it");
123                 else
124                 {
125                         ENL1_printf("outer tuple is nil, need new outer tuple");
126                         needNewOuterTuple = true;
127                 }
128
129                 /* ----------------
130                  *      if we have an outerTuple, try to get the next inner tuple.
131                  * ----------------
132                  */
133                 if (!needNewOuterTuple)
134                 {
135                         ENL1_printf("getting new inner tuple");
136
137                         innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
138                         econtext->ecxt_innertuple = innerTupleSlot;
139
140                         if (TupIsNull(innerTupleSlot))
141                         {
142                                 ENL1_printf("no inner tuple, need new outer tuple");
143                                 needNewOuterTuple = true;
144                         }
145                 }
146
147                 /* ----------------
148                  *      loop until we have a new outer tuple and a new
149                  *      inner tuple.
150                  * ----------------
151                  */
152                 while (needNewOuterTuple)
153                 {
154                         /* ----------------
155                          *      now try to get the next outer tuple
156                          * ----------------
157                          */
158                         ENL1_printf("getting new outer tuple");
159                         outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
160                         econtext->ecxt_outertuple = outerTupleSlot;
161
162                         /* ----------------
163                          *      if there are no more outer tuples, then the join
164                          *      is complete..
165                          * ----------------
166                          */
167                         if (TupIsNull(outerTupleSlot))
168                         {
169                                 ENL1_printf("no outer tuple, ending join");
170                                 return NULL;
171                         }
172
173                         ENL1_printf("saving new outer tuple information");
174                         nlstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
175
176                         /* ----------------
177                          *      now rescan the inner plan and get a new inner tuple
178                          * ----------------
179                          */
180
181                         ENL1_printf("rescanning inner plan");
182
183                         /*
184                          * The scan key of the inner plan might depend on the current
185                          * outer tuple (e.g. in index scans), that's why we pass our
186                          * expr context.
187                          */
188                         ExecReScan(innerPlan, econtext, parent);
189
190                         ENL1_printf("getting new inner tuple");
191
192                         innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
193                         econtext->ecxt_innertuple = innerTupleSlot;
194
195                         if (TupIsNull(innerTupleSlot))
196                                 ENL1_printf("couldn't get inner tuple - need new outer tuple");
197                         else
198                         {
199                                 ENL1_printf("got inner and outer tuples");
200                                 needNewOuterTuple = false;
201                         }
202                 }                                               /* while (needNewOuterTuple) */
203
204                 /* ----------------
205                  *       at this point we have a new pair of inner and outer
206                  *       tuples so we test the inner and outer tuples to see
207                  *       if they satisify the node's qualification.
208                  * ----------------
209                  */
210                 ENL1_printf("testing qualification");
211                 qualResult = ExecQual((List *) qual, econtext);
212
213                 if (qualResult)
214                 {
215                         /* ----------------
216                          *      qualification was satisified so we project and
217                          *      return the slot containing the result tuple
218                          *      using ExecProject().
219                          * ----------------
220                          */
221                         ProjectionInfo *projInfo;
222                         TupleTableSlot *result;
223                         bool            isDone;
224
225                         ENL1_printf("qualification succeeded, projecting tuple");
226
227                         projInfo = nlstate->jstate.cs_ProjInfo;
228                         result = ExecProject(projInfo, &isDone);
229                         nlstate->jstate.cs_TupFromTlist = !isDone;
230                         return result;
231                 }
232
233                 /* ----------------
234                  *      qualification failed so we have to try again..
235                  * ----------------
236                  */
237                 ENL1_printf("qualification failed, looping");
238         }
239 }
240
241 /* ----------------------------------------------------------------
242  *              ExecInitNestLoop
243  *
244  *              Creates the run-time state information for the nestloop node
245  *              produced by the planner and initailizes inner and outer relations
246  *              (child nodes).
247  * ----------------------------------------------------------------
248  */
249 bool
250 ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
251 {
252         NestLoopState *nlstate;
253
254         NL1_printf("ExecInitNestLoop: %s\n",
255                            "initializing node");
256
257         /* ----------------
258          *      assign execution state to node
259          * ----------------
260          */
261         node->join.state = estate;
262
263         /* ----------------
264          *        create new nest loop state
265          * ----------------
266          */
267         nlstate = makeNode(NestLoopState);
268         nlstate->nl_PortalFlag = false;
269         node->nlstate = nlstate;
270
271         /* ----------------
272          *      Miscellanious initialization
273          *
274          *               +      assign node's base_id
275          *               +      assign debugging hooks and
276          *               +      create expression context for node
277          * ----------------
278          */
279         ExecAssignNodeBaseInfo(estate, &nlstate->jstate, parent);
280         ExecAssignExprContext(estate, &nlstate->jstate);
281
282 #define NESTLOOP_NSLOTS 1
283         /* ----------------
284          *      tuple table initialization
285          * ----------------
286          */
287         ExecInitResultTupleSlot(estate, &nlstate->jstate);
288
289         /* ----------------
290          *        now initialize children
291          * ----------------
292          */
293         ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
294         ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
295
296         /* ----------------
297          *      initialize tuple type and projection info
298          * ----------------
299          */
300         ExecAssignResultTypeFromTL((Plan *) node, &nlstate->jstate);
301         ExecAssignProjectionInfo((Plan *) node, &nlstate->jstate);
302
303         /* ----------------
304          *      finally, wipe the current outer tuple clean.
305          * ----------------
306          */
307         nlstate->jstate.cs_OuterTupleSlot = NULL;
308         nlstate->jstate.cs_TupFromTlist = false;
309
310         NL1_printf("ExecInitNestLoop: %s\n",
311                            "node initialized");
312         return TRUE;
313 }
314
315 int
316 ExecCountSlotsNestLoop(NestLoop *node)
317 {
318         return ExecCountSlotsNode(outerPlan(node)) +
319         ExecCountSlotsNode(innerPlan(node)) +
320         NESTLOOP_NSLOTS;
321 }
322
323 /* ----------------------------------------------------------------
324  *              ExecEndNestLoop
325  *
326  *              closes down scans and frees allocated storage
327  * ----------------------------------------------------------------
328  */
329 void
330 ExecEndNestLoop(NestLoop *node)
331 {
332         NestLoopState *nlstate;
333
334         NL1_printf("ExecEndNestLoop: %s\n",
335                            "ending node processing");
336
337         /* ----------------
338          *      get info from the node
339          * ----------------
340          */
341         nlstate = node->nlstate;
342
343         /* ----------------
344          *      Free the projection info
345          *
346          *      Note: we don't ExecFreeResultType(nlstate)
347          *                because the rule manager depends on the tupType
348          *                returned by ExecMain().  So for now, this
349          *                is freed at end-transaction time.  -cim 6/2/91
350          * ----------------
351          */
352         ExecFreeProjectionInfo(&nlstate->jstate);
353
354         /* ----------------
355          *      close down subplans
356          * ----------------
357          */
358         ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
359         ExecEndNode(innerPlan((Plan *) node), (Plan *) node);
360
361         /* ----------------
362          *      clean out the tuple table
363          * ----------------
364          */
365         ExecClearTuple(nlstate->jstate.cs_ResultTupleSlot);
366
367         NL1_printf("ExecEndNestLoop: %s\n",
368                            "node processing ended");
369 }
370
371 /* ----------------------------------------------------------------
372  *              ExecReScanNestLoop
373  * ----------------------------------------------------------------
374  */
375 void
376 ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt, Plan *parent)
377 {
378         NestLoopState *nlstate = node->nlstate;
379         Plan       *outerPlan = outerPlan((Plan *) node);
380
381         /*
382          * If outerPlan->chgParam is not null then plan will be automatically
383          * re-scanned by first ExecProcNode. innerPlan is re-scanned for each
384          * new outer tuple and MUST NOT be re-scanned from here or you'll get
385          * troubles from inner index scans when outer Vars are used as
386          * run-time keys...
387          */
388         if (outerPlan->chgParam == NULL)
389                 ExecReScan(outerPlan, exprCtxt, (Plan *) node);
390
391         /* let outerPlan to free its result typle ... */
392         nlstate->jstate.cs_OuterTupleSlot = NULL;
393         nlstate->jstate.cs_TupFromTlist = false;
394
395         return;
396 }