KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.TableOperatorNode
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.sanity.SanityManager;
27
28 import org.apache.derby.iapi.error.StandardException;
29
30 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
31 import org.apache.derby.iapi.sql.compile.CompilerContext;
32 import org.apache.derby.iapi.sql.compile.Optimizable;
33 import org.apache.derby.iapi.sql.compile.Visitable;
34 import org.apache.derby.iapi.sql.compile.Visitor;
35 import org.apache.derby.iapi.sql.compile.Optimizer;
36 import org.apache.derby.iapi.sql.compile.OptimizableList;
37 import org.apache.derby.iapi.sql.compile.CostEstimate;
38 import org.apache.derby.iapi.sql.compile.OptimizerFactory;
39 import org.apache.derby.iapi.sql.compile.RequiredRowOrdering;
40 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
41
42 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
43 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
44
45 import org.apache.derby.iapi.util.JBitSet;
46
47 import java.util.Properties JavaDoc;
48
49 /**
50  * A TableOperatorNode represents a relational operator like UNION, INTERSECT,
51  * JOIN, etc. that takes two tables as parameters and returns a table. The
52  * parameters it takes are represented as ResultSetNodes.
53  *
54  * Currently, all known table operators are binary operators, so there are no
55  * subclasses of this node type called "BinaryTableOperatorNode" and
56  * "UnaryTableOperatorNode".
57  *
58  * @author Jeff Lichtman
59  */

