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