KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > compile > HalfOuterJoinNode


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.HalfOuterJoinNode
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.sql.compile;
23
24 import org.apache.derby.iapi.services.context.ContextManager;
25
26 import org.apache.derby.iapi.services.compiler.MethodBuilder;
27
28 import org.apache.derby.iapi.services.sanity.SanityManager;
29
30 import org.apache.derby.iapi.error.StandardException;
31
32 import org.apache.derby.iapi.sql.compile.Optimizable;
33 import org.apache.derby.iapi.sql.compile.OptimizablePredicate;
34 import org.apache.derby.iapi.sql.compile.OptimizablePredicateList;
35 import org.apache.derby.iapi.sql.compile.Optimizer;
36 import org.apache.derby.iapi.sql.compile.CostEstimate;
37 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
38
39 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
40
41 import org.apache.derby.iapi.sql.Activation;
42 import org.apache.derby.iapi.sql.ResultSet;
43
44 import org.apache.derby.iapi.error.StandardException;
45
46 import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
47
48 import org.apache.derby.iapi.util.JBitSet;
49
50 import java.util.Properties JavaDoc;
51
52 /**
53  * An HalfOuterJoinNode represents a left or a right outer join result set.
54  * Right outer joins are always transformed into left outer joins during
55  * preprocessing for simplicity.
56  *
57  * @author Jerry Brenner
58  */

