]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeMergejoin.c
Final cleanup.
[postgresql] / src / backend / executor / nodeMergejoin.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeMergejoin.c
4  *        routines supporting merge joins
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.28 1999/07/16 04:58:50 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 /*
15  * INTERFACE ROUTINES
16  *              ExecMergeJoin                   mergejoin outer and inner relations.
17  *              ExecInitMergeJoin               creates and initializes run time states
18  *              ExecEndMergeJoin                cleand up the node.
19  *
20  * NOTES
21  *              Essential operation of the merge join algorithm is as follows:
22  *              (** indicates the tuples satisfy the merge clause).
23  *
24  *              Join {                                                                                             -
25  *                      get initial outer and inner tuples                              INITIALIZE
26  *                      Skip Inner                                                                              SKIPINNER
27  *                      mark inner position                                                             JOINMARK
28  *                      do forever {                                                                       -
29  *                              while (outer == inner) {                                        JOINTEST
30  *                                      join tuples                                                             JOINTUPLES
31  *                                      advance inner position                                  NEXTINNER
32  *                              }                                                                                          -
33  *                              advance outer position                                          NEXTOUTER
34  *                              if (outer == mark) {                                            TESTOUTER
35  *                                      restore inner position to mark                  TESTOUTER
36  *                                      continue                                                                   -
37  *                              } else {                                                                           -
38  *                                      Skip Outer                                                              SKIPOUTER
39  *                                      mark inner position                                             JOINMARK
40  *                              }                                                                                          -
41  *                      }                                                                                                  -
42  *              }                                                                                                          -
43  *
44  *              Skip Outer {                                                                            SKIPOUTER
45  *                      if (inner == outer) Join Tuples                                 JOINTUPLES
46  *                      while (outer < inner)                                                   SKIPOUTER
47  *                              advance outer                                                           SKIPOUTER
48  *                      if (outer > inner)                                                              SKIPOUTER
49  *                              Skip Inner                                                                      SKIPINNER
50  *              }                                                                                                          -
51  *
52  *              Skip Inner {                                                                            SKIPINNER
53  *                      if (inner == outer) Join Tuples                                 JOINTUPLES
54  *                      while (outer > inner)                                                   SKIPINNER
55  *                              advance inner                                                           SKIPINNER
56  *                      if (outer < inner)                                                              SKIPINNER
57  *                              Skip Outer                                                                      SKIPOUTER
58  *              }                                                                                                          -
59  *
60  *              The merge join operation is coded in the fashion
61  *              of a state machine.  At each state, we do something and then
62  *              proceed to another state.  This state is stored in the node's
63  *              execution state information and is preserved across calls to
64  *              ExecMergeJoin. -cim 10/31/89
65  *
66  */
67 #include "postgres.h"
68
69 #include "access/heapam.h"
70 #include "catalog/pg_operator.h"
71 #include "executor/execdebug.h"
72 #include "executor/execdefs.h"
73 #include "executor/executor.h"
74 #include "executor/nodeMergejoin.h"
75 #include "utils/lsyscache.h"
76 #include "utils/psort.h"
77
78
79 static bool MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext);
80
81 #define MarkInnerTuple(innerTupleSlot, mergestate) \
82 ( \
83         ExecStoreTuple(heap_copytuple((innerTupleSlot)->val), \
84                                    (mergestate)->mj_MarkedTupleSlot, \
85                                    InvalidBuffer, \
86                                    true) \
87 )
88
89
90 /* ----------------------------------------------------------------
91  *              MJFormSkipQual
92  *
93  *              This takes the mergeclause which is a qualification of the
94  *              form ((= expr expr) (= expr expr) ...) and forms a new
95  *              qualification like ((> expr expr) (> expr expr) ...) which
96  *              is used by ExecMergeJoin() in order to determine if we should
97  *              skip tuples.  The replacement operators are named either ">"
98  *              or "<" according to the replaceopname parameter, and have the
99  *              same operand data types as the "=" operators they replace.
100  *              (We expect there to be such operators because the "=" operators
101  *              were marked mergejoinable; however, there might be a different
102  *              one needed in each qual clause.)
103  * ----------------------------------------------------------------
104  */
105 static List *
106 MJFormSkipQual(List *qualList, char *replaceopname)
107 {
108         List       *qualCopy;
109         List       *qualcdr;
110         Expr       *qual;
111         Oper       *op;
112         HeapTuple       optup;
113         Form_pg_operator opform;
114         Oid                     oprleft,
115                                 oprright;
116
117         /* ----------------
118          *      qualList is a list: ((op .. ..) ...)
119          *      first we make a copy of it.  copyObject() makes a deep copy
120          *      so let's use it instead of the old fashoned lispCopy()...
121          * ----------------
122          */
123         qualCopy = (List *) copyObject((Node *) qualList);
124
125         foreach(qualcdr, qualCopy)
126         {
127                 /* ----------------
128                  *       first get the current (op .. ..) list
129                  * ----------------
130                  */
131                 qual = lfirst(qualcdr);
132
133                 /* ----------------
134                  *       now get at the op
135                  * ----------------
136                  */
137                 op = (Oper *) qual->oper;
138                 if (!IsA(op, Oper))
139                         elog(ERROR, "MJFormSkipQual: op not an Oper!");
140
141                 /* ----------------
142                  *       Get the declared left and right operand types of the operator.
143                  *       Note we do *not* use the actual operand types, since those might
144                  *       be different in scenarios with binary-compatible data types.
145                  *       There should be "<" and ">" operators matching a mergejoinable
146                  *       "=" operator's declared operand types, but we might not find them
147                  *       if we search with the actual operand types.
148                  * ----------------
149                  */
150                 optup = get_operator_tuple(op->opno);
151                 if (!HeapTupleIsValid(optup))   /* shouldn't happen */
152                         elog(ERROR, "MJFormSkipQual: operator %u not found", op->opno);
153                 opform = (Form_pg_operator) GETSTRUCT(optup);
154                 oprleft = opform->oprleft;
155                 oprright = opform->oprright;
156
157                 /* ----------------
158                  *       Now look up the matching "<" or ">" operator.  If there isn't one,
159                  *       whoever marked the "=" operator mergejoinable was a loser.
160                  * ----------------
161                  */
162                 optup = SearchSysCacheTuple(OPRNAME,
163                                                                         PointerGetDatum(replaceopname),
164                                                                         ObjectIdGetDatum(oprleft),
165                                                                         ObjectIdGetDatum(oprright),
166                                                                         CharGetDatum('b'));
167                 if (!HeapTupleIsValid(optup))
168                         elog(ERROR,
169                         "MJFormSkipQual: mergejoin operator %u has no matching %s op",
170                                  op->opno, replaceopname);
171                 opform = (Form_pg_operator) GETSTRUCT(optup);
172
173                 /* ----------------
174                  *       And replace the data in the copied operator node.
175                  * ----------------
176                  */
177                 op->opno = optup->t_data->t_oid;
178                 op->opid = opform->oprcode;
179                 op->op_fcache = NULL;
180         }
181
182         return qualCopy;
183 }
184
185 /* ----------------------------------------------------------------
186  *              MergeCompare
187  *
188  *              Compare the keys according to 'compareQual' which is of the
189  *              form: {(key1a > key2a)(key1b > key2b) ...}.
190  *
191  *              (actually, it could also be the form (key1a < key2a)..)
192  *
193  *              This is different from calling ExecQual because ExecQual returns
194  *              true only if ALL the comparisions clauses are satisfied.
195  *              However, there is an order of significance among the keys with
196  *              the first keys being most significant. Therefore, the clauses
197  *              are evaluated in order and the 'compareQual' is satisfied
198  *              if (key1i > key2i) is true and (key1j = key2j) for 0 < j < i.
199  *              We use the original mergeclause items to detect equality.
200  * ----------------------------------------------------------------
201  */
202 static bool
203 MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
204 {
205         List       *clause;
206         List       *eqclause;
207         Datum           const_value;
208         bool            isNull;
209         bool            isDone;
210
211         /* ----------------
212          *      if we have no compare qualification, return nil
213          * ----------------
214          */
215         if (compareQual == NIL)
216                 return false;
217
218         /* ----------------
219          *      for each pair of clauses, test them until
220          *      our compare conditions are satisified
221          * ----------------
222          */
223         eqclause = eqQual;
224         foreach(clause, compareQual)
225         {
226                 /* ----------------
227                  *       first test if our compare clause is satisified.
228                  *       if so then return true. ignore isDone, don't iterate in
229                  *       quals.
230                  * ----------------
231                  */
232                 const_value = (Datum)
233                         ExecEvalExpr((Node *) lfirst(clause), econtext, &isNull, &isDone);
234
235                 if (DatumGetInt32(const_value) != 0)
236                         return true;
237
238                 /* ----------------
239                  *       ok, the compare clause failed so we test if the keys
240                  *       are equal... if key1 != key2, we return false.
241                  *       otherwise key1 = key2 so we move on to the next pair of keys.
242                  *
243                  *       ignore isDone, don't iterate in quals.
244                  * ----------------
245                  */
246                 const_value = ExecEvalExpr((Node *) lfirst(eqclause),
247                                                                    econtext,
248                                                                    &isNull,
249                                                                    &isDone);
250
251                 if (DatumGetInt32(const_value) == 0)
252                         return false;
253                 eqclause = lnext(eqclause);
254         }
255
256         /* ----------------
257          *      if we get here then it means none of our key greater-than
258          *      conditions were satisified so we return false.
259          * ----------------
260          */
261         return false;
262 }
263
264 /* ----------------------------------------------------------------
265  *              ExecMergeTupleDump
266  *
267  *              This function is called through the MJ_dump() macro
268  *              when EXEC_MERGEJOINDEBUG is defined
269  * ----------------------------------------------------------------
270  */
271 #ifdef EXEC_MERGEJOINDEBUG
272 void
273                         ExecMergeTupleDumpInner(ExprContext *econtext);
274
275 void
276 ExecMergeTupleDumpInner(ExprContext *econtext)
277 {
278         TupleTableSlot *innerSlot;
279
280         printf("==== inner tuple ====\n");
281         innerSlot = econtext->ecxt_innertuple;
282         if (TupIsNull(innerSlot))
283                 printf("(nil)\n");
284         else
285                 MJ_debugtup(innerSlot->val,
286                                         innerSlot->ttc_tupleDescriptor);
287 }
288
289 void
290                         ExecMergeTupleDumpOuter(ExprContext *econtext);
291
292 void
293 ExecMergeTupleDumpOuter(ExprContext *econtext)
294 {
295         TupleTableSlot *outerSlot;
296
297         printf("==== outer tuple ====\n");
298         outerSlot = econtext->ecxt_outertuple;
299         if (TupIsNull(outerSlot))
300                 printf("(nil)\n");
301         else
302                 MJ_debugtup(outerSlot->val,
303                                         outerSlot->ttc_tupleDescriptor);
304 }
305
306 void ExecMergeTupleDumpMarked(ExprContext *econtext,
307                                                  MergeJoinState *mergestate);
308
309 void
310 ExecMergeTupleDumpMarked(ExprContext *econtext,
311                                                  MergeJoinState *mergestate)
312 {
313         TupleTableSlot *markedSlot;
314
315         printf("==== marked tuple ====\n");
316         markedSlot = mergestate->mj_MarkedTupleSlot;
317
318         if (TupIsNull(markedSlot))
319                 printf("(nil)\n");
320         else
321                 MJ_debugtup(markedSlot->val,
322                                         markedSlot->ttc_tupleDescriptor);
323 }
324
325 void
326                         ExecMergeTupleDump(ExprContext *econtext, MergeJoinState *mergestate);
327
328 void
329 ExecMergeTupleDump(ExprContext *econtext, MergeJoinState *mergestate)
330 {
331         printf("******** ExecMergeTupleDump ********\n");
332
333         ExecMergeTupleDumpInner(econtext);
334         ExecMergeTupleDumpOuter(econtext);
335         ExecMergeTupleDumpMarked(econtext, mergestate);
336
337         printf("******** \n");
338 }
339
340 #endif
341
342 /* ----------------------------------------------------------------
343  *              ExecMergeJoin
344  *
345  * old comments
346  *              Details of the merge-join routines:
347  *
348  *              (1) ">" and "<" operators
349  *
350  *              Merge-join is done by joining the inner and outer tuples satisfying
351  *              the join clauses of the form ((= outerKey innerKey) ...).
352  *              The join clauses is provided by the query planner and may contain
353  *              more than one (= outerKey innerKey) clauses (for composite key).
354  *
355  *              However, the query executor needs to know whether an outer
356  *              tuple is "greater/smaller" than an inner tuple so that it can
357  *              "synchronize" the two relations. For e.g., consider the following
358  *              relations:
359  *
360  *                              outer: (0 ^1 1 2 5 5 5 6 6 7)   current tuple: 1
361  *                              inner: (1 ^3 5 5 5 5 6)                 current tuple: 3
362  *
363  *              To continue the merge-join, the executor needs to scan both inner
364  *              and outer relations till the matching tuples 5. It needs to know
365  *              that currently inner tuple 3 is "greater" than outer tuple 1 and
366  *              therefore it should scan the outer relation first to find a
367  *              matching tuple and so on.
368  *
369  *              Therefore, when initializing the merge-join node, the executor
370  *              creates the "greater/smaller" clause by substituting the "="
371  *              operator in the join clauses with the corresponding ">" operator.
372  *              The opposite "smaller/greater" clause is formed by substituting "<".
373  *
374  *              Note: prior to v6.5, the relational clauses were formed using the
375  *              sort op used to sort the inner relation, which of course would fail
376  *              if the outer and inner keys were of different data types.
377  *              In the current code, we instead assume that operators named "<" and ">"
378  *              will do the right thing.  This should be true since the mergejoin "="
379  *              operator's pg_operator entry will have told the planner to sort by
380  *              "<" for each of the left and right sides.
381  *
382  *              (2) repositioning inner "cursor"
383  *
384  *              Consider the above relations and suppose that the executor has
385  *              just joined the first outer "5" with the last inner "5". The
386  *              next step is of course to join the second outer "5" with all
387  *              the inner "5's". This requires repositioning the inner "cursor"
388  *              to point at the first inner "5". This is done by "marking" the
389  *              first inner 5 and restore the "cursor" to it before joining
390  *              with the second outer 5. The access method interface provides
391  *              routines to mark and restore to a tuple.
392  * ----------------------------------------------------------------
393  */
394 TupleTableSlot *
395 ExecMergeJoin(MergeJoin *node)
396 {
397         EState     *estate;
398         MergeJoinState *mergestate;
399         ScanDirection direction;
400         List       *innerSkipQual;
401         List       *outerSkipQual;
402         List       *mergeclauses;
403         List       *qual;
404         bool            qualResult;
405         bool            compareResult;
406
407         Plan       *innerPlan;
408         TupleTableSlot *innerTupleSlot;
409
410         Plan       *outerPlan;
411         TupleTableSlot *outerTupleSlot;
412
413         ExprContext *econtext;
414
415 #ifdef ENABLE_OUTER_JOINS
416
417         /*
418          * These should be set from the expression context! - thomas
419          * 1999-02-20
420          */
421         static bool isLeftJoin = true;
422         static bool isRightJoin = false;
423
424 #endif
425
426         /* ----------------
427          *      get information from node
428          * ----------------
429          */
430         mergestate = node->mergestate;
431         estate = node->join.state;
432         direction = estate->es_direction;
433         innerPlan = innerPlan((Plan *) node);
434         outerPlan = outerPlan((Plan *) node);
435         econtext = mergestate->jstate.cs_ExprContext;
436         mergeclauses = node->mergeclauses;
437         qual = node->join.qual;
438
439         if (ScanDirectionIsForward(direction))
440         {
441                 outerSkipQual = mergestate->mj_OuterSkipQual;
442                 innerSkipQual = mergestate->mj_InnerSkipQual;
443         }
444         else
445         {
446                 outerSkipQual = mergestate->mj_InnerSkipQual;
447                 innerSkipQual = mergestate->mj_OuterSkipQual;
448         }
449
450         /* ----------------
451          *      ok, everything is setup.. let's go to work
452          * ----------------
453          */
454         if (mergestate->jstate.cs_TupFromTlist)
455         {
456                 TupleTableSlot *result;
457                 ProjectionInfo *projInfo;
458                 bool            isDone;
459
460                 projInfo = mergestate->jstate.cs_ProjInfo;
461                 result = ExecProject(projInfo, &isDone);
462                 if (!isDone)
463                         return result;
464         }
465         for (;;)
466         {
467                 /* ----------------
468                  *      get the current state of the join and do things accordingly.
469                  *      Note: The join states are highlighted with 32-* comments for
470                  *                improved readability.
471                  * ----------------
472                  */
473                 MJ_dump(econtext, mergestate);
474
475                 switch (mergestate->mj_JoinState)
476                 {
477
478                                 /*
479                                  * EXEC_MJ_INITIALIZE means that this is the first time
480                                  * ExecMergeJoin() has been called and so we have to
481                                  * initialize the inner, outer and marked tuples as well
482                                  * as various stuff in the expression context.
483                                  */
484                         case EXEC_MJ_INITIALIZE:
485                                 MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE\n");
486
487                                 /*
488                                  * Note: at this point, if either of our inner or outer
489                                  * tuples are nil, then the join ends immediately because
490                                  * we know one of the subplans is empty.
491                                  */
492                                 innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
493                                 if (TupIsNull(innerTupleSlot))
494                                 {
495                                         MJ_printf("ExecMergeJoin: **** inner tuple is nil ****\n");
496                                         return NULL;
497                                 }
498
499                                 outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
500                                 if (TupIsNull(outerTupleSlot))
501                                 {
502                                         MJ_printf("ExecMergeJoin: **** outer tuple is nil ****\n");
503                                         return NULL;
504                                 }
505
506                                 /* ----------------
507                                  *       store the inner and outer tuple in the merge state
508                                  * ----------------
509                                  */
510                                 econtext->ecxt_innertuple = innerTupleSlot;
511                                 econtext->ecxt_outertuple = outerTupleSlot;
512
513                                 mergestate->mj_MarkedTupleSlot->ttc_tupleDescriptor =
514                                         innerTupleSlot->ttc_tupleDescriptor;
515
516                                 /* ----------------
517                                  *      initialize merge join state to skip inner tuples.
518                                  * ----------------
519                                  */
520                                 mergestate->mj_JoinState = EXEC_MJ_SKIPINNER;
521                                 break;
522
523                                 /*
524                                  * EXEC_MJ_JOINMARK means we have just found a new outer
525                                  * tuple and a possible matching inner tuple. This is the
526                                  * case after the INITIALIZE, SKIPOUTER or SKIPINNER
527                                  * states.
528                                  */
529                         case EXEC_MJ_JOINMARK:
530                                 MJ_printf("ExecMergeJoin: EXEC_MJ_JOINMARK\n");
531                                 ExecMarkPos(innerPlan);
532
533                                 MarkInnerTuple(econtext->ecxt_innertuple, mergestate);
534
535                                 mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
536                                 break;
537
538                                 /*
539                                  * EXEC_MJ_JOINTEST means we have two tuples which might
540                                  * satisfy the merge clause, so we test them.
541                                  *
542                                  * If they do satisfy, then we join them and move on to the
543                                  * next inner tuple (EXEC_MJ_JOINTUPLES).
544                                  *
545                                  * If they do not satisfy then advance to next outer tuple.
546                                  */
547                         case EXEC_MJ_JOINTEST:
548                                 MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTEST\n");
549
550                                 qualResult = ExecQual((List *) mergeclauses, econtext);
551                                 MJ_DEBUG_QUAL(mergeclauses, qualResult);
552
553                                 if (qualResult)
554                                         mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
555                                 else
556                                         mergestate->mj_JoinState = EXEC_MJ_NEXTOUTER;
557                                 break;
558
559                                 /*
560                                  * EXEC_MJ_JOINTUPLES means we have two tuples which
561                                  * satisified the merge clause so we join them and then
562                                  * proceed to get the next inner tuple (EXEC_NEXT_INNER).
563                                  */
564                         case EXEC_MJ_JOINTUPLES:
565                                 MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTUPLES\n");
566                                 mergestate->mj_JoinState = EXEC_MJ_NEXTINNER;
567
568                                 qualResult = ExecQual((List *) qual, econtext);
569                                 MJ_DEBUG_QUAL(qual, qualResult);
570
571                                 if (qualResult)
572                                 {
573                                         /* ----------------
574                                          *      qualification succeeded.  now form the desired
575                                          *      projection tuple and return the slot containing it.
576                                          * ----------------
577                                          */
578                                         ProjectionInfo *projInfo;
579                                         TupleTableSlot *result;
580                                         bool            isDone;
581
582                                         MJ_printf("ExecMergeJoin: **** returning tuple ****\n");
583
584                                         projInfo = mergestate->jstate.cs_ProjInfo;
585
586                                         result = ExecProject(projInfo, &isDone);
587                                         mergestate->jstate.cs_TupFromTlist = !isDone;
588                                         return result;
589                                 }
590                                 break;
591
592                                 /*
593                                  * EXEC_MJ_NEXTINNER means advance the inner scan to the
594                                  * next tuple. If the tuple is not nil, we then proceed to
595                                  * test it against the join qualification.
596                                  */
597                         case EXEC_MJ_NEXTINNER:
598                                 MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTINNER\n");
599
600                                 /* ----------------
601                                  *      now we get the next inner tuple, if any
602                                  * ----------------
603                                  */
604                                 innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
605                                 MJ_DEBUG_PROC_NODE(innerTupleSlot);
606                                 econtext->ecxt_innertuple = innerTupleSlot;
607
608                                 if (TupIsNull(innerTupleSlot))
609                                         mergestate->mj_JoinState = EXEC_MJ_NEXTOUTER;
610                                 else
611                                         mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
612                                 break;
613
614                                 /*-------------------------------------------
615                                  * EXEC_MJ_NEXTOUTER means
616                                  *
617                                  *                              outer inner
618                                  * outer tuple -  5             5  - marked tuple
619                                  *                                5             5
620                                  *                                6             6  - inner tuple
621                                  *                                7             7
622                                  *
623                                  * we know we just bumped into the
624                                  * first inner tuple > current outer tuple
625                                  * so get a new outer tuple and then
626                                  * proceed to test it against the marked tuple
627                                  * (EXEC_MJ_TESTOUTER)
628                                  *------------------------------------------------
629                                  */
630                         case EXEC_MJ_NEXTOUTER:
631                                 MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTOUTER\n");
632
633                                 outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
634                                 MJ_DEBUG_PROC_NODE(outerTupleSlot);
635                                 econtext->ecxt_outertuple = outerTupleSlot;
636
637                                 /* ----------------
638                                  *      if the outer tuple is null then we know
639                                  *      we are done with the join
640                                  * ----------------
641                                  */
642                                 if (TupIsNull(outerTupleSlot))
643                                 {
644                                         MJ_printf("ExecMergeJoin: **** outer tuple is nil ****\n");
645                                         return NULL;
646                                 }
647
648                                 mergestate->mj_JoinState = EXEC_MJ_TESTOUTER;
649                                 break;
650
651                                 /*--------------------------------------------------------
652                                  * EXEC_MJ_TESTOUTER If the new outer tuple and the marked
653                                  * tuple satisfy the merge clause then we know we have
654                                  * duplicates in the outer scan so we have to restore the
655                                  * inner scan to the marked tuple and proceed to join the
656                                  * new outer tuples with the inner tuples (EXEC_MJ_JOINTEST)
657                                  *
658                                  * This is the case when
659                                  *                                                outer inner
660                                  *                                                      4         5  - marked tuple
661                                  *                       outer tuple -  5         5
662                                  *               new outer tuple -      5         5
663                                  *                                                      6         8  - inner tuple
664                                  *                                                      7        12
665                                  *
666                                  *                              new outer tuple = marked tuple
667                                  *
668                                  *              If the outer tuple fails the test, then we know we have
669                                  *              to proceed to skip outer tuples until outer >= inner
670                                  *              (EXEC_MJ_SKIPOUTER).
671                                  *
672                                  *              This is the case when
673                                  *
674                                  *                                                outer inner
675                                  *                                                      5         5  - marked tuple
676                                  *                       outer tuple -  5         5
677                                  *               new outer tuple -      6         8  - inner tuple
678                                  *                                                      7        12
679                                  *
680                                  *
681                                  *               new outer tuple > marked tuple
682                                  *
683                                  *---------------------------------------------------------
684                                  */
685                         case EXEC_MJ_TESTOUTER:
686                                 MJ_printf("ExecMergeJoin: EXEC_MJ_TESTOUTER\n");
687
688                                 /* ----------------
689                                  *      here we compare the outer tuple with the marked inner tuple
690                                  *      by using the marked tuple in place of the inner tuple.
691                                  * ----------------
692                                  */
693                                 innerTupleSlot = econtext->ecxt_innertuple;
694                                 econtext->ecxt_innertuple = mergestate->mj_MarkedTupleSlot;
695
696                                 qualResult = ExecQual((List *) mergeclauses, econtext);
697                                 MJ_DEBUG_QUAL(mergeclauses, qualResult);
698
699                                 if (qualResult)
700                                 {
701
702                                         /*
703                                          * the merge clause matched so now we juggle the slots
704                                          * back the way they were and proceed to JOINTEST.
705                                          *
706                                          * I can't understand why we have to go to JOINTEST and
707                                          * compare outer tuple with the same inner one again
708                                          * -> go to JOINTUPLES...        - vadim 02/27/98
709                                          */
710
711                                         ExecRestrPos(innerPlan);
712 #if 0
713                                         mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
714 #endif
715                                         mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
716
717                                 }
718                                 else
719                                 {
720                                         econtext->ecxt_innertuple = innerTupleSlot;
721                                         /* ----------------
722                                          *      if the inner tuple was nil and the new outer
723                                          *      tuple didn't match the marked outer tuple then
724                                          *      we may have the case:
725                                          *
726                                          *                       outer inner
727                                          *                         4     4      - marked tuple
728                                          * new outer - 5         4
729                                          *                         6    nil - inner tuple
730                                          *                         7
731                                          *
732                                          *      which means that all subsequent outer tuples will be
733                                          *      larger than our inner tuples.
734                                          * ----------------
735                                          */
736                                         if (TupIsNull(innerTupleSlot))
737                                         {
738 #ifdef ENABLE_OUTER_JOINS
739                                                 if (isLeftJoin)
740                                                 {
741                                                         /* continue on to null fill outer tuples */
742                                                         mergestate->mj_JoinState = EXEC_MJ_FILLOUTER;
743                                                         break;
744                                                 }
745 #endif
746                                                 MJ_printf("ExecMergeJoin: **** weird case 1 ****\n");
747                                                 return NULL;
748                                         }
749
750                                         /* continue on to skip outer tuples */
751                                         mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER;
752                                 }
753                                 break;
754
755                                 /*----------------------------------------------------------
756                                  * EXEC_MJ_SKIPOUTER means skip over tuples in the outer plan
757                                  * until we find an outer tuple > current inner tuple.
758                                  *
759                                  * For example:
760                                  *
761                                  *                              outer inner
762                                  *                                5             5
763                                  *                                5             5
764                                  * outer tuple -  6             8  - inner tuple
765                                  *                                7    12
766                                  *                                8    14
767                                  *
768                                  * we have to advance the outer scan
769                                  * until we find the outer 8.
770                                  *----------------------------------------------------------
771                                  */
772                         case EXEC_MJ_SKIPOUTER:
773                                 MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER\n");
774                                 /* ----------------
775                                  *      before we advance, make sure the current tuples
776                                  *      do not satisfy the mergeclauses.  If they do, then
777                                  *      we update the marked tuple and go join them.
778                                  * ----------------
779                                  */
780                                 qualResult = ExecQual((List *) mergeclauses, econtext);
781                                 MJ_DEBUG_QUAL(mergeclauses, qualResult);
782
783                                 if (qualResult)
784                                 {
785                                         ExecMarkPos(innerPlan);
786
787                                         MarkInnerTuple(econtext->ecxt_innertuple, mergestate);
788
789                                         mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
790                                         break;
791                                 }
792
793                                 /* ----------------
794                                  *      ok, now test the skip qualification
795                                  * ----------------
796                                  */
797                                 compareResult = MergeCompare(mergeclauses,
798                                                                                          outerSkipQual,
799                                                                                          econtext);
800
801                                 MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult);
802
803                                 /* ----------------
804                                  *      compareResult is true as long as we should
805                                  *      continue skipping tuples.
806                                  * ----------------
807                                  */
808                                 if (compareResult)
809                                 {
810 #ifdef ENABLE_OUTER_JOINS
811                                         /* ----------------
812                                          *      if this is a left or full outer join, then fill
813                                          * ----------------
814                                          */
815                                         if (isLeftJoin)
816                                         {
817                                                 mergestate->mj_JoinState = EXEC_MJ_FILLOUTER;
818                                                 break;
819                                         }
820 #endif
821
822                                         outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
823                                         MJ_DEBUG_PROC_NODE(outerTupleSlot);
824                                         econtext->ecxt_outertuple = outerTupleSlot;
825
826                                         /* ----------------
827                                          *      if the outer tuple is null then we know
828                                          *      we are done with the join
829                                          * ----------------
830                                          */
831                                         if (TupIsNull(outerTupleSlot))
832                                         {
833                                                 MJ_printf("ExecMergeJoin: **** outerTuple is nil ****\n");
834                                                 return NULL;
835                                         }
836                                         /* ----------------
837                                          *      otherwise test the new tuple against the skip qual.
838                                          *      (we remain in the EXEC_MJ_SKIPOUTER state)
839                                          * ----------------
840                                          */
841                                         break;
842                                 }
843
844                                 /* ----------------
845                                  *      now check the inner skip qual to see if we
846                                  *      should now skip inner tuples... if we fail the
847                                  *      inner skip qual, then we know we have a new pair
848                                  *      of matching tuples.
849                                  * ----------------
850                                  */
851                                 compareResult = MergeCompare(mergeclauses,
852                                                                                          innerSkipQual,
853                                                                                          econtext);
854
855                                 MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult);
856
857                                 if (compareResult)
858                                         mergestate->mj_JoinState = EXEC_MJ_SKIPINNER;
859                                 else
860                                         mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
861                                 break;
862
863                                 /*-----------------------------------------------------------
864                                  * EXEC_MJ_SKIPINNER means skip over tuples in the inner plan
865                                  * until we find an inner tuple > current outer tuple.
866                                  *
867                                  * For example:
868                                  *
869                                  *                              outer inner
870                                  *                                5             5
871                                  *                                5             5
872                                  * outer tuple - 12             8  - inner tuple
873                                  *                               14    10
874                                  *                               17    12
875                                  *
876                                  * we have to advance the inner scan
877                                  * until we find the inner 12.
878                                  *
879                                  *-------------------------------------------------------
880                                  */
881                         case EXEC_MJ_SKIPINNER:
882                                 MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER\n");
883                                 /* ----------------
884                                  *      before we advance, make sure the current tuples
885                                  *      do not satisfy the mergeclauses.  If they do, then
886                                  *      we update the marked tuple and go join them.
887                                  * ----------------
888                                  */
889                                 qualResult = ExecQual((List *) mergeclauses, econtext);
890                                 MJ_DEBUG_QUAL(mergeclauses, qualResult);
891
892                                 if (qualResult)
893                                 {
894                                         ExecMarkPos(innerPlan);
895
896                                         MarkInnerTuple(econtext->ecxt_innertuple, mergestate);
897
898                                         mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
899                                         break;
900                                 }
901
902                                 /* ----------------
903                                  *      ok, now test the skip qualification
904                                  * ----------------
905                                  */
906                                 compareResult = MergeCompare(mergeclauses,
907                                                                                          innerSkipQual,
908                                                                                          econtext);
909
910                                 MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult);
911
912                                 /* ----------------
913                                  *      compareResult is true as long as we should
914                                  *      continue skipping tuples.
915                                  * ----------------
916                                  */
917                                 if (compareResult)
918                                 {
919 #ifdef ENABLE_OUTER_JOINS
920                                         /* ----------------
921                                          *      if this is a right or full outer join, then fill
922                                          * ----------------
923                                          */
924                                         if (isRightJoin)
925                                         {
926                                                 mergestate->mj_JoinState = EXEC_MJ_FILLINNER;
927                                                 break;
928                                         }
929 #endif
930
931                                         /* ----------------
932                                          *      now try and get a new inner tuple
933                                          * ----------------
934                                          */
935                                         innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
936                                         MJ_DEBUG_PROC_NODE(innerTupleSlot);
937                                         econtext->ecxt_innertuple = innerTupleSlot;
938
939                                         /* ----------------
940                                          *      if the inner tuple is null then we know
941                                          *      we have to restore the inner scan
942                                          *      and advance to the next outer tuple
943                                          * ----------------
944                                          */
945                                         if (TupIsNull(innerTupleSlot))
946                                         {
947                                                 /* ----------------
948                                                  *      this is an interesting case.. all our
949                                                  *      inner tuples are smaller then our outer
950                                                  *      tuples so we never found an inner tuple
951                                                  *      to mark.
952                                                  *
953                                                  *                        outer inner
954                                                  *       outer tuple -  5         4
955                                                  *                                      5         4
956                                                  *                                      6        nil  - inner tuple
957                                                  *                                      7
958                                                  *
959                                                  *      This means the join should end.
960                                                  * ----------------
961                                                  */
962                                                 MJ_printf("ExecMergeJoin: **** weird case 2 ****\n");
963                                                 return NULL;
964                                         }
965
966                                         /* ----------------
967                                          *      otherwise test the new tuple against the skip qual.
968                                          *      (we remain in the EXEC_MJ_SKIPINNER state)
969                                          * ----------------
970                                          */
971                                         break;
972                                 }
973
974                                 /* ----------------
975                                  *      compare finally failed and we have stopped skipping
976                                  *      inner tuples so now check the outer skip qual
977                                  *      to see if we should now skip outer tuples...
978                                  * ----------------
979                                  */
980                                 compareResult = MergeCompare(mergeclauses,
981                                                                                          outerSkipQual,
982                                                                                          econtext);
983
984                                 MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult);
985
986                                 if (compareResult)
987                                         mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER;
988                                 else
989                                         mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
990
991                                 break;
992
993 #ifdef ENABLE_OUTER_JOINS
994
995                                 /*
996                                  * EXEC_MJ_FILLINNER means we have an unmatched inner
997                                  * tuple which must be null-expanded into the projection
998                                  * tuple. get the next inner tuple and reset markers
999                                  * (EXEC_MJ_JOINMARK).
1000                                  */
1001                         case EXEC_MJ_FILLINNER:
1002                                 MJ_printf("ExecMergeJoin: EXEC_MJ_FILLINNER\n");
1003                                 mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
1004
1005                                 /* ----------------
1006                                  *      project the inner tuple into the result
1007                                  * ----------------
1008                                  */
1009                                 MJ_printf("ExecMergeJoin: project inner tuple into the result (not yet implemented)\n");
1010
1011                                 /* ----------------
1012                                  *      now skip this inner tuple
1013                                  * ----------------
1014                                  */
1015                                 innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
1016                                 MJ_DEBUG_PROC_NODE(innerTupleSlot);
1017                                 econtext->ecxt_innertuple = innerTupleSlot;
1018
1019                                 /* ----------------
1020                                  *      if the inner tuple is null then we know
1021                                  *      we have to restore the inner scan
1022                                  *      and advance to the next outer tuple
1023                                  * ----------------
1024                                  */
1025                                 if (TupIsNull(innerTupleSlot))
1026                                 {
1027                                         if (isLeftJoin && !TupIsNull(outerTupleSlot))
1028                                         {
1029                                                 mergestate->mj_JoinState = EXEC_MJ_FILLOUTER;
1030                                                 MJ_printf("ExecMergeJoin: try to complete outer fill\n");
1031                                                 break;
1032                                         }
1033
1034                                         MJ_printf("ExecMergeJoin: **** weird case 2 ****\n");
1035                                         return NULL;
1036                                 }
1037
1038                                 /* ----------------
1039                                  *      otherwise test the new tuple against the skip qual.
1040                                  *      (we move to the EXEC_MJ_JOINMARK state)
1041                                  * ----------------
1042                                  */
1043                                 break;
1044
1045                                 /*
1046                                  * EXEC_MJ_FILLOUTER means we have an unmatched outer
1047                                  * tuple which must be null-expanded into the projection
1048                                  * tuple. get the next outer tuple and reset markers
1049                                  * (EXEC_MJ_JOINMARK).
1050                                  */
1051                         case EXEC_MJ_FILLOUTER:
1052                                 MJ_printf("ExecMergeJoin: EXEC_MJ_FILLOUTER\n");
1053                                 mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
1054
1055                                 /* ----------------
1056                                  *      project the outer tuple into the result
1057                                  * ----------------
1058                                  */
1059                                 MJ_printf("ExecMergeJoin: project outer tuple into the result (not yet implemented)\n");
1060
1061                                 /* ----------------
1062                                  *      now skip this outer tuple
1063                                  * ----------------
1064                                  */
1065                                 outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
1066                                 MJ_DEBUG_PROC_NODE(outerTupleSlot);
1067                                 econtext->ecxt_outertuple = outerTupleSlot;
1068
1069                                 /* ----------------
1070                                  *      if the outer tuple is null then we know
1071                                  *      we are done with the left half of the join
1072                                  * ----------------
1073                                  */
1074                                 if (TupIsNull(outerTupleSlot))
1075                                 {
1076                                         if (isRightJoin && !TupIsNull(innerTupleSlot))
1077                                         {
1078                                                 mergestate->mj_JoinState = EXEC_MJ_FILLINNER;
1079                                                 MJ_printf("ExecMergeJoin: try to complete inner fill\n");
1080                                                 break;
1081                                         }
1082
1083                                         MJ_printf("ExecMergeJoin: **** outerTuple is nil ****\n");
1084                                         return NULL;
1085                                 }
1086
1087                                 /* ----------------
1088                                  *      otherwise test the new tuple against the skip qual.
1089                                  *      (we move to the EXEC_MJ_JOINMARK state)
1090                                  * ----------------
1091                                  */
1092                                 break;
1093 #endif
1094
1095                                 /*
1096                                  * if we get here it means our code is fouled up and so we
1097                                  * just end the join prematurely.
1098                                  */
1099                         default:
1100                                 elog(NOTICE, "ExecMergeJoin: invalid join state. aborting");
1101                                 return NULL;
1102                 }
1103         }
1104 }
1105
1106 /* ----------------------------------------------------------------
1107  *              ExecInitMergeJoin
1108  *
1109  * old comments
1110  *              Creates the run-time state information for the node and
1111  *              sets the relation id to contain relevant decriptors.
1112  * ----------------------------------------------------------------
1113  */
1114 bool
1115 ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
1116 {
1117         MergeJoinState *mergestate;
1118         List       *joinclauses;
1119         TupleTableSlot *mjSlot;
1120
1121         MJ1_printf("ExecInitMergeJoin: %s\n",
1122                            "initializing node");
1123
1124         /* ----------------
1125          *      assign the node's execution state and
1126          *      get the range table and direction from it
1127          * ----------------
1128          */
1129         node->join.state = estate;
1130
1131         /* ----------------
1132          *      create new merge state for node
1133          * ----------------
1134          */
1135         mergestate = makeNode(MergeJoinState);
1136         mergestate->mj_OuterSkipQual = NIL;
1137         mergestate->mj_InnerSkipQual = NIL;
1138         mergestate->mj_JoinState = 0;
1139         mergestate->mj_MarkedTupleSlot = NULL;
1140         node->mergestate = mergestate;
1141
1142         /* ----------------
1143          *      Miscellaneous initialization
1144          *
1145          *               +      assign node's base_id
1146          *               +      assign debugging hooks and
1147          *               +      create expression context for node
1148          * ----------------
1149          */
1150         ExecAssignNodeBaseInfo(estate, &mergestate->jstate, parent);
1151         ExecAssignExprContext(estate, &mergestate->jstate);
1152
1153 #define MERGEJOIN_NSLOTS 2
1154         /* ----------------
1155          *      tuple table initialization
1156          * ----------------
1157          */
1158         ExecInitResultTupleSlot(estate, &mergestate->jstate);
1159         mjSlot = (TupleTableSlot *) palloc(sizeof(TupleTableSlot));
1160         mjSlot->val = NULL;
1161         mjSlot->ttc_shouldFree = true;
1162         mjSlot->ttc_tupleDescriptor = NULL;
1163         mjSlot->ttc_whichplan = -1;
1164         mjSlot->ttc_descIsNew = true;
1165         mergestate->mj_MarkedTupleSlot = mjSlot;
1166
1167         /* ----------------
1168          *      form merge skip qualifications
1169          * ----------------
1170          */
1171         joinclauses = node->mergeclauses;
1172         mergestate->mj_OuterSkipQual = MJFormSkipQual(joinclauses, "<");
1173         mergestate->mj_InnerSkipQual = MJFormSkipQual(joinclauses, ">");
1174
1175         MJ_printf("\nExecInitMergeJoin: OuterSkipQual is ");
1176         MJ_nodeDisplay(mergestate->mj_OuterSkipQual);
1177         MJ_printf("\nExecInitMergeJoin: InnerSkipQual is ");
1178         MJ_nodeDisplay(mergestate->mj_InnerSkipQual);
1179         MJ_printf("\n");
1180
1181         /* ----------------
1182          *      initialize join state
1183          * ----------------
1184          */
1185         mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;
1186
1187         /* ----------------
1188          *      initialize subplans
1189          * ----------------
1190          */
1191         ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
1192         ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
1193
1194         /* ----------------
1195          *      initialize tuple type and projection info
1196          * ----------------
1197          */
1198         ExecAssignResultTypeFromTL((Plan *) node, &mergestate->jstate);
1199         ExecAssignProjectionInfo((Plan *) node, &mergestate->jstate);
1200
1201         mergestate->jstate.cs_TupFromTlist = false;
1202         /* ----------------
1203          *      initialization successful
1204          * ----------------
1205          */
1206         MJ1_printf("ExecInitMergeJoin: %s\n",
1207                            "node initialized");
1208
1209         return TRUE;
1210 }
1211
1212 int
1213 ExecCountSlotsMergeJoin(MergeJoin *node)
1214 {
1215         return ExecCountSlotsNode(outerPlan((Plan *) node)) +
1216         ExecCountSlotsNode(innerPlan((Plan *) node)) +
1217         MERGEJOIN_NSLOTS;
1218 }
1219
1220 /* ----------------------------------------------------------------
1221  *              ExecEndMergeJoin
1222  *
1223  * old comments
1224  *              frees storage allocated through C routines.
1225  * ----------------------------------------------------------------
1226  */
1227 void
1228 ExecEndMergeJoin(MergeJoin *node)
1229 {
1230         MergeJoinState *mergestate;
1231
1232         MJ1_printf("ExecEndMergeJoin: %s\n",
1233                            "ending node processing");
1234
1235         /* ----------------
1236          *      get state information from the node
1237          * ----------------
1238          */
1239         mergestate = node->mergestate;
1240
1241         /* ----------------
1242          *      Free the projection info and the scan attribute info
1243          *
1244          *      Note: we don't ExecFreeResultType(mergestate)
1245          *                because the rule manager depends on the tupType
1246          *                returned by ExecMain().  So for now, this
1247          *                is freed at end-transaction time.  -cim 6/2/91
1248          * ----------------
1249          */
1250         ExecFreeProjectionInfo(&mergestate->jstate);
1251
1252         /* ----------------
1253          *      shut down the subplans
1254          * ----------------
1255          */
1256         ExecEndNode((Plan *) innerPlan((Plan *) node), (Plan *) node);
1257         ExecEndNode((Plan *) outerPlan((Plan *) node), (Plan *) node);
1258
1259         /* ----------------
1260          *      clean out the tuple table so that we don't try and
1261          *      pfree the marked tuples..  see HACK ALERT at the top of
1262          *      this file.
1263          * ----------------
1264          */
1265         ExecClearTuple(mergestate->jstate.cs_ResultTupleSlot);
1266         ExecClearTuple(mergestate->mj_MarkedTupleSlot);
1267         pfree(mergestate->mj_MarkedTupleSlot);
1268         mergestate->mj_MarkedTupleSlot = NULL;
1269
1270         MJ1_printf("ExecEndMergeJoin: %s\n",
1271                            "node processing ended");
1272 }
1273
1274 void
1275 ExecReScanMergeJoin(MergeJoin *node, ExprContext *exprCtxt, Plan *parent)
1276 {
1277         MergeJoinState *mergestate = node->mergestate;
1278         TupleTableSlot *mjSlot = mergestate->mj_MarkedTupleSlot;
1279
1280         ExecClearTuple(mjSlot);
1281         mjSlot->val = NULL;
1282         mjSlot->ttc_shouldFree = true;
1283         mjSlot->ttc_tupleDescriptor = NULL;
1284         mjSlot->ttc_whichplan = -1;
1285         mjSlot->ttc_descIsNew = true;
1286
1287         mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;
1288
1289         /*
1290          * if chgParam of subnodes is not null then plans will be re-scanned
1291          * by first ExecProcNode.
1292          */
1293         if (((Plan *) node)->lefttree->chgParam == NULL)
1294                 ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
1295         if (((Plan *) node)->righttree->chgParam == NULL)
1296                 ExecReScan(((Plan *) node)->righttree, exprCtxt, (Plan *) node);
1297
1298 }