60
61 abstract class TableOperatorNode extends FromTable
62 {
63     ResultSetNode leftResultSet;
64     ResultSetNode rightResultSet;
65     Optimizer leftOptimizer;
66     Optimizer rightOptimizer;
67     private boolean leftModifyAccessPathsDone;
68     private boolean rightModifyAccessPathsDone;
69
70     /**
71      * Initializer for a TableOperatorNode.
72      *
73      * @param leftResultSet The ResultSetNode on the left side of this node
74      * @param rightResultSet The ResultSetNode on the right side of this node
75      * @param tableProperties Properties list associated with the table
76      *
77      * @exception StandardException Thrown on error
78      */

79     public void init(Object JavaDoc leftResultSet,
80                              Object JavaDoc rightResultSet,
81                              Object JavaDoc tableProperties)
82                 throws StandardException
83     {
84         /* correlationName is always null */
85         init(null, tableProperties);
86         this.leftResultSet = (ResultSetNode) leftResultSet;
87         this.rightResultSet = (ResultSetNode) rightResultSet;
88     }
89
90     /**
91      * @see Optimizable#modifyAccessPath
92      *
93      * @exception StandardException Thrown on error
94      */

95     public Optimizable modifyAccessPath(JBitSet outerTables) throws StandardException
96     {
97         boolean callModifyAccessPaths = false;
98
99         if (leftResultSet instanceof FromTable)
100         {
101             if (leftOptimizer != null)
102                 leftOptimizer.modifyAccessPaths();
103             else
104             {
105                 leftResultSet =
106                     (ResultSetNode)
107                         ((FromTable) leftResultSet).modifyAccessPath(outerTables);
108             }
109             leftModifyAccessPathsDone = true;
110         }
111         else
112         {
113             callModifyAccessPaths = true;
114         }
115
116         if (rightResultSet instanceof FromTable)
117         {
118             if (rightOptimizer != null)
119                 rightOptimizer.modifyAccessPaths();
120             else
121             {
122                 rightResultSet =
123                     (ResultSetNode)
124                         ((FromTable) rightResultSet).modifyAccessPath(outerTables);
125             }
126             rightModifyAccessPathsDone = true;
127         }
128         else
129         {
130             callModifyAccessPaths = true;
131         }
132
133         if (callModifyAccessPaths)
134         {
135             return (Optimizable) modifyAccessPaths();
136         }
137         return this;
138     }
139
140     /** @see Optimizable#verifyProperties
141      * @exception StandardException Thrown on error
142      */

143     public void verifyProperties(DataDictionary dDictionary)
144         throws StandardException
145     {
146         if (leftResultSet instanceof Optimizable)
147         {
148             ((Optimizable) leftResultSet).verifyProperties(dDictionary);
149         }
150         if (rightResultSet instanceof Optimizable)
151         {
152             ((Optimizable) rightResultSet).verifyProperties(dDictionary);
153         }
154
155         super.verifyProperties(dDictionary);
156     }
157
158     /**
159      * @see Optimizable#updateBestPlanMap
160      *
161      * Makes a call to add/load/remove the plan mapping for this node,
162      * and then makes the necessary call to recurse on this node's
163      * left and right child, in order to ensure that we've handled
164      * the full plan all the way down this node's subtree.
165      */

166     public void updateBestPlanMap(short action,
167         Object JavaDoc planKey) throws StandardException
168     {
169         super.updateBestPlanMap(action, planKey);
170
171         // Now walk the children. Note that if either child is not
172
// an Optimizable and the call to child.getOptimizerImpl()
173
// returns null, then that means we haven't tried to optimize
174
// the child yet. So in that case there's nothing to
175
// add/load.
176

177         if (leftResultSet instanceof Optimizable)
178         {
179             ((Optimizable)leftResultSet).
180                 updateBestPlanMap(action, planKey);
181         }
182         else if (leftResultSet.getOptimizerImpl() != null)
183         {
184             leftResultSet.getOptimizerImpl().
185                 updateBestPlanMaps(action, planKey);
186         }
187
188         if (rightResultSet instanceof Optimizable)
189         {
190             ((Optimizable)rightResultSet).
191                 updateBestPlanMap(action, planKey);
192         }
193         else if (rightResultSet.getOptimizerImpl() != null)
194         {
195             rightResultSet.getOptimizerImpl().
196                 updateBestPlanMaps(action, planKey);
197         }
198     }
199
200     /**
201      * Convert this object to a String. See comments in QueryTreeNode.java
202      * for how this should be done for tree printing.
203      *
204      * @return This object as a String
205      */

206
207     public String JavaDoc toString()
208     {
209         if (SanityManager.DEBUG)
210         {
211             return "nestedInParens: " + false + "\n" +
212                 leftResultSet.toString() + "\n" +
213                 rightResultSet.toString() + "\n" +
214                 super.toString();
215         }
216         else
217         {
218             return "";
219         }
220     }
221
222     /**
223      * Prints the sub-nodes of this object. See QueryTreeNode.java for
224      * how tree printing is supposed to work.
225      *
226      * @param depth The depth of this node in the tree
227      */

228
229     public void printSubNodes(int depth)
230     {
231         if (SanityManager.DEBUG)
232         {
233             super.printSubNodes(depth);
234
235             if (leftResultSet != null)
236             {
237                 printLabel(depth, "leftResultSet: ");
238                 leftResultSet.printSubNodes(depth + 1);
239             }
240
241             if (rightResultSet != null)
242             {
243                 printLabel(depth, "rightResultSet: ");
244                 rightResultSet.printSubNodes(depth + 1);
245             }
246         }
247     }
248
249     /**
250      * Get the leftResultSet from this node.
251      *
252      * @return ResultSetNode The leftResultSet from this node.
253      */

254     public ResultSetNode getLeftResultSet()
255     {
256         return leftResultSet;
257     }
258
259     /**
260      * Get the rightResultSet from this node.
261      *
262      * @return ResultSetNode The rightResultSet from this node.
263      */

264     public ResultSetNode getRightResultSet()
265     {
266         return rightResultSet;
267     }
268
269     public ResultSetNode getLeftmostResultSet()
270     {
271         if (leftResultSet instanceof TableOperatorNode)
272         {
273             return ((TableOperatorNode) leftResultSet).getLeftmostResultSet();
274         }
275         else
276         {
277             return leftResultSet;
278         }
279     }
280
281     public void setLeftmostResultSet(ResultSetNode newLeftResultSet)
282     {
283         if (leftResultSet instanceof TableOperatorNode)
284         {
285             ((TableOperatorNode) leftResultSet).setLeftmostResultSet(newLeftResultSet);
286         }
287         else
288         {
289             this.leftResultSet = newLeftResultSet;
290         }
291     }
292
293     /**
294      * Set the (query block) level (0-based) for this FromTable.
295      *
296      * @param level The query block level for this FromTable.
297      */

298     public void setLevel(int level)
299     {
300         super.setLevel(level);
301         if (leftResultSet instanceof FromTable)
302         {
303             ((FromTable) leftResultSet).setLevel(level);
304         }
305         if (rightResultSet instanceof FromTable)
306         {
307             ((FromTable) rightResultSet).setLevel(level);
308         }
309     }
310
311     /**
312      * Return the exposed name for this table, which is the name that
313      * can be used to refer to this table in the rest of the query.
314      *
315      * @return The exposed name for this table.
316      */

317
318     public String JavaDoc getExposedName()
319     {
320         return null;
321     }
322
323     /**
324      * Mark whether or not this node is nested in parens. (Useful to parser
325      * since some trees get created left deep and others right deep.)
326      * The resulting state of this cal was never used so its
327      * field was removed to save runtimespace for this node.
328      * Further cleanup can be done including parser changes
329      * if this call is really nor required.
330      *
331      * @param nestedInParens Whether or not this node is nested in parens.
332      */

333     public void setNestedInParens(boolean nestedInParens)
334     {
335     }
336
337
338     /**
339      * Bind the non VTI tables in this TableOperatorNode. This means getting
340      * their TableDescriptors from the DataDictionary.
341      * We will build an unbound RCL for this node. This RCL must be
342      * "bound by hand" after the underlying left and right RCLs
343      * are bound.
344      *
345      * @param dataDictionary The DataDictionary to use for binding
346      * @param fromListParam FromList to use/append to.
347      *
348      * @return ResultSetNode Returns this.
349      *
350      * @exception StandardException Thrown on error
351      */

352
353     public ResultSetNode bindNonVTITables(DataDictionary dataDictionary,
354                           FromList fromListParam)
355                             throws StandardException
356     {
357         leftResultSet = leftResultSet.bindNonVTITables(dataDictionary, fromListParam);
358         rightResultSet = rightResultSet.bindNonVTITables(dataDictionary, fromListParam);
359         /* Assign the tableNumber */
360         if (tableNumber == -1) // allow re-bind, in which case use old number
361
tableNumber = getCompilerContext().getNextTableNumber();
362
363         return this;
364     }
365
366     /**
367      * Bind the VTI tables in this TableOperatorNode. This means getting
368      * their TableDescriptors from the DataDictionary.
369      * We will build an unbound RCL for this node. This RCL must be
370      * "bound by hand" after the underlying left and right RCLs
371      * are bound.
372      *
373      * @param fromListParam FromList to use/append to.
374      *
375      * @return ResultSetNode Returns this.
376      *
377      * @exception StandardException Thrown on error
378      */

379
380     public ResultSetNode bindVTITables(FromList fromListParam)
381                             throws StandardException
382     {
383         leftResultSet = leftResultSet.bindVTITables(fromListParam);
384         rightResultSet = rightResultSet.bindVTITables(fromListParam);
385
386         return this;
387     }
388
389     /**
390      * Bind the expressions under this TableOperatorNode. This means
391      * binding the sub-expressions, as well as figuring out what the
392      * return type is for each expression.
393      *
394      * @exception StandardException Thrown on error
395      */

396
397     public void bindExpressions(FromList fromListParam)
398                 throws StandardException
399     {
400         /*
401         ** Parameters not allowed in select list of either side of union,
402         ** except when the union is for a table constructor.
403         */

404         if ( ! (this instanceof UnionNode) ||
405              ! ((UnionNode) this).tableConstructor())
406         {
407             leftResultSet.rejectParameters();
408             rightResultSet.rejectParameters();
409         }
410
411         leftResultSet.bindExpressions(fromListParam);
412         rightResultSet.bindExpressions(fromListParam);
413     }
414
415     /**
416      * Check for (and reject) ? parameters directly under the ResultColumns.
417      * This is done for SELECT statements. For TableOperatorNodes, we
418      * simply pass the check through to the left and right children.
419      *
420      * @exception StandardException Thrown if a ? parameter found
421      * directly under a ResultColumn
422      */

423
424     public void rejectParameters() throws StandardException
425     {
426         leftResultSet.rejectParameters();
427         rightResultSet.rejectParameters();
428     }
429
430     /**
431      * Bind the expressions in this ResultSetNode if it has tables. This means binding the
432      * sub-expressions, as well as figuring out what the return type is for
433      * each expression.
434      *
435      * @param fromListParam FromList to use/append to.
436      *
437      * @exception StandardException Thrown on error
438      */

439     public void bindExpressionsWithTables(FromList fromListParam)
440                     throws StandardException
441     {
442         /*
443         ** Parameters not allowed in select list of either side of a set operator,
444         ** except when the set operator is for a table constructor.
445         */

446         if ( ! (this instanceof UnionNode) ||
447              ! ((UnionNode) this).tableConstructor())
448         {
449             leftResultSet.rejectParameters();
450             rightResultSet.rejectParameters();
451         }
452
453         leftResultSet.bindExpressionsWithTables(fromListParam);
454         rightResultSet.bindExpressionsWithTables(fromListParam);
455     }
456
457     /**
458      * Bind the result columns of this ResultSetNode when there is no
459      * base table to bind them to. This is useful for SELECT statements,
460      * where the result columns get their types from the expressions that
461      * live under them.
462      *
463      * @param fromListParam FromList to use/append to.
464      *
465      * @exception StandardException Thrown on error
466      */

467     public void bindResultColumns(FromList fromListParam)
468                     throws StandardException
469     {
470         leftResultSet.bindResultColumns(fromListParam);
471         rightResultSet.bindResultColumns(fromListParam);
472     }
473
474     /**
475      * Bind the result columns for this ResultSetNode to a base table.
476      * This is useful for INSERT and UPDATE statements, where the
477      * result columns get their types from the table being updated or
478      * inserted into.
479      * If a result column list is specified, then the verification that the
480      * result column list does not contain any duplicates will be done when
481      * binding them by name.
482      *
483      * @param targetTableDescriptor The TableDescriptor for the table being
484      * updated or inserted into
485      * @param targetColumnList For INSERT statements, the user
486      * does not have to supply column
487      * names (for example, "insert into t
488      * values (1,2,3)". When this
489      * parameter is null, it means that
490      * the user did not supply column
491      * names, and so the binding should
492      * be done based on order. When it
493      * is not null, it means do the binding
494      * by name, not position.
495      * @param statement Calling DMLStatementNode (Insert or Update)
496      * @param fromListParam FromList to use/append to.
497      *
498      * @exception StandardException Thrown on error
499      */

500
501     public void bindResultColumns(TableDescriptor targetTableDescriptor,
502                     FromVTI targetVTI,
503                     ResultColumnList targetColumnList,
504                     DMLStatementNode statement,
505                     FromList fromListParam)
506                 throws StandardException
507     {
508         leftResultSet.bindResultColumns(targetTableDescriptor,
509                                         targetVTI,
510                                         targetColumnList,
511                                         statement, fromListParam);
512         rightResultSet.bindResultColumns(targetTableDescriptor,
513                                         targetVTI,
514                                         targetColumnList,
515                                         statement, fromListParam);
516     }
517
518     /**
519      * Determine whether or not the specified name is an exposed name in
520      * the current query block.
521      *
522      * @param name The specified name to search for as an exposed name.
523      * @param schemaName Schema name, if non-null.
524      * @param exactMatch Whether or not we need an exact match on specified schema and table
525      * names or match on table id.
526      *
527      * @return The FromTable, if any, with the exposed name.
528      *
529      * @exception StandardException Thrown on error
530      */

531     protected FromTable getFromTableByName(String JavaDoc name, String JavaDoc schemaName, boolean exactMatch)
532         throws StandardException
533     {
534         FromTable result = leftResultSet.getFromTableByName(name, schemaName, exactMatch);
535
536         /* We search both sides for a TableOperatorNode (join nodes)
537          * but only the left side for a UnionNode.
538          */

539         if (result == null)
540         {
541             result = rightResultSet.getFromTableByName(name, schemaName, exactMatch);
542         }
543         return result;
544     }
545
546     /**
547      * Put a ProjectRestrictNode on top of each FromTable in the FromList.
548      * ColumnReferences must continue to point to the same ResultColumn, so
549      * that ResultColumn must percolate up to the new PRN. However,
550      * that ResultColumn will point to a new expression, a VirtualColumnNode,
551      * which points to the FromTable and the ResultColumn that is the source for
552      * the ColumnReference.
553      * (The new PRN will have the original of the ResultColumnList and
554      * the ResultColumns from that list. The FromTable will get shallow copies
555      * of the ResultColumnList and its ResultColumns. ResultColumn.expression
556      * will remain at the FromTable, with the PRN getting a new
557      * VirtualColumnNode for each ResultColumn.expression.)
558      * We then project out the non-referenced columns. If there are no referenced
559      * columns, then the PRN's ResultColumnList will consist of a single ResultColumn
560      * whose expression is 1.
561      *
562      * @param numTables Number of tables in the DML Statement
563      * @param gbl The group by list, if any
564      * @param fromList The from list, if any
565      *
566      * @return The generated ProjectRestrictNode atop the original FromTable.
567      *
568      * @exception StandardException Thrown on error
569      */

570
571     public ResultSetNode preprocess(int numTables,
572                                     GroupByList gbl,
573                                     FromList fromList)
574                                 throws StandardException
575     {
576         leftResultSet = leftResultSet.preprocess(numTables, gbl, fromList);
577         /* If leftResultSet is a FromSubquery, then we must explicitly extract
578          * out the subquery (flatten it). (SelectNodes have their own
579          * method of flattening them.
580          */

581         if (leftResultSet instanceof FromSubquery)
582         {
583             leftResultSet = ((FromSubquery) leftResultSet).extractSubquery(numTables);
584         }
585         rightResultSet = rightResultSet.preprocess(numTables, gbl, fromList);
586         /* If rightResultSet is a FromSubquery, then we must explicitly extract
587          * out the subquery (flatten it). (SelectNodes have their own
588          * method of flattening them.
589          */

590         if (rightResultSet instanceof FromSubquery)
591         {
592             rightResultSet = ((FromSubquery) rightResultSet).extractSubquery(numTables);
593         }
594
595         /* Build the referenced table map (left || right) */
596         referencedTableMap = (JBitSet) leftResultSet.getReferencedTableMap().clone();
597         referencedTableMap.or((JBitSet) rightResultSet.getReferencedTableMap());
598         referencedTableMap.set(tableNumber);
599
600         /* Only generate a PRN if this node is not a flattenable join node. */
601         if (isFlattenableJoinNode())
602         {
603             return this;
604         }
605         else
606         {
607             /* Project out any unreferenced RCs before we generate the PRN.
608              * NOTE: We have to do this at the end of preprocess since it has to
609              * be from the bottom up. We can't do it until the join expression is
610              * bound, since the join expression may contain column references that
611              * are not referenced anywhere else above us.
612              */

613             projectResultColumns();
614             return genProjectRestrict(numTables);
615         }
616     }
617
618     /**
619      * Find the unreferenced result columns and project them out. This is used in pre-processing joins
620      * that are not flattened into the where clause.
621      */

622     void projectResultColumns() throws StandardException
623     {
624         resultColumns.doProjection();
625     }
626     
627     /**
628      * Set the referenced columns in the column list if it may not be correct.
629      */

630     void setReferencedColumns()
631     {}
632     
633     /**
634      * Optimize a TableOperatorNode.
635      *
636      * @param dataDictionary The DataDictionary to use for optimization
637      * @param predicateList The PredicateList to apply.
638      *
639      * @return ResultSetNode The top of the optimized query tree
640      *
641      * @exception StandardException Thrown on error
642      */

643     public ResultSetNode optimize(DataDictionary dataDictionary,
644                                   PredicateList predicateList,
645                                   double outerRows)
646                 throws StandardException
647     {
648         /* Get an optimizer, so we can get a cost structure */
649         Optimizer optimizer =
650                             getOptimizer(
651                                 (FromList) getNodeFactory().getNode(
652                                     C_NodeTypes.FROM_LIST,
653                                     getNodeFactory().doJoinOrderOptimization(),
654                                     this,
655                                     getContextManager()),
656                                     predicateList,
657                                     dataDictionary,
658                                     (RequiredRowOrdering) null);
659
660         costEstimate = optimizer.newCostEstimate();
661
662         /* RESOLVE: This is just a stub for now */
663         leftResultSet = leftResultSet.optimize(
664                                             dataDictionary,
665                                             predicateList,
666                                             outerRows);
667         rightResultSet = rightResultSet.optimize(
668                                             dataDictionary,
669                                             predicateList,
670                                             outerRows);
671
672         /* The cost is the sum of the two child costs */
673         costEstimate.setCost(leftResultSet.getCostEstimate().getEstimatedCost(),
674                              leftResultSet.getCostEstimate().rowCount(),
675                              leftResultSet.getCostEstimate().singleScanRowCount() +
676                              rightResultSet.getCostEstimate().singleScanRowCount());
677
678         costEstimate.add(rightResultSet.costEstimate, costEstimate);
679
680         return this;
681     }
682
683     /**
684      * @see ResultSetNode#modifyAccessPaths
685      *
686      * @exception StandardException Thrown on error
687      */

688     public ResultSetNode modifyAccessPaths() throws StandardException
689     {
690         /* Beetle 4454 - union all with another union all would modify access
691          * paths twice causing NullPointerException, make sure we don't
692          * do this again, if we have already done it in modifyAccessPaths(outertables)
693          */

694         if (!leftModifyAccessPathsDone)
695         {
696             if (leftOptimizer != null)
697                 leftOptimizer.modifyAccessPaths();
698             else
699             {
700                 // If this is a SetOperatorNode then we may have pushed
701
// predicates down to the children. If that's the case
702
// then we need to pass those predicates down as part
703
// of the modifyAccessPaths call so that they can be
704
// pushed one last time, in prep for generation.
705
if (this instanceof SetOperatorNode)
706                 {
707                     SetOperatorNode setOp = (SetOperatorNode)this;
708                     leftResultSet = leftResultSet.modifyAccessPaths(
709                         setOp.getLeftOptPredicateList());
710                 }
711                 else
712                     leftResultSet = leftResultSet.modifyAccessPaths();
713             }
714         }
715         if (!rightModifyAccessPathsDone)
716         {
717             if (rightOptimizer != null)
718                 rightOptimizer.modifyAccessPaths();
719             else
720             {
721                 if (this instanceof SetOperatorNode) {
722                     SetOperatorNode setOp = (SetOperatorNode)this;
723                     rightResultSet = rightResultSet.modifyAccessPaths(
724                         setOp.getRightOptPredicateList());
725                 }
726                 else
727                     rightResultSet = rightResultSet.modifyAccessPaths();
728             }
729         }
730         return this;
731     }
732
733     /**
734      * Search to see if a query references the specifed table name.
735      *
736      * @param name Table name (String) to search for.
737      * @param baseTable Whether or not name is for a base table
738      *
739      * @return true if found, else false
740      *
741      * @exception StandardException Thrown on error
742      */

743     public boolean referencesTarget(String JavaDoc name, boolean baseTable)
744         throws StandardException
745     {
746         return leftResultSet.referencesTarget(name, baseTable) ||
747                rightResultSet.referencesTarget(name, baseTable);
748     }
749
750     /**
751      * Return true if the node references SESSION schema tables (temporary or permanent)
752      *
753      * @return true if references SESSION schema tables, else false
754      *
755      * @exception StandardException Thrown on error
756      */

757     public boolean referencesSessionSchema()
758         throws StandardException
759     {
760         return leftResultSet.referencesSessionSchema() ||
761                rightResultSet.referencesSessionSchema();
762     }
763
764     /**
765      * Optimize a source result set to this table operator.
766      *
767      * @exception StandardException Thrown on error
768      */

769     protected ResultSetNode optimizeSource(
770                             Optimizer optimizer,
771                             ResultSetNode sourceResultSet,
772                             PredicateList predList,
773                             CostEstimate outerCost)
774             throws StandardException
775     {
776         ResultSetNode retval;
777
778         if (sourceResultSet instanceof FromTable)
779         {
780             FromList optList = (FromList) getNodeFactory().getNode(
781                                     C_NodeTypes.FROM_LIST,
782                                     getNodeFactory().doJoinOrderOptimization(),
783                                     sourceResultSet,
784                                     getContextManager());
785
786             /* If there is no predicate list, create an empty one */
787             if (predList == null)
788                 predList = (PredicateList) getNodeFactory().getNode(
789                                                 C_NodeTypes.PREDICATE_LIST,
790                                                 getContextManager());
791
792             LanguageConnectionContext lcc = getLanguageConnectionContext();
793             OptimizerFactory optimizerFactory = lcc.getOptimizerFactory();
794             optimizer = optimizerFactory.getOptimizer(optList,
795                                                     predList,
796                                                     getDataDictionary(),
797                                                     (RequiredRowOrdering) null,
798                                                     getCompilerContext().getNumTables(),
799                                                       lcc);
800             optimizer.prepForNextRound();
801
802             if (sourceResultSet == leftResultSet)
803             {
804                 leftOptimizer = optimizer;
805             }
806             else if (sourceResultSet == rightResultSet)
807             {
808                 rightOptimizer = optimizer;
809             }
810             else
811             {
812                 if (SanityManager.DEBUG)
813                     SanityManager.THROWASSERT("Result set being optimized is neither left nor right");
814             }
815             
816             /*
817             ** Set the estimated number of outer rows from the outer part of
818             ** the plan.
819             */

820             optimizer.setOuterRows(outerCost.rowCount());
821
822             /* Optimize the underlying result set */
823             while (optimizer.getNextPermutation())
824             {
825                 while (optimizer.getNextDecoratedPermutation())
826                 {
827                     optimizer.costPermutation();
828                 }
829             }
830
831             retval = sourceResultSet;
832         }
833         else
834         {
835             retval = sourceResultSet.optimize(
836                                         optimizer.getDataDictionary(),
837                                         predList,
838                                         outerCost.rowCount());
839         }
840
841         return retval;
842     }
843
844     /**
845      * Decrement (query block) level (0-based) for
846      * all of the tables in this ResultSet tree.
847      * This is useful when flattening a subquery.
848      *
849      * @param decrement The amount to decrement by.
850      */

851     void decrementLevel(int decrement)
852     {
853         leftResultSet.decrementLevel(decrement);
854         rightResultSet.decrementLevel(decrement);
855     }
856
857     /**
858      * Replace any DEFAULTs with the associated tree for the default.
859      *
860      * @param ttd The TableDescriptor for the target table.
861      * @param tcl The RCL for the target table.
862      *
863      * @exception StandardException Thrown on error
864      */

865     void replaceDefaults(TableDescriptor ttd, ResultColumnList tcl)
866         throws StandardException
867     {
868         leftResultSet.replaceDefaults(ttd, tcl);
869         rightResultSet.replaceDefaults(ttd, tcl);
870     }
871
872     /**
873      * Notify the underlying result set tree that the result is
874      * ordering dependent. (For example, no bulk fetch on an index
875      * if under an IndexRowToBaseRow.)
876      */

877     void markOrderingDependent()
878     {
879         leftResultSet.markOrderingDependent();
880         rightResultSet.markOrderingDependent();
881     }
882
883     /**
884      * Accept a visitor, and call v.visit()
885      * on child nodes as necessary.
886      *
887      * @param v the visitor
888      *
889      * @exception StandardException on error
890      */

891     public Visitable accept(Visitor v)
892         throws StandardException
893     {
894         if (v.skipChildren(this))
895         {
896             return v.visit(this);
897         }
898
899         Visitable returnNode = super.accept(v);
900
901         if (leftResultSet != null && !v.stopTraversal())
902         {
903             leftResultSet = (ResultSetNode)leftResultSet.accept(v);
904         }
905         if (rightResultSet != null && !v.stopTraversal())
906         {
907             rightResultSet = (ResultSetNode)rightResultSet.accept(v);
908         }
909         return returnNode;
910     }
911
912     /**
913      * apparently something special needs to be done for me....
914      */

915     public boolean needsSpecialRCLBinding()
916     {
917         return true;
918     }
919 }
920
Popular Tags