59
60 public class HalfOuterJoinNode extends JoinNode
61 {
62     private boolean rightOuterJoin;
63     private boolean transformed = false;
64
65     /**
66      * Initializer for a HalfOuterJoinNode.
67      *
68      * @param leftResult The ResultSetNode on the left side of this join
69      * @param rightResult The ResultSetNode on the right side of this join
70      * @param onClause The ON clause
71      * @param usingClause The USING clause
72      * @param rightOuterJoin Whether or not this node represents a user
73      * specified right outer join
74      * @param tableProperties Properties list associated with the table
75      *
76      * @exception StandardException Thrown on error
77      */

78
79     public void init(
80                             Object JavaDoc leftResult,
81                             Object JavaDoc rightResult,
82                             Object JavaDoc onClause,
83                             Object JavaDoc usingClause,
84                             Object JavaDoc rightOuterJoin,
85                             Object JavaDoc tableProperties)
86         throws StandardException
87     {
88         super.init(
89                 leftResult,
90                 rightResult,
91                 onClause,
92                 usingClause,
93                 null,
94                 tableProperties,
95                 null);
96         this.rightOuterJoin = ((Boolean JavaDoc) rightOuterJoin).booleanValue();
97
98         /* We can only flatten an outer join
99          * using the null intolerant predicate xform.
100          * In that case, we will return an InnerJoin.
101          */

102         flattenableJoin = false;
103     }
104
105     /*
106      * Optimizable interface
107      */

108
109     /**
110      * @see Optimizable#pushOptPredicate
111      *
112      * @exception StandardException Thrown on error
113      */

114
115     public boolean pushOptPredicate(OptimizablePredicate optimizablePredicate)
116             throws StandardException
117     {
118         /* We should never push the predicate to joinPredicates as in JoinNode. joinPredicates
119          * should only be predicates relating the two joining tables. In the case of half join,
120          * it is biased. If the general predicate (not join predicate) contains refernce to right
121          * result set, and if doesn't qualify, we shouldn't return the row for the result to be
122          * correct, but half join will fill right side NULL and return the row. So we can only
123          * push predicate to the left, as we do in "pushExpression". bug 5055
124          */

125         FromTable leftFromTable = (FromTable) leftResultSet;
126         if (leftFromTable.getReferencedTableMap().contains(optimizablePredicate.getReferencedMap()))
127             return leftFromTable.pushOptPredicate(optimizablePredicate);
128         return false;
129     }
130
131     /**
132      * Convert this object to a String. See comments in QueryTreeNode.java
133      * for how this should be done for tree printing.
134      *
135      * @return This object as a String
136      */

137
138     public String JavaDoc toString()
139     {
140         if (SanityManager.DEBUG)
141         {
142             return "rightOuterJoin: " + rightOuterJoin + "\n" +
143                 "transformed: " + transformed + "\n" +
144                 super.toString();
145         }
146         else
147         {
148             return "";
149         }
150     }
151
152     /**
153      * Put a ProjectRestrictNode on top of each FromTable in the FromList.
154      * ColumnReferences must continue to point to the same ResultColumn, so
155      * that ResultColumn must percolate up to the new PRN. However,
156      * that ResultColumn will point to a new expression, a VirtualColumnNode,
157      * which points to the FromTable and the ResultColumn that is the source for
158      * the ColumnReference.
159      * (The new PRN will have the original of the ResultColumnList and
160      * the ResultColumns from that list. The FromTable will get shallow copies
161      * of the ResultColumnList and its ResultColumns. ResultColumn.expression
162      * will remain at the FromTable, with the PRN getting a new
163      * VirtualColumnNode for each ResultColumn.expression.)
164      * We then project out the non-referenced columns. If there are no referenced
165      * columns, then the PRN's ResultColumnList will consist of a single ResultColumn
166      * whose expression is 1.
167      *
168      * @param numTables Number of tables in the DML Statement
169      * @param gbl The group by list, if any
170      * @param fromList The from list, if any
171      *
172      * @return The generated ProjectRestrictNode atop the original FromTable.
173      *
174      * @exception StandardException Thrown on error
175      */

176     public ResultSetNode preprocess(int numTables,
177                                     GroupByList gbl,
178                                     FromList fromList)
179                                 throws StandardException
180     {
181         ResultSetNode newTreeTop;
182
183         /* Transform right outer joins to the equivalent left outer join */
184         if (rightOuterJoin)
185         {
186             /* Verify that a user specifed right outer join is transformed into
187              * a left outer join exactly once.
188              */

189             if (SanityManager.DEBUG)
190             {
191                 SanityManager.ASSERT(! transformed,
192                     "Attempting to transform a right outer join multiple times");
193             }
194
195             ResultSetNode tmp = leftResultSet;
196
197             leftResultSet = rightResultSet;
198             rightResultSet = tmp;
199             transformed = true;
200         }
201         
202         newTreeTop = super.preprocess(numTables, gbl, fromList);
203
204         return newTreeTop;
205     }
206
207     /**
208      * Push expressions down to the first ResultSetNode which can do expression
209      * evaluation and has the same referenced table map.
210      * RESOLVE - This means only pushing down single table expressions to
211      * DistinctNodes today. Once we have a better understanding of how
212      * the optimizer will work, we can push down join clauses.
213      *
214      * @param outerPredicateList The PredicateList from the outer RS.
215      *
216      * @exception StandardException Thrown on error
217      */

218     public void pushExpressions(PredicateList outerPredicateList)
219                     throws StandardException
220     {
221         FromTable leftFromTable = (FromTable) leftResultSet;
222         FromTable rightFromTable = (FromTable) rightResultSet;
223
224         /* We only try to push single table predicates to the left.
225          * Pushing them to the right would give incorrect semantics.
226          * We use the logic for pushing down single table predicates here.
227          */

228         pushExpressionsToLeft(outerPredicateList);
229
230         /* Push the pushable outer join predicates to the right. This is done
231          * bottom up, hence at the end of this method, so that outer join
232          * conditions only get pushed down 1 level.
233          * We use the optimizer's logic for pushing down join clause here.
234          */

235         // Walk joinPredicates backwards due to possible deletes
236
for (int index = joinPredicates.size() - 1; index >= 0; index --)
237         {
238             Predicate predicate;
239
240             predicate = (Predicate) joinPredicates.elementAt(index);
241             if (! predicate.getPushable())
242             {
243                 continue;
244             }
245
246             getRightPredicateList().addPredicate(predicate);
247
248             /* Remove the matching predicate from the outer list */
249             joinPredicates.removeElementAt(index);
250         }
251
252         /* Recurse down both sides of tree */
253         PredicateList noPredicates =
254                         (PredicateList) getNodeFactory().getNode(
255                                             C_NodeTypes.PREDICATE_LIST,
256                                             getContextManager());
257         leftFromTable.pushExpressions(getLeftPredicateList());
258         rightFromTable.pushExpressions(noPredicates);
259     }
260
261     /**
262      * This method determines if (1) the query is a LOJ, and (2) if the LOJ is a candidate for
263      * reordering (i.e., linearization). The condition for LOJ linearization is:
264      * 1. only LOJ in the fromList, i.e., no INNER, no FULL JOINs, no ROJs
265      * 2. ON clause must be equality join between left and right operands and in CNF (i.e., AND is allowed)
266      */

267     public boolean LOJ_reorderable(int numTables)
268         throws StandardException
269     {
270         boolean anyChange = false;
271
272         ResultSetNode logicalLeftResultSet; // row-preserving side
273
ResultSetNode logicalRightResultSet; // null-producing side
274

275         // Figure out which is the row-preserving side and which is
276
// null-producing side.
277
if (rightOuterJoin)
278         { // right outer join
279
logicalLeftResultSet = rightResultSet;
280             logicalRightResultSet = leftResultSet;
281         }
282         else
283         {
284             logicalLeftResultSet = leftResultSet;
285             logicalRightResultSet = rightResultSet;
286         }
287         
288         // Redundantly normalize the ON predicate (it will also be called in preprocess()).
289
super.normExpressions();
290
291         // This is a very simple LOJ of base tables. Do nothing.
292
if (logicalLeftResultSet instanceof FromBaseTable &&
293             logicalRightResultSet instanceof FromBaseTable)
294             return anyChange;
295
296         // Recursively check if we can reordering LOJ, and build the table
297
// references. Note that joins may have been reordered and therefore the
298
// table references need to be recomputed.
299
if (logicalLeftResultSet instanceof HalfOuterJoinNode)
300         {
301             anyChange = ((HalfOuterJoinNode)logicalLeftResultSet).LOJ_reorderable(numTables) || anyChange;
302         }
303         else if (!(logicalLeftResultSet instanceof FromBaseTable))
304         {// left operand must be either a base table or another LOJ
305
// In principle, we don't care about the left operand. However, we
306
// need to re-bind the resultColumns. If the left operand is a
307
// view, we may have to re-bind the where clause etc...
308
// We ran into difficulty for the following query:
309
// create view v8 (cv, bv, av) as (select c, b, a from t union select f, e, d from s);
310
// select * from v8 left outer join (s left outer join r on (f = i)) on (e=v8.bv);
311
return anyChange;
312         }
313
314         if (logicalRightResultSet instanceof HalfOuterJoinNode)
315         {
316             anyChange = ((HalfOuterJoinNode)logicalRightResultSet).LOJ_reorderable(numTables) || anyChange;
317         }
318         else if (!(logicalRightResultSet instanceof FromBaseTable))
319         {// right operand must be either a base table or another LOJ
320
return anyChange;
321         }
322
323         // It is much easier to do LOJ reordering if there is no ROJ.
324
// However, we ran into some problem downstream when we transform an ROJ
325
// into LOJ -- transformOuterJoin() didn't expect ROJ to be transformed
326
// into LOJ alread. So, we skip optimizing ROJ at the moment.
327
if (rightOuterJoin || (logicalRightResultSet instanceof HalfOuterJoinNode &&
328                                ((HalfOuterJoinNode)logicalRightResultSet).rightOuterJoin))
329         {
330             return LOJ_bindResultColumns(anyChange);
331         }
332
333         // Build the data structure for testing/doing LOJ reordering.
334
// Fill in the table references on row-preserving and null-producing sides.
335
// It may be possible that either operand is a complex view.
336
JBitSet NPReferencedTableMap; // Null-producing
337
JBitSet RPReferencedTableMap; // Row-preserving
338

339         RPReferencedTableMap = logicalLeftResultSet.LOJgetReferencedTables(numTables);
340         NPReferencedTableMap = logicalRightResultSet.LOJgetReferencedTables(numTables);
341
342         if ((RPReferencedTableMap == null || NPReferencedTableMap == null) &&
343             anyChange)
344         {
345             return LOJ_bindResultColumns(anyChange);
346         }
347             
348         // Check if the predicate is equality predicate in CNF (i.e., AND only)
349
// and left/right column references must come from either operand.
350
// That is, we don't allow:
351
// 1. A=A
352
// 2. 1=1
353
// 3. B=C where both B and C are either from left or right operand.
354

355         // we probably need to make the joinClause "left-deep" so that we can
356
// walk it easier.
357
BinaryRelationalOperatorNode equals;
358         ValueNode leftCol;
359         ValueNode rightCol;
360         AndNode and;
361         ValueNode left;
362         ValueNode vn = joinClause;
363         while (vn instanceof AndNode)
364         {
365             and = (AndNode) vn;
366             left = and.getLeftOperand();
367
368             // Make sure that this is an equijoin of the form "C = D" where C
369
// and D references tables from both left and right operands.
370
if (left instanceof RelationalOperator &&
371                 ((ValueNode)left).isBinaryEqualsOperatorNode())
372             {
373                 equals = (BinaryRelationalOperatorNode) left;
374                 leftCol = equals.getLeftOperand();
375                 rightCol = equals.getRightOperand();
376
377                 if (!( leftCol instanceof ColumnReference && rightCol instanceof ColumnReference))
378                     return LOJ_bindResultColumns(anyChange);
379
380                 boolean refCheck = false;
381                 boolean leftOperandCheck = false;
382
383                 if (RPReferencedTableMap.get(((ColumnReference)leftCol).getTableNumber()))
384                 {
385                     refCheck = true;
386                     leftOperandCheck = true;
387                 }
388                 else if (NPReferencedTableMap.get(((ColumnReference)leftCol).getTableNumber()))
389                 {
390                     refCheck = true;
391                 }
392
393                 if (refCheck == false)
394                     return LOJ_bindResultColumns(anyChange);
395
396                 refCheck = false;
397                 if (leftOperandCheck == false && RPReferencedTableMap.get(((ColumnReference)rightCol).getTableNumber()))
398                 {
399                     refCheck = true;
400                 }
401                 else if (leftOperandCheck == true && NPReferencedTableMap.get(((ColumnReference)rightCol).getTableNumber()))
402                 {
403                     refCheck = true;
404                 }
405
406                 if (refCheck == false)
407                     return LOJ_bindResultColumns(anyChange);
408             }
409             else return LOJ_bindResultColumns(anyChange); // get out of here
410

411             vn = and.getRightOperand();
412         }
413
414         // Check if the logical right resultset is a composite inner and as such
415
// that this current LOJ can be pushed through it.
416
boolean push = false;
417         // logical right operand is another LOJ... so we may be able to push the
418
// join
419
if (logicalRightResultSet instanceof HalfOuterJoinNode)
420         {
421             // get the Null-producing operand of the child
422
JBitSet logicalNPRefTableMap = ((HalfOuterJoinNode)logicalRightResultSet).LOJgetNPReferencedTables(numTables);
423
424             // does the current LOJ join predicate reference
425
// logicalNPRefTableMap? If not, we can push the current
426
// join.
427
vn = joinClause;
428             push = true;
429             while (vn instanceof AndNode)
430             {
431                 and = (AndNode) vn;
432                 left = and.getLeftOperand();
433                 equals = (BinaryRelationalOperatorNode) left;
434                 leftCol = equals.getLeftOperand();
435                 rightCol = equals.getRightOperand();
436
437                 if (logicalNPRefTableMap.get(((ColumnReference)leftCol).getTableNumber()) ||
438                     logicalNPRefTableMap.get(((ColumnReference)rightCol).getTableNumber()))
439                 {
440                     push = false;
441                     break;
442                 }
443
444                 vn = and.getRightOperand();
445             }
446         }
447
448         // Push the current LOJ into the next level
449
if (push)
450         {
451             // For safety, check the JoinNode data members: they should null or
452
// empty list before we proceed.
453
if (super.subqueryList.size() != 0 ||
454                 ((JoinNode)logicalRightResultSet).subqueryList.size() != 0 ||
455                 super.joinPredicates.size() != 0 ||
456                 ((JoinNode)logicalRightResultSet).joinPredicates.size() != 0 ||
457                 super.usingClause != null ||
458                 ((JoinNode)logicalRightResultSet).usingClause != null)
459                 return LOJ_bindResultColumns(anyChange); // get out of here
460

461             anyChange = true; // we are reordering the LOJs.
462

463             ResultSetNode tmp = logicalLeftResultSet;
464             ResultSetNode LChild, RChild;
465
466             // this LOJ
467
// / \
468
// logicalLeftRS LogicalRightRS
469
// / \
470
// LChild RChild
471
// becomes
472
//
473
// this LOJ
474
// / \
475
// LogicalRightRS RChild
476
// / \
477
// logicalLeftRS LChild <<< we need to be careful about this order
478
// as the "LogicalRightRS may be a ROJ
479
//
480

481             // handle the lower level LOJ node
482
LChild = ((HalfOuterJoinNode)logicalRightResultSet).leftResultSet;
483             RChild = ((HalfOuterJoinNode)logicalRightResultSet).rightResultSet;
484
485             ((HalfOuterJoinNode)logicalRightResultSet).rightResultSet = LChild;
486             ((HalfOuterJoinNode)logicalRightResultSet).leftResultSet = tmp;
487
488             // switch the ON clause
489
vn = joinClause;
490             joinClause = ((HalfOuterJoinNode)logicalRightResultSet).joinClause;
491             ((HalfOuterJoinNode)logicalRightResultSet).joinClause = vn;
492
493             // No need to switch HalfOuterJoinNode data members for now because
494
// we are handling only LOJ.
495
// boolean local_rightOuterJoin = rightOuterJoin;
496
// boolean local_transformed = transformed;
497
// rightOuterJoin = ((HalfOuterJoinNode)logicalRightResultSet).rightOuterJoin;
498
// transformed = ((HalfOuterJoinNode)logicalRightResultSet).transformed;
499
// ((HalfOuterJoinNode)logicalRightResultSet).rightOuterJoin = local_rightOuterJoin;
500
// ((HalfOuterJoinNode)logicalRightResultSet).transformed = local_transformed;
501

502             FromList localFromList = (FromList) getNodeFactory().getNode(
503                                                                          C_NodeTypes.FROM_LIST,
504                                                                          getNodeFactory().doJoinOrderOptimization(),
505                                                                          getContextManager());
506
507             // switch LOJ nodes: by handling the current LOJ node
508
leftResultSet = logicalRightResultSet;
509             rightResultSet = RChild;
510
511             // rebuild the result columns and re-bind column references
512
((HalfOuterJoinNode)leftResultSet).resultColumns = null;
513             ((JoinNode)leftResultSet).bindResultColumns(localFromList); // localFromList is empty
514

515             // left operand must be another LOJ, try again until a fixpoint
516
boolean localChange = ((HalfOuterJoinNode)leftResultSet).LOJ_reorderable(numTables);
517
518             // rebuild the result columns and re-bind column references for 'this'
519
return LOJ_bindResultColumns(anyChange);
520         }
521
522         return LOJ_bindResultColumns(anyChange);
523     }
524
525     // This method re-binds the result columns which may be referenced in the ON
526
// clause in this node.
527
public boolean LOJ_bindResultColumns(boolean anyChange)
528         throws StandardException
529     {
530         if (anyChange)
531         {
532             this.resultColumns = null;
533             FromList localFromList = (FromList) getNodeFactory().getNode(C_NodeTypes.FROM_LIST,
534                                                                          getNodeFactory().doJoinOrderOptimization(),
535                                                                          getContextManager());
536             ((JoinNode)this).bindResultColumns(localFromList);
537         }
538         return anyChange;
539     }
540     
541
542     /**
543      * Transform any Outer Join into an Inner Join where applicable.
544      * (Based on the existence of a null intolerant
545      * predicate on the inner table.)
546      *
547      * @param predicateTree The predicate tree for the query block
548      *
549      * @return The new tree top (OuterJoin or InnerJoin).
550      *
551      * @exception StandardException Thrown on error
552      */

553     public FromTable transformOuterJoins(ValueNode predicateTree, int numTables)
554         throws StandardException
555     {
556         ResultSetNode innerRS;
557
558         if (predicateTree == null)
559         {
560             /* We can't transform this node, so tell both sides of the
561              * outer join that they can't get flattened into outer query block.
562              */

563             leftResultSet.notFlattenableJoin();
564             rightResultSet.notFlattenableJoin();
565             return this;
566         }
567
568         super.transformOuterJoins(predicateTree, numTables);
569
570         JBitSet innerMap = new JBitSet(numTables);
571         if (rightOuterJoin)
572         {
573             if (SanityManager.DEBUG)
574             {
575                 SanityManager.ASSERT(! transformed,
576                     "right OJ not expected to be transformed into left OJ yet");
577             }
578             innerRS = leftResultSet;
579         }
580         else
581         {
582             innerRS = rightResultSet;
583         }
584
585         innerRS.fillInReferencedTableMap(innerMap);
586
587         /* Walk predicates looking for
588          * a null intolerant predicate on the inner table.
589          */

590         ValueNode vn = predicateTree;
591         while (vn instanceof AndNode)
592         {
593             AndNode and = (AndNode) vn;
594             ValueNode left = and.getLeftOperand();
595
596             /* Skip IS NULL predicates as they are not null intolerant */
597             if (left.isInstanceOf(C_NodeTypes.IS_NULL_NODE))
598             {
599                 vn = and.getRightOperand();
600                 continue;
601             }
602
603             /* Only consider predicates that are relops */
604             if (left instanceof RelationalOperator)
605             {
606                 JBitSet refMap = new JBitSet(numTables);
607                 /* Do not consider method calls,
608                  * conditionals, field references, etc. */

609                 if (! (left.categorize(refMap, true)))
610                 {
611                     vn = and.getRightOperand();
612                     continue;
613                 }
614
615                 /* If the predicate is a null intolerant predicate
616                  * on the right side then we can flatten to an
617                  * inner join. We do the xform here, flattening
618                  * will happen later.
619                  */

620                 for (int bit = 0; bit < numTables; bit++)
621                 {
622                     if (refMap.get(bit) && innerMap.get(bit))
623                     {
624                         // OJ -> IJ
625
JoinNode ij = (JoinNode)
626                                             getNodeFactory().getNode(
627                                                 C_NodeTypes.JOIN_NODE,
628                                                 leftResultSet,
629                                                 rightResultSet,
630                                                 joinClause,
631                                                 null,
632                                                 resultColumns,
633                                                 null,
634                                                 null,
635                                                 getContextManager());
636                         ij.setTableNumber(tableNumber);
637                         ij.setSubqueryList(subqueryList);
638                         ij.setAggregateVector(aggregateVector);
639                         return ij;
640                     }
641                 }
642             }
643
644             vn = and.getRightOperand();
645         }
646
647         /* We can't transform this node, so tell both sides of the
648          * outer join that they can't get flattened into outer query block.
649          */

650         leftResultSet.notFlattenableJoin();
651         rightResultSet.notFlattenableJoin();
652
653         return this;
654     }
655
656     /** @see JoinNode#adjustNumberOfRowsReturned */
657     protected void adjustNumberOfRowsReturned(CostEstimate costEstimate)
658     {
659         /*
660         ** An outer join returns at least as many rows as in the outer
661         ** table. Even if this started as a right outer join, it will
662         ** have been transformed to a left outer join by this point.
663         */

664         CostEstimate outerCost = getLeftResultSet().getCostEstimate();
665
666         if (costEstimate.rowCount() < outerCost.rowCount())
667         {
668             costEstimate.setCost(costEstimate.getEstimatedCost(),
669                                  outerCost.rowCount(),
670                                  outerCost.rowCount());
671         }
672     }
673
674     /**
675      * Generate the code for an inner join node.
676      *
677      * @exception StandardException Thrown on error
678      */

679     public void generate(ActivationClassBuilder acb,
680                                 MethodBuilder mb)
681                         throws StandardException
682     {
683         /* Verify that a user specifed right outer join is transformed into
684          * a left outer join exactly once.
685          */

686         if (SanityManager.DEBUG)
687         {
688             SanityManager.ASSERT(rightOuterJoin == transformed,
689                 "rightOuterJoin (" + rightOuterJoin +
690                 ") is expected to equal transformed (" + transformed + ")");
691         }
692         super.generateCore(acb, mb, LEFTOUTERJOIN);
693     }
694
695     /**
696      * Generate and add any arguments specifict to outer joins.
697      * Generate the methods (and add them as parameters) for
698      * returning an empty row from 1 or more sides of an outer join,
699      * if required. Pass whether or not this was originally a
700      * right outer join.
701      *
702      * @param acb The ActivationClassBuilder
703      * @param mb the method the generate code is to go into
704      *
705      * return The args that have been added
706      *
707      * @exception StandardException Thrown on error
708      */

709      protected int addOuterJoinArguments(ActivationClassBuilder acb,
710                                             MethodBuilder mb)
711          throws StandardException
712      {
713         /* Nulls always generated from the right */
714         rightResultSet.getResultColumns().generateNulls(acb, mb);
715
716         /* Was this originally a right outer join? */
717         mb.push(rightOuterJoin);
718
719         return 2;
720      }
721
722     /**
723      * Return the number of arguments to the join result set.
724      */

725     protected int getNumJoinArguments()
726     {
727         /* We add two more arguments than the superclass does */
728         return super.getNumJoinArguments() + 2;
729     }
730
731     protected void oneRowRightSide(ActivationClassBuilder acb,
732                                        MethodBuilder mb)
733     {
734         // always return false for now
735
mb.push(false);
736         mb.push(false); //isNotExists?
737
}
738
739     /**
740      * Return the logical left result set for this qualified
741      * join node.
742      * (For RIGHT OUTER JOIN, the left is the right
743      * and the right is the left and the JOIN is the NIOJ).
744      */

745     ResultSetNode getLogicalLeftResultSet()
746     {
747         if (rightOuterJoin)
748         {
749             return rightResultSet;
750         }
751         else
752         {
753             return leftResultSet;
754         }
755     }
756
757     /**
758      * Return the logical right result set for this qualified
759      * join node.
760      * (For RIGHT OUTER JOIN, the left is the right
761      * and the right is the left and the JOIN is the NIOJ).
762      */

763     ResultSetNode getLogicalRightResultSet()
764     {
765         if (rightOuterJoin)
766         {
767             return leftResultSet;
768         }
769         else
770         {
771             return rightResultSet;
772         }
773     }
774
775     /**
776      * Return true if right outer join or false if left outer join
777      * Used to set Nullability correctly in JoinNode
778      */

779     public boolean isRightOuterJoin()
780     {
781         return rightOuterJoin;
782     }
783
784     // return the Null-producing table references
785
public JBitSet LOJgetNPReferencedTables(int numTables)
786                 throws StandardException
787     {
788         if (rightOuterJoin && !transformed)
789             return (JBitSet) leftResultSet.LOJgetReferencedTables(numTables);
790         else
791             return (JBitSet) rightResultSet.LOJgetReferencedTables(numTables);
792     }
793 }
794
Popular Tags