KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.SelectNode
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
23 package org.apache.derby.impl.sql.compile;
24
25 import org.apache.derby.iapi.sql.compile.CostEstimate;
26 import org.apache.derby.iapi.sql.compile.Optimizer;
27 import org.apache.derby.iapi.sql.compile.Visitable;
28 import org.apache.derby.iapi.sql.compile.Visitor;
29 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
30
31 import org.apache.derby.iapi.sql.conn.Authorizer;
32
33 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
34 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
35
36 import org.apache.derby.iapi.types.TypeId;
37 import org.apache.derby.iapi.types.DataTypeDescriptor;
38
39 import org.apache.derby.iapi.reference.Limits;
40 import org.apache.derby.iapi.reference.SQLState;
41 import org.apache.derby.iapi.error.StandardException;
42
43 import org.apache.derby.iapi.store.access.TransactionController;
44
45 import org.apache.derby.iapi.services.sanity.SanityManager;
46
47 import org.apache.derby.iapi.util.JBitSet;
48
49 import java.util.Vector JavaDoc;
50 import java.util.HashSet JavaDoc;
51
52 /**
53  * A SelectNode represents the result set for any of the basic DML
54  * operations: SELECT, INSERT, UPDATE, and DELETE. (A RowResultSetNode
55  * will be used for an INSERT with a VALUES clause.) For INSERT - SELECT,
56  * any of the fields in a SelectNode can be used (the SelectNode represents
57  * the SELECT statement in the INSERT - SELECT). For UPDATE and
58  * DELETE, there will be one table in the fromList, and the groupByList
59  * fields will be null. For both INSERT and UPDATE,
60  * the resultColumns in the selectList will contain the names of the columns
61  * being inserted into or updated.
62  *
63  * @author Jeff Lichtman
64  */

65
66 public class SelectNode extends ResultSetNode
67 {
68     /**
69      * List of tables in the FROM clause of this SELECT
70      */

71     FromList fromList;
72     FromTable targetTable;
73
74     /* Aggregate Vectors for select and where clauses */
75     Vector JavaDoc selectAggregates ;
76     Vector JavaDoc whereAggregates;
77
78     /**
79      * The ValueNode for the WHERE clause must represent a boolean
80      * expression. The binding phase will enforce this - the parser
81      * does not have enough information to enforce it in all cases
82      * (for example, user methods that return boolean).
83      */

84     ValueNode whereClause;
85     ValueNode originalWhereClause;
86
87     /**
88      * List of result columns in GROUP BY clause
89      */

90     GroupByList groupByList;
91
92     /* List of columns in ORDER BY list */
93     OrderByList orderByList;
94     boolean orderByQuery ;
95
96     /* PredicateLists for where clause */
97     PredicateList wherePredicates;
98
99     /* SubqueryLists for select and where clauses */
100     SubqueryList selectSubquerys;
101     SubqueryList whereSubquerys;
102
103     /* Whether or not we are only binding the target list */
104     private boolean bindTargetListOnly;
105
106     private boolean isDistinct;
107
108     private boolean orderByAndDistinctMerged;
109
110     private boolean generatedForGroupByClause;
111     private boolean generatedForHavingClause;
112
113     /* Copy of fromList prior to generating join tree */
114     private FromList preJoinFL;
115
116     /**
117      * Initializer for a SelectNode.
118      *
119      * @param selectList The result column list for the SELECT statement
120      * @param aggregateVector The aggregate vector for this SELECT
121      * @param fromList The FROM list for the SELECT statement
122      * @param whereClause An expression representing the WHERE clause.
123      * It must be a boolean expression, but this is
124      * not checked until binding.
125      * @param groupByList The GROUP BY list, if any.
126      * @exception StandardException Thrown on error
127      */

128
129     public void init(Object JavaDoc selectList,
130               Object JavaDoc aggregateVector,
131               Object JavaDoc fromList,
132               Object JavaDoc whereClause,
133               Object JavaDoc groupByList)
134             throws StandardException
135     {
136         /* RESOLVE - remove aggregateList from constructor.
137          * Consider adding selectAggregates and whereAggregates
138          */

139         resultColumns = (ResultColumnList) selectList;
140         if (resultColumns != null)
141             resultColumns.markInitialSize();
142         this.fromList = (FromList) fromList;
143         this.whereClause = (ValueNode) whereClause;
144         this.originalWhereClause = (ValueNode) whereClause;
145         this.groupByList = (GroupByList) groupByList;
146         bindTargetListOnly = false;
147     }
148
149     /**
150      * Convert this object to a String. See comments in QueryTreeNode.java
151      * for how this should be done for tree printing.
152      *
153      * @return This object as a String
154      */

155
156     public String JavaDoc toString()
157     {
158         if (SanityManager.DEBUG)
159         {
160             return "isDistinct: "+ isDistinct + "\n"+
161                 "groupByList: " +
162                 (groupByList != null ? groupByList.toString() : "null") + "\n" +
163                 "orderByList: " +
164                 (orderByList != null ? orderByList.toString() : "null") + "\n" +
165                 "generatedForGroupByClause: " +generatedForGroupByClause +"\n" +
166                 "generatedForHavingClause: " + generatedForHavingClause + "\n" +
167                 super.toString();
168         }
169         else
170         {
171             return "";
172         }
173     }
174
175     public String JavaDoc statementToString()
176     {
177         return "SELECT";
178     }
179
180     public void makeDistinct()
181     {
182         isDistinct = true;
183     }
184
185     public void clearDistinct()
186     {
187         isDistinct = false;
188     }
189
190     boolean hasDistinct()
191     {
192         return isDistinct;
193     }
194
195     /**
196      * Mark this SelectNode as being generated for a GROUP BY clause.
197      */

198     public void markAsForGroupByClause()
199     {
200         generatedForGroupByClause = true;
201     }
202
203     /**
204      * Return whether or not this SelectNode was generated for a GROUP BY clause.
205      *
206      * @return boolean Whether or not this SelectNode was generated for a GROUP BY clause.
207      */

208     public boolean getGeneratedForGroupbyClause()
209     {
210         return generatedForGroupByClause;
211     }
212
213     /**
214      * Mark this SelectNode as being generated for a HAVING clause.
215      */

216     public void markAsForHavingClause()
217     {
218         generatedForHavingClause = true;
219     }
220
221     /**
222      * Prints the sub-nodes of this object. See QueryTreeNode.java for
223      * how tree printing is supposed to work.
224      *
225      * @param depth The depth of this node in the tree
226      */

227
228     public void printSubNodes(int depth)
229     {
230         if (SanityManager.DEBUG)
231         {
232             super.printSubNodes(depth);
233
234             if (selectSubquerys != null)
235             {
236                 printLabel(depth, "selectSubquerys: ");
237                 selectSubquerys.treePrint(depth + 1);
238             }
239
240             printLabel(depth, "fromList: ");
241
242             if (fromList != null)
243             {
244                 fromList.treePrint(depth + 1);
245             }
246
247             if (whereClause != null)
248             {
249                 printLabel(depth, "whereClause: ");
250                 whereClause.treePrint(depth + 1);
251             }
252
253             if ((wherePredicates != null) &&wherePredicates.size() > 0)
254             {
255                 printLabel(depth, "wherePredicates: ");
256                 wherePredicates.treePrint(depth + 1);
257             }
258
259             if (whereSubquerys != null)
260             {
261                 printLabel(depth, "whereSubquerys: ");
262                 whereSubquerys.treePrint(depth + 1);
263             }
264
265             printLabel(depth, "preJoinFL: ");
266
267             if (preJoinFL != null)
268             {
269                 preJoinFL.treePrint(depth + 1);
270             }
271         }
272     }
273
274     /**
275      * Return the fromList for this SelectNode.
276      *
277      * @return FromList The fromList for this SelectNode.
278      */

279     public FromList getFromList()
280     {
281         return fromList;
282     }
283
284     /**
285      * Find colName in the result columns and return underlying columnReference.
286      * Note that this function returns null if there are more than one FromTable
287      * for this SelectNode and the columnReference needs to be directly under
288      * the resultColumn. So having an expression under the resultSet would cause
289      * returning null.
290      *
291      * @param colName Name of the column
292      *
293      * @return ColumnReference ColumnReference to the column, if found
294      */

295     public ColumnReference findColumnReferenceInResult(String JavaDoc colName)
296                     throws StandardException
297     {
298         if (fromList.size() != 1)
299             return null;
300
301         // This logic is similar to SubQueryNode.singleFromBaseTable(). Refactor
302
FromTable ft = (FromTable) fromList.elementAt(0);
303         if (! ((ft instanceof ProjectRestrictNode) &&
304                 ((ProjectRestrictNode) ft).getChildResult() instanceof FromBaseTable) &&
305                 !(ft instanceof FromBaseTable))
306             return null;
307
308         // Loop through the result columns looking for a match
309
int rclSize = resultColumns.size();
310         for (int index = 0; index < rclSize; index++)
311         {
312             ResultColumn rc = (ResultColumn) resultColumns.elementAt(index);
313             if (! (rc.getExpression() instanceof ColumnReference))
314                 return null;
315
316             ColumnReference crNode = (ColumnReference) rc.getExpression();
317
318             if (crNode.columnName.equals(colName))
319                 return (ColumnReference) crNode.getClone();
320         }
321
322         return null;
323     }
324
325     /**
326      * Return the whereClause for this SelectNode.
327      *
328      * @return ValueNode The whereClause for this SelectNode.
329      */

330     public ValueNode getWhereClause()
331     {
332         return whereClause;
333     }
334
335     /**
336      * Return the wherePredicates for this SelectNode.
337      *
338      * @return PredicateList The wherePredicates for this SelectNode.
339      */

340     public PredicateList getWherePredicates()
341     {
342         return wherePredicates;
343     }
344
345     /**
346      * Return the selectSubquerys for this SelectNode.
347      *
348      * @return SubqueryList The selectSubquerys for this SelectNode.
349      */

350     public SubqueryList getSelectSubquerys()
351     {
352         return selectSubquerys;
353     }
354
355     /**
356      * Return the specified aggregate vector for this SelectNode.
357      *
358      * @param clause Which clause to get the aggregate list for
359      *
360      * @return aggregateVector The specified aggregate vector for this SelectNode.
361      */

362     public Vector JavaDoc getAggregateVector(int clause)
363     {
364         switch (clause)
365         {
366             case ValueNode.IN_SELECT_LIST:
367                 return selectAggregates;
368
369             case ValueNode.IN_WHERE_CLAUSE:
370                 if (generatedForHavingClause)
371                 {
372                     return null;
373                 }
374                 else
375                 {
376                     return whereAggregates;
377                 }
378
379             case ValueNode.IN_HAVING_CLAUSE:
380                 if (generatedForHavingClause)
381                 {
382                     return whereAggregates;
383                 }
384                 else
385                 {
386                     return null;
387                 }
388
389             default:
390                 if (SanityManager.DEBUG)
391                 {
392                     SanityManager.ASSERT(false,
393                         "Unexpected value for clause");
394                 }
395                 return null;
396         }
397     }
398
399     /**
400      * Return the whereSubquerys for this SelectNode.
401      *
402      * @return SubqueryList The whereSubquerys for this SelectNode.
403      */

404     public SubqueryList getWhereSubquerys()
405     {
406         return whereSubquerys;
407     }
408
409     /**
410      * Bind the tables in this SelectNode. This includes getting their
411      * TableDescriptors from the DataDictionary and numbering the FromTables.
412      * NOTE: Because this node represents the top of a new query block, we bind
413      * both the non VTI and VTI tables under this node in this method call.
414      *
415      * @param dataDictionary The DataDictionary to use for binding
416      * @param fromListParam FromList to use/append to.
417      *
418      * @return ResultSetNode
419      *
420      * @exception StandardException Thrown on error
421      */

422
423     public ResultSetNode bindNonVTITables(DataDictionary dataDictionary,
424                            FromList fromListParam)
425                     throws StandardException
426     {
427         int fromListParamSize = fromListParam.size();
428         int fromListSize = fromList.size();
429         int nestingLevel;
430         FromList fromListClone = (FromList) getNodeFactory().getNode(
431                                     C_NodeTypes.FROM_LIST,
432                                     getNodeFactory().doJoinOrderOptimization(),
433                                     getContextManager());
434
435         wherePredicates = (PredicateList) getNodeFactory().getNode(
436                                             C_NodeTypes.PREDICATE_LIST,
437                                             getContextManager());
438         preJoinFL = (FromList) getNodeFactory().getNode(
439                                     C_NodeTypes.FROM_LIST,
440                                     getNodeFactory().doJoinOrderOptimization(),
441                                     getContextManager());
442
443         /* Set the nesting level in the fromList */
444         if (fromListParam.size() == 0)
445         {
446             nestingLevel = 0;
447         }
448         else
449         {
450             nestingLevel = ((FromTable) fromListParam.elementAt(0)).getLevel() + 1;
451         }
452         fromList.setLevel(nestingLevel);
453
454         /* Splice a clone of our FromList on to the beginning of fromListParam, before binding
455          * the tables, for correlated column resolution in VTIs.
456          */

457         for (int index = 0; index < fromListSize; index++)
458         {
459             fromListParam.insertElementAt(fromList.elementAt(index), 0);
460         }
461
462         // Now bind our from list
463
fromList.bindTables(dataDictionary, fromListParam);
464
465         /* Restore fromListParam */
466         for (int index = 0; index < fromListSize; index++)
467         {
468             fromListParam.removeElementAt(0);
469         }
470         return this;
471     }
472
473     /**
474      * Bind the expressions in this SelectNode. This means binding the
475      * sub-expressions, as well as figuring out what the return type is
476      * for each expression.
477      *
478      * @param fromListParam FromList to use/append to.
479      *
480      * @exception StandardException Thrown on error
481      */

482     public void bindExpressions(FromList fromListParam)
483                     throws StandardException
484     {
485         int fromListParamSize = fromListParam.size();
486         int fromListSize = fromList.size();
487         int numDistinctAggs;
488
489         if (SanityManager.DEBUG)
490         SanityManager.ASSERT(fromList != null && resultColumns != null,
491             "Both fromList and resultColumns are expected to be non-null");
492
493         /* NOTE - a lot of this code would be common to bindTargetExpression(),
494          * so we use a private boolean to share the code instead of duplicating
495          * it. bindTargetExpression() is responsible for toggling the boolean.
496          */

497         if (! bindTargetListOnly)
498         {
499             /* Bind the expressions in FromSubquerys, JoinNodes, etc. */
500             fromList.bindExpressions( fromListParam );
501         }
502
503         selectSubquerys = (SubqueryList) getNodeFactory().getNode(
504                                             C_NodeTypes.SUBQUERY_LIST,
505                                             getContextManager());
506         selectAggregates = new Vector JavaDoc();
507
508         /* Splice our FromList on to the beginning of fromListParam, before binding
509          * the expressions, for correlated column resolution.
510          */

511         for (int index = 0; index < fromListSize; index++)
512         {
513             fromListParam.insertElementAt(fromList.elementAt(index), index);
514         }
515
516         resultColumns.setClause(ValueNode.IN_SELECT_LIST);
517         resultColumns.bindExpressions(fromListParam,
518                                       selectSubquerys,
519                                       selectAggregates);
520
521         /* We're done if we're only binding the target list.
522          * (After we restore the fromList, of course.)
523          */

524         if (bindTargetListOnly)
525         {
526             for (int index = 0; index < fromListSize; index++)
527             {
528                 fromListParam.removeElementAt(0);
529             }
530             return;
531         }
532
533         whereAggregates = new Vector JavaDoc();
534         whereSubquerys = (SubqueryList) getNodeFactory().getNode(
535                                                 C_NodeTypes.SUBQUERY_LIST,
536                                                 getContextManager());
537         if (whereClause != null)
538         {
539             getCompilerContext().pushCurrentPrivType( Authorizer.SELECT_PRIV);
540             whereClause = whereClause.bindExpression(fromListParam,
541                                         whereSubquerys,
542                                         whereAggregates);
543
544             /* RESOLVE - Temporarily disable aggregates in the HAVING clause.
545             ** (We may remove them in the parser anyway.)
546             ** RESOLVE - Disable aggregates in the WHERE clause. Someday
547             ** Aggregates will be allowed iff they are in a subquery
548             ** of the having clause and they correlate to an outer
549             ** query block. For now, aggregates are not supported
550             ** in the WHERE clause at all.
551             ** Note: a similar check is made in JoinNode.
552             */

553             if ((whereAggregates.size() > 0) &&
554                     !generatedForHavingClause)
555             {
556                 throw StandardException.newException(SQLState.LANG_NO_AGGREGATES_IN_WHERE_CLAUSE);
557             }
558
559             /* If whereClause is a parameter, (where ?/where -?/where +?), then we should catch it and throw exception
560              */

561             if (whereClause.isParameterNode())
562                 throw StandardException.newException(SQLState.LANG_NON_BOOLEAN_WHERE_CLAUSE, "PARAMETER" );
563             if ((whereClause instanceof UnaryOperatorNode) &&
564                     ((UnaryOperatorNode)whereClause).isUnaryMinusOrPlusWithParameter())
565                 throw StandardException.newException(SQLState.LANG_NON_BOOLEAN_WHERE_CLAUSE, "PARAMETER" );
566             
567             whereClause = whereClause.checkIsBoolean();
568             getCompilerContext().popCurrentPrivType();
569         }
570
571         /* Restore fromList */
572         for (int index = 0; index < fromListSize; index++)
573         {
574             fromListParam.removeElementAt(0);
575         }
576
577         if (SanityManager.DEBUG) {
578         SanityManager.ASSERT(fromListParam.size() == fromListParamSize,
579             "fromListParam.size() = " + fromListParam.size() +
580             ", expected to be restored to " + fromListParamSize);
581         SanityManager.ASSERT(fromList.size() == fromListSize,
582             "fromList.size() = " + fromList.size() +
583             ", expected to be restored to " + fromListSize);
584         }
585
586         /* If query is grouped, bind the group by list. */
587         if (groupByList != null)
588         {
589             Vector JavaDoc gbAggregateVector = new Vector JavaDoc();
590
591             groupByList.bindGroupByColumns(this,
592                                            gbAggregateVector);
593
594             /*
595             ** There should be no aggregates in the Group By list.
596             ** We don't expect any, but just to be on the safe side
597             ** we will check under sanity.
598             */

599             if (SanityManager.DEBUG)
600             {
601                 SanityManager.ASSERT(gbAggregateVector.size() == 0,
602                         "Unexpected Aggregate vector generated by Group By clause");
603             }
604         }
605         /* If ungrouped query with aggregates in SELECT list, verify
606          * that all result columns are valid aggregate expressions -
607          * no column references outside of an aggregate.
608          * If grouped query with aggregates in SELECT list, verify that all
609          * result columns are either grouping expressions or valid
610          * grouped aggregate expressions - the only column references
611          * allowed outside of an aggregate are columns in expressions in
612          * the group by list.
613          */

614         if (groupByList != null || selectAggregates.size() > 0)
615         {
616
617             VerifyAggregateExpressionsVisitor visitor =
618                 new VerifyAggregateExpressionsVisitor(groupByList);
619             resultColumns.accept(visitor);
620         }
621
622         /*
623         ** RESOLVE: for now, only one distinct aggregate is supported
624         ** in the select list.
625         */

626         numDistinctAggs = numDistinctAggregates(selectAggregates);
627         if (numDistinctAggs > 1)
628         {
629             throw StandardException.newException(SQLState.LANG_USER_AGGREGATE_MULTIPLE_DISTINCTS);
630         }
631     }
632
633     /**
634      * Bind the expressions in this ResultSetNode if it has tables. This means binding the
635      * sub-expressions, as well as figuring out what the return type is for
636      * each expression.
637      *
638      * @param fromListParam FromList to use/append to.
639      *
640      * @exception StandardException Thrown on error
641      */

642     public void bindExpressionsWithTables(FromList fromListParam)
643                     throws StandardException
644     {
645         /* We have tables, so simply call bindExpressions() */
646         bindExpressions(fromListParam);
647     }
648
649     /**
650      * Bind the expressions in the target list. This means binding the
651      * sub-expressions, as well as figuring out what the return type is
652      * for each expression. This is useful for EXISTS subqueries, where we
653      * need to validate the target list before blowing it away and replacing
654      * it with a SELECT true.
655      *
656      * @exception StandardException Thrown on error
657      */

658
659     public void bindTargetExpressions(FromList fromListParam)
660                     throws StandardException
661     {
662         bindTargetListOnly = true;
663         bindExpressions(fromListParam);
664         bindTargetListOnly = false;
665     }
666
667     /**
668      * Bind the result columns of this ResultSetNode when there is no
669      * base table to bind them to. This is useful for SELECT statements,
670      * where the result columns get their types from the expressions that
671      * live under them.
672      *
673      * @param fromListParam FromList to use/append to.
674      *
675      * @exception StandardException Thrown on error
676      */

677
678     public void bindResultColumns(FromList fromListParam)
679                 throws StandardException
680     {
681         /* We first bind the resultColumns for any FromTable which
682          * needs its own binding, such as JoinNodes.
683          * We pass through the fromListParam without adding our fromList
684          * to it, since the elements in our fromList can only be correlated
685          * with outer query blocks.
686          */

687         fromList.bindResultColumns(fromListParam);
688         super.bindResultColumns(fromListParam);
689
690         /* Only 1012 elements allowed in select list */
691         if (resultColumns.size() > Limits.DB2_MAX_ELEMENTS_IN_SELECT_LIST)
692         {
693             throw StandardException.newException(SQLState.LANG_TOO_MANY_ELEMENTS);
694         }
695
696         /* Fix nullability in case of any outer joins in the fromList */
697         if (fromList.hasOuterJoins())
698             resultColumns.setNullability(true);
699     }
700
701     /**
702      * Bind the result columns for this ResultSetNode to a base table.
703      * This is useful for INSERT and UPDATE statements, where the
704      * result columns get their types from the table being updated or
705      * inserted into.
706      * If a result column list is specified, then the verification that the
707      * result column list does not contain any duplicates will be done when
708      * binding them by name.
709      *
710      * @param targetTableDescriptor The TableDescriptor for the table being
711      * updated or inserted into
712      * @param targetColumnList For INSERT statements, the user
713      * does not have to supply column
714      * names (for example, "insert into t
715      * values (1,2,3)". When this
716      * parameter is null, it means that
717      * the user did not supply column
718      * names, and so the binding should
719      * be done based on order. When it
720      * is not null, it means do the binding
721      * by name, not position.
722      * @param statement Calling DMLStatementNode (Insert or Update)
723      * @param fromListParam FromList to use/append to.
724      *
725      * @exception StandardException Thrown on error
726      */

727
728     public void bindResultColumns(TableDescriptor targetTableDescriptor,
729                     FromVTI targetVTI,
730                     ResultColumnList targetColumnList,
731                     DMLStatementNode statement,
732                     FromList fromListParam)
733                 throws StandardException
734     {
735         /* We first bind the resultColumns for any FromTable which
736          * needs its own binding, such as JoinNodes.
737          * We pass through the fromListParam without adding our fromList
738          * to it, since the elements in our fromList can only be correlated
739          * with outer query blocks.
740          */

741         fromList.bindResultColumns(fromListParam);
742         super.bindResultColumns(targetTableDescriptor,
743                                 targetVTI,
744                                 targetColumnList, statement,
745                                 fromListParam);
746     }
747
748     /**
749      * Push an expression into this SELECT (and possibly down into
750      * one of the tables in the FROM list). This is useful when
751      * trying to push predicates into unflattened views or
752      * derived tables.
753      *
754      * @param predicate The predicate that we attempt to push
755      *
756      * @exception StandardException Thrown on error
757      */

758     void pushExpressionsIntoSelect(Predicate predicate)
759         throws StandardException
760     {
761         wherePredicates.pullExpressions(referencedTableMap.size(), predicate.getAndNode());
762         fromList.pushPredicates(wherePredicates);
763     }
764
765
766     /**
767      * Verify that a SELECT * is valid for this type of subquery.
768      *
769      * @param outerFromList The FromList from the outer query block(s)
770      * @param subqueryType The subquery type
771      *
772      * @exception StandardException Thrown on error
773      */

774     public void verifySelectStarSubquery(FromList outerFromList, int subqueryType)
775                     throws StandardException
776     {
777         if (! ((ResultColumn) resultColumns.elementAt(0) instanceof AllResultColumn) )
778         {
779             return;
780         }
781
782         /* Select * always okay when SelectNode generated to wrap
783          * GROUP BY or HAVING.
784          */

785         if (generatedForGroupByClause || generatedForHavingClause)
786         {
787             return;
788         }
789
790         /* Select * currently only valid for EXISTS/NOT EXISTS.
791          * NOT EXISTS does not appear prior to preprocessing.
792          */

793         if (subqueryType != SubqueryNode.EXISTS_SUBQUERY)
794         {
795             throw StandardException.newException(SQLState.LANG_CANT_SELECT_STAR_SUBQUERY);
796         }
797
798         /* If the AllResultColumn is qualified, then we have to verify
799          * that the qualification is a valid exposed name.
800          * NOTE: The exposed name can come from an outer query block.
801          */

802         String JavaDoc fullTableName;
803             
804         fullTableName = ((AllResultColumn) resultColumns.elementAt(0)).getFullTableName();
805
806         if (fullTableName != null)
807         {
808             if (fromList.getFromTableByName(fullTableName, null, true) == null &&
809                 outerFromList.getFromTableByName(fullTableName, null, true) == null)
810             {
811                 if (fromList.getFromTableByName(fullTableName, null, false) == null &&
812                     outerFromList.getFromTableByName(fullTableName, null, false) == null)
813                 {
814                     throw StandardException.newException(SQLState.LANG_EXPOSED_NAME_NOT_FOUND, fullTableName);
815                 }
816             }
817         }
818     }
819
820     /**
821      * Determine whether or not the specified name is an exposed name in
822      * the current query block.
823      *
824      * @param name The specified name to search for as an exposed name.
825      * @param schemaName Schema name, if non-null.
826      * @param exactMatch Whether or not we need an exact match on specified schema and table
827      * names or match on table id.
828      *
829      * @return The FromTable, if any, with the exposed name.
830      *
831      * @exception StandardException Thrown on error
832      */

833     protected FromTable getFromTableByName(String JavaDoc name, String JavaDoc schemaName, boolean exactMatch)
834         throws StandardException
835     {
836         return fromList.getFromTableByName(name, schemaName, exactMatch);
837     }
838
839     /**
840      * Check for (and reject) ? parameters directly under the ResultColumns.
841      * This is done for SELECT statements.
842      *
843      * @exception StandardException Thrown if a ? parameter found
844      * directly under a ResultColumn
845      */

846
847     public void rejectParameters() throws StandardException
848     {
849         super.rejectParameters();
850         fromList.rejectParameters();
851     }
852
853     /**
854      * Push the order by list down from the cursor node
855      * into its child result set so that the optimizer
856      * has all of the information that it needs to
857      * consider sort avoidance.
858      *
859      * @param orderByList The order by list
860      */

861     void pushOrderByList(OrderByList orderByList)
862     {
863         this.orderByList = orderByList;
864         // remember that there was an order by list
865
orderByQuery = true;
866     }
867
868     /**
869      * Put a ProjectRestrictNode on top of each FromTable in the FromList.
870      * ColumnReferences must continue to point to the same ResultColumn, so
871      * that ResultColumn must percolate up to the new PRN. However,
872      * that ResultColumn will point to a new expression, a VirtualColumnNode,
873      * which points to the FromTable and the ResultColumn that is the source for
874      * the ColumnReference.
875      * (The new PRN will have the original of the ResultColumnList and
876      * the ResultColumns from that list. The FromTable will get shallow copies
877      * of the ResultColumnList and its ResultColumns. ResultColumn.expression
878      * will remain at the FromTable, with the PRN getting a new
879      * VirtualColumnNode for each ResultColumn.expression.)
880      * We then project out the non-referenced columns. If there are no referenced
881      * columns, then the PRN's ResultColumnList will consist of a single ResultColumn
882      * whose expression is 1.
883      *
884      * @param numTables The number of tables in the DML Statement
885      * @param gbl The outer group by list, if any
886      * @param fl The from list, if any
887      *
888      * @return The generated ProjectRestrictNode atop the original FromTable.
889      *
890      * @exception StandardException Thrown on error
891      */

892
893     public ResultSetNode preprocess(int numTables,
894                                     GroupByList gbl,
895                                     FromList fl)
896                                 throws StandardException
897     {
898         ResultSetNode newTop = this;
899
900         /* Put the expression trees in conjunctive normal form.
901          * NOTE - This needs to occur before we preprocess the subqueries
902          * because the subquery transformations assume that any subquery operator
903          * negation has already occurred.
904          */

905         normExpressions();
906
907         /**
908          * This method determines if (1) the query is a LOJ, and (2) if the LOJ is a candidate for
909          * reordering (i.e., linearization). The condition for LOJ linearization is:
910          * 1. either LOJ or ROJ in the fromList, i.e., no INNER, NO FULL JOINs
911          * 2. ON clause must be equality join between left and right operands and in CNF (i.e., AND is allowed)
912          */

913         boolean anyChange = fromList.LOJ_reorderable(numTables);
914         if (anyChange)
915         {
916             FromList afromList = (FromList) getNodeFactory().getNode(C_NodeTypes.FROM_LIST,
917                                                                      getNodeFactory().doJoinOrderOptimization(),
918                                                                      getContextManager());
919             bindExpressions(afromList);
920         }
921
922         /* Preprocess the fromList. For each FromTable, if it is a FromSubquery
923          * then we will preprocess it, replacing the FromSubquery with a
924          * ProjectRestrictNode. If it is a FromBaseTable, then we will generate
925          * the ProjectRestrictNode above it.
926          */

927         fromList.preprocess(numTables, groupByList, whereClause);
928
929         /* selectSubquerys is always allocated at bind() time */
930         if (SanityManager.DEBUG)
931         {
932             SanityManager.ASSERT(selectSubquerys != null,
933                 "selectSubquerys is expected to be non-null");
934         }
935
936         /* Preprocess the RCL after the from list so that
937          * we can flatten/optimize any subqueries in the
938          * select list.
939          */

940         resultColumns.preprocess(numTables,
941                                  fromList, whereSubquerys,
942                                  wherePredicates);
943
944         /* Preprocess the expressions. (This is necessary for subqueries.
945          * This is also where we do tranformations such as for LIKE.)
946          *
947          * NOTE: We do this after preprocessing the fromList so that, for
948          * quantified subqueries, the join expression with the outer
949          * expression will be pushable (to be pushable, the ColumnReference
950          * has to point to a VirtualColumnNode, and not to a BaseColumnNode).
951          */

952         if (whereClause != null)
953         {
954             whereClause.preprocess(numTables,
955                                    fromList, whereSubquerys,
956                                    wherePredicates);
957         }
958
959         /* Preprocess the group by list too. We need to compare
960          * expressions in the group by list with the select list and we
961          * can't rewrite one and not the other.
962          */

963         if (groupByList != null)
964         {
965             groupByList.preprocess(numTables, fromList, whereSubquerys, wherePredicates);
966         }
967         
968         /* Pull apart the expression trees */
969         if (whereClause != null)
970         {
971             wherePredicates.pullExpressions(numTables, whereClause);
972             whereClause = null;
973         }
974
975         /* RESOLVE - Where should we worry about expression pull up for
976          * expensive predicates?
977          */

978
979         // Flatten any flattenable FromSubquerys or JoinNodes
980
fromList.flattenFromTables(resultColumns,
981                                    wherePredicates,
982                                    whereSubquerys,
983                                    groupByList);
984
985         if (wherePredicates != null && wherePredicates.size() > 0 && fromList.size() > 0)
986         {
987             // Perform various forms of transitive closure on wherePredicates
988
if (fromList.size() > 1)
989             {
990                 performTransitiveClosure(numTables);
991             }
992
993             if (orderByList != null)
994             {
995                 // Remove constant columns from order by list. Constant
996
// columns are ones that have equality comparisons with
997
// constant expressions (e.g. x = 3)
998
orderByList.removeConstantColumns(wherePredicates);
999
1000                /*
1001                ** It's possible for the order by list to shrink to nothing
1002                ** as a result of removing constant columns. If this happens,
1003                ** get rid of the list entirely.
1004                */

1005                if (orderByList.size() == 0)
1006                {
1007                    orderByList = null;
1008                }
1009            }
1010        }
1011
1012        /* A valid group by without any aggregates is equivalent to
1013         * a distinct without the group by. We do the transformation
1014         * in order to simplify the group by code.
1015         */

1016        if (groupByList != null &&
1017            selectAggregates.size() == 0 &&
1018            whereAggregates.size() == 0)
1019        {
1020            isDistinct = true;
1021            groupByList = null;
1022        }
1023
1024        /* Consider distinct elimination based on a uniqueness condition.
1025         * In order to do this:
1026         * o All top level ColumnReferences in the select list are
1027         * from the same base table. (select t1.c1, t2.c2 + t3.c3 is
1028         * okay - t1 is the table of interest.)
1029         * o If the from list is a single table then the columns in the
1030         * select list plus the columns in the where clause that are
1031         * in = comparisons with constants or parameters must be a
1032         * superset of any unique index.
1033         * o If the from list has multiple tables then at least 1 table
1034         * meet the following - the set of columns in = comparisons
1035         * with constants or parameters is a superset of any unique
1036         * index on the table. All of the other tables must meet
1037         * the following - the set of columns in = comparisons with
1038         * constants, parameters or join columns is a superset of
1039         * any unique index on the table. If the table from which
1040         * the columns in the select list are coming from is in this
1041         * later group then the rule for it is to also include
1042         * the columns in the select list in the set of columns that
1043         * needs to be a superset of the unique index. Whew!
1044         */

1045        if (isDistinct && groupByList == null)
1046        {
1047            int distinctTable = resultColumns.allTopCRsFromSameTable();
1048            
1049            if (distinctTable != -1)
1050            {
1051                if (fromList.returnsAtMostSingleRow(resultColumns,
1052                                               whereClause, wherePredicates,
1053                                               getDataDictionary()))
1054                {
1055                    isDistinct = false;
1056                }
1057            }
1058
1059            /* If we were unable to eliminate the distinct and we have
1060             * an order by then we can consider eliminating the sort for the
1061             * order by. All of the columns in the order by list must
1062             * be ascending in order to do this. There are 2 cases:
1063             * o The order by list is an in order prefix of the columns
1064             * in the select list. In this case the output of the
1065             * sort from the distinct will be in the right order
1066             * so we simply eliminate the order by list.
1067             * o The order by list is a subset of the columns in the
1068             * the select list. In this case we need to reorder the
1069             * columns in the select list so that the ordering columns
1070             * are an in order prefix of the select list and put a PRN
1071             * above the select so that the shape of the result set
1072             * is as expected.
1073             */

1074            if (isDistinct && orderByList != null && orderByList.allAscending())
1075            {
1076                /* Order by list currently restricted to columns in select
1077                 * list, so we will always eliminate the order by here.
1078                 */

1079                if (orderByList.isInOrderPrefix(resultColumns))
1080                {
1081                    orderByList = null;
1082                }
1083                else
1084                {
1085                    /* Order by list is not an in order prefix of the select list
1086                     * so we must reorder the columns in the the select list to
1087                     * match the order by list and generate the PRN above us to
1088                     * preserve the expected order.
1089                     */

1090                    newTop = genProjectRestrictForReordering();
1091                    orderByList.resetToSourceRCs();
1092                    resultColumns = orderByList.reorderRCL(resultColumns);
1093                    orderByList = null;
1094                }
1095                orderByAndDistinctMerged = true;
1096            }
1097        }
1098
1099        /*
1100         * Push predicates that are pushable.
1101         *
1102         * NOTE: We pass the wherePredicates down to the new PRNs here,
1103         * so they can pull any clauses and possibily push them down further.
1104         * NOTE: We wait until all of the FromTables have been preprocessed
1105         * until we attempt to push down predicates, because we cannot push down
1106         * a predicate if the immediate source of any of its column references
1107         * is not a ColumnReference or a VirtualColumnNode.
1108         */

1109        fromList.pushPredicates(wherePredicates);
1110
1111        /* Set up the referenced table map */
1112        referencedTableMap = new JBitSet(numTables);
1113        int flSize = fromList.size();
1114        for (int index = 0; index < flSize; index++)
1115        {
1116            referencedTableMap.or(((FromTable) fromList.elementAt(index)).
1117                                                    getReferencedTableMap());
1118        }
1119
1120        /* Copy the referenced table map to the new tree top, if necessary */
1121        if (newTop != this)
1122        {
1123            newTop.setReferencedTableMap((JBitSet) referencedTableMap.clone());
1124        }
1125        return newTop;
1126    }
1127
1128    /**
1129     * Peform the various types of transitive closure on the where clause.
1130     * The 2 types are transitive closure on join clauses and on search clauses.
1131     * Join clauses will be processed first to maximize benefit for search clauses.
1132     *
1133     * @param numTables The number of tables in the query
1134     *
1135     * @exception StandardException Thrown on error
1136     */

1137    private void performTransitiveClosure(int numTables)
1138        throws StandardException
1139    {
1140        // Join clauses
1141
wherePredicates.joinClauseTransitiveClosure(numTables, fromList, getCompilerContext());
1142
1143        // Search clauses
1144
wherePredicates.searchClauseTransitiveClosure(numTables, fromList.hashJoinSpecified());
1145    }
1146
1147    /** Put the expression trees in conjunctive normal form
1148     *
1149     * @exception StandardException Thrown on error
1150     */

1151    private void normExpressions()
1152                throws StandardException
1153    {
1154        /* For each expression tree:
1155         * o Eliminate NOTs (eliminateNots())
1156         * o Ensure that there is an AndNode on top of every
1157         * top level expression. (putAndsOnTop())
1158         * o Finish the job (changeToCNF())
1159         */

1160        if (whereClause != null)
1161        {
1162            whereClause = whereClause.eliminateNots(false);
1163            if (SanityManager.DEBUG)
1164            {
1165                if (!(whereClause.verifyEliminateNots()) )
1166                {
1167                    whereClause.treePrint();
1168                    SanityManager.THROWASSERT(
1169                        "whereClause in invalid form: " + whereClause);
1170                }
1171            }
1172            whereClause = whereClause.putAndsOnTop();
1173            if (SanityManager.DEBUG)
1174            {
1175                if (! ((whereClause instanceof AndNode) &&
1176                       (whereClause.verifyPutAndsOnTop())) )
1177                {
1178                    whereClause.treePrint();
1179                    SanityManager.THROWASSERT(
1180                        "whereClause in invalid form: " + whereClause);
1181                }
1182            }
1183            whereClause = whereClause.changeToCNF(true);
1184            if (SanityManager.DEBUG)
1185            {
1186                if (! ((whereClause instanceof AndNode) &&
1187                       (whereClause.verifyChangeToCNF())) )
1188                {
1189                    whereClause.treePrint();
1190                    SanityManager.THROWASSERT(
1191                        "whereClause in invalid form: " + whereClause);
1192                }
1193            }
1194        }
1195    }
1196
1197    /**
1198     * Add a new predicate to the list. This is useful when doing subquery
1199     * transformations, when we build a new predicate with the left side of
1200     * the subquery operator and the subquery's result column.
1201     *
1202     * @param predicate The predicate to add
1203     *
1204     * @return ResultSetNode The new top of the tree.
1205     *
1206     * @exception StandardException Thrown on error
1207     */

1208    public ResultSetNode addNewPredicate(Predicate predicate)
1209            throws StandardException
1210    {
1211        wherePredicates.addPredicate(predicate);
1212        return this;
1213    }
1214
1215    /**
1216     * Evaluate whether or not the subquery in a FromSubquery is flattenable.
1217     * Currently, a FSqry is flattenable if all of the following are true:
1218     * o Subquery is a SelectNode. (ie, not a RowResultSetNode or a UnionNode)
1219     * o It contains a single table in its FROM list.
1220     * o It contains no subqueries in the SELECT list.
1221     * o It does not contain a group by or having clause
1222     * o It does not contain aggregates.
1223     * o It is not a DISTINCT.
1224     *
1225     * @param fromList The outer from list
1226     *
1227     * @return boolean Whether or not the FromSubquery is flattenable.
1228     */

1229    public boolean flattenableInFromSubquery(FromList fromList)
1230    {
1231        if (isDistinct)
1232        {
1233            return false;
1234        }
1235        if (this.fromList.size() > 1)
1236        {
1237            return false;
1238        }
1239
1240        /* Don't flatten (at least for now) if selectNode's SELECT list contains a subquery */
1241        if ((selectSubquerys != null) &&
1242             (selectSubquerys.size() > 0))
1243        {
1244            return false;
1245        }
1246
1247        /* Don't flatten if selectNode contains a group by or having clause */
1248        if ((groupByList != null) || generatedForHavingClause)
1249        {
1250            return false;
1251        }
1252
1253        /* Don't flatten if select list contains something that isn't cloneable.
1254         */

1255        if (! resultColumns.isCloneable())
1256        {
1257            return false;
1258        }
1259
1260        /* Don't flatten if selectNode contains an aggregate */
1261        if ((selectAggregates != null) &&
1262             (selectAggregates.size() > 0))
1263        {
1264            return false;
1265        }
1266
1267        return true;
1268    }
1269
1270    /**
1271     * Replace this SelectNode with a ProjectRestrictNode,
1272     * since it has served its purpose.
1273     *
1274     * @param origFromListSize The size of the original FROM list, before
1275     * generation of join tree.
1276     * @return ResultSetNode new ResultSetNode atop the query tree.
1277     *
1278     * @exception StandardException Thrown on error
1279     */

1280
1281    public ResultSetNode genProjectRestrict(int origFromListSize)
1282                throws StandardException
1283    {
1284        boolean orderingDependent = false;
1285        PredicateList restrictionList;
1286        ResultColumnList prRCList;
1287        ResultSetNode prnRSN;
1288
1289
1290        prnRSN = (ResultSetNode) getNodeFactory().getNode(
1291                                C_NodeTypes.PROJECT_RESTRICT_NODE,
1292                                fromList.elementAt(0), /* Child ResultSet */
1293                                resultColumns, /* Projection */
1294                                whereClause, /* Restriction */
1295                                wherePredicates,/* Restriction as PredicateList */
1296                                selectSubquerys,/* Subquerys in Projection */
1297                                whereSubquerys, /* Subquerys in Restriction */
1298                                null,
1299                                getContextManager() );
1300
1301        /*
1302        ** If we have aggregates OR a select list we want
1303        ** to generate a GroupByNode. In the case of a
1304        ** scalar aggregate we have no grouping columns.
1305        **
1306        ** JRESOLVE: what about correlated aggregates from another
1307        ** block.
1308        */

1309        if (((selectAggregates != null) && (selectAggregates.size() > 0))
1310            || (groupByList != null))
1311        {
1312            GroupByNode gbn = (GroupByNode) getNodeFactory().getNode(
1313                                                C_NodeTypes.GROUP_BY_NODE,
1314                                                prnRSN,
1315                                                groupByList,
1316                                                selectAggregates,
1317                                                null,
1318                                                getContextManager());
1319            gbn.considerPostOptimizeOptimizations(originalWhereClause != null);
1320            gbn.assignCostEstimate(optimizer.getOptimizedCost());
1321
1322            groupByList = null;
1323            prnRSN = gbn.getParent();
1324
1325            // Remember if the result is dependent on the ordering
1326
orderingDependent = orderingDependent || gbn.getIsInSortedOrder();
1327        }
1328
1329        // if it is distinct, that must also be taken care of.
1330
if (isDistinct)
1331        {
1332            // We first verify that a distinct is valid on the
1333
// RCL.
1334
resultColumns.verifyAllOrderable();
1335
1336            /* See if we can push duplicate elimination into the store
1337             * via a hash scan. This is possible iff:
1338             * o A single table query
1339             * o We haven't merged the order by and distinct sorts.
1340             * (Results do not have to be in a particular order.)
1341             * o All entries in the select's RCL are ColumnReferences.
1342             * o No predicates (This is because we currently do not
1343             * differentiate between columns referenced in the select
1344             * list and columns referenced in other clauses. In other
1345             * words, the store will do duplicate elimination based on
1346             * all referenced columns.)
1347             * RESOLVE - We can change this to be all referenced columns
1348             * have to be in the select list. In that case, we need to
1349             * refine which predicates are allowed. Basically, all predicates
1350             * must have been pushed down to the index/table scan.(If we make
1351             * this change, then we need to verify that non of the columns in
1352             * the predicates are correlated columns.)
1353             * o NOTE: The implementation of isPossibleDistinctScan() will return
1354             * false if there is an IndexRowToBaseRow above the
1355             * FromBaseTable. This is because all of a table's columns must come
1356             * from the same conglomerate in order to get consistent data.
1357             */

1358            boolean distinctScanPossible = false;
1359            if (origFromListSize == 1 &&
1360                (! orderByAndDistinctMerged) &&
1361                resultColumns.countNumberOfSimpleColumnReferences() == resultColumns.size())
1362            {
1363                boolean simpleColumns = true;
1364                HashSet JavaDoc distinctColumns = new HashSet JavaDoc();
1365                int size = resultColumns.size();
1366                for (int i = 1; i <= size; i++) {
1367                    BaseColumnNode bc = resultColumns.getResultColumn(i).getBaseColumnNode();
1368                    if (bc == null) {
1369                        simpleColumns = false;
1370                        break;
1371                    }
1372                    distinctColumns.add(bc);
1373                }
1374                if (simpleColumns && prnRSN.isPossibleDistinctScan(distinctColumns)) {
1375                    prnRSN.markForDistinctScan();
1376                    distinctScanPossible = true;
1377                }
1378            }
1379
1380            if (!distinctScanPossible)
1381            {
1382                /* We can't do a distinct scan. Determine if we can filter out
1383                 * duplicates without a sorter.
1384                 */

1385                boolean inSortedOrder = isOrderedResult(resultColumns, prnRSN, !(orderByAndDistinctMerged));
1386                prnRSN = (ResultSetNode) getNodeFactory().getNode(
1387                                            C_NodeTypes.DISTINCT_NODE,
1388                                            prnRSN,
1389                                            new Boolean JavaDoc(inSortedOrder),
1390                                            null,
1391                                            getContextManager());
1392                prnRSN.costEstimate = costEstimate.cloneMe();
1393
1394                // Remember if the result is dependent on the ordering
1395
orderingDependent = orderingDependent || inSortedOrder;
1396            }
1397        }
1398
1399        /* Generate the OrderByNode if a sort is still required for
1400         * the order by.
1401         */

1402        if (orderByList != null)
1403        {
1404            if (orderByList.getSortNeeded())
1405            {
1406                prnRSN = (ResultSetNode) getNodeFactory().getNode(
1407                                                C_NodeTypes.ORDER_BY_NODE,
1408                                                prnRSN,
1409                                                orderByList,
1410                                                null,
1411                                                getContextManager());
1412                prnRSN.costEstimate = costEstimate.cloneMe();
1413            }
1414
1415            int orderBySelect = this.getResultColumns().getOrderBySelect();
1416            if (orderBySelect > 0)
1417            {
1418                ResultColumnList selectRCs = prnRSN.getResultColumns().copyListAndObjects();
1419                int wholeSize = selectRCs.size();
1420                for (int i = wholeSize - 1; orderBySelect > 0; i--, orderBySelect--)
1421                    selectRCs.removeElementAt(i);
1422                selectRCs.genVirtualColumnNodes(prnRSN, prnRSN.getResultColumns());
1423                prnRSN = (ResultSetNode) getNodeFactory().getNode(
1424                                C_NodeTypes.PROJECT_RESTRICT_NODE,
1425                                prnRSN,
1426                                selectRCs,
1427                                null,
1428                                null,
1429                                null,
1430                                null,
1431                                null,
1432                                getContextManager());
1433            }
1434        }
1435
1436        if (!(orderByList != null && orderByList.getSortNeeded()) && orderByQuery)
1437        {
1438            // Remember if the result is dependent on the ordering
1439
orderingDependent = true;
1440        }
1441
1442        /* If the result is ordering dependent, then we must
1443         * tell the underlying tree. At minimum, this means no
1444         * group fetch on an index under an IndexRowToBaseRow
1445         * since that could lead to incorrect results. (Bug 2347.)
1446         */

1447        if (orderingDependent)
1448        {
1449            prnRSN.markOrderingDependent();
1450        }
1451
1452        /* Set the cost of this node in the generated node */
1453        prnRSN.costEstimate = costEstimate.cloneMe();
1454
1455        return prnRSN;
1456    }
1457
1458    /**
1459     * Is the result of this node an ordered result set. An ordered result set
1460     * means that the results from this node will come in a known sorted order.
1461     * This means that the data is ordered according to the order of the elements in the RCL.
1462     * Today, the data is considered ordered if:
1463     * o The RCL is composed entirely of CRs or ConstantNodes
1464     * o The underlying tree is ordered on the CRs in the order in which
1465     * they appear in the RCL, taking equality predicates into account.
1466     * Future Enhancements:
1467     * o The prefix will not be required to be in order. (We will need to
1468     * reorder the RCL and generate a PRN with an RCL in the expected order.)
1469     *
1470     * @return boolean Whether or not this node returns an ordered result set.
1471     *
1472     * @exception StandardException Thrown on error
1473     */

1474    private boolean isOrderedResult(ResultColumnList resultColumns,
1475                                          ResultSetNode newTopRSN,
1476                                          boolean permuteOrdering)
1477        throws StandardException
1478    {
1479        int rclSize = resultColumns.size();
1480
1481        /* Not ordered if RCL contains anything other than a ColumnReference
1482         * or a ConstantNode.
1483         */

1484        int numCRs = 0;
1485        for (int index = 0; index < rclSize; index++)
1486        {
1487            ResultColumn rc = (ResultColumn) resultColumns.elementAt(index);
1488            if (rc.getExpression() instanceof ColumnReference)
1489            {
1490                numCRs++;
1491            }
1492            else if (! (rc.getExpression() instanceof ConstantNode))
1493            {
1494                return false;
1495            }
1496        }
1497
1498        // Corner case, all constants
1499
if (numCRs == 0)
1500        {
1501            return true;
1502        }
1503
1504        ColumnReference[] crs = new ColumnReference[numCRs];
1505
1506        // Now populate the CR array and see if ordered
1507
int crsIndex = 0;
1508        for (int index = 0; index < rclSize; index++)
1509        {
1510            ResultColumn rc = (ResultColumn) resultColumns.elementAt(index);
1511            if (rc.getExpression() instanceof ColumnReference)
1512            {
1513                crs[crsIndex++] = (ColumnReference) rc.getExpression();
1514            }
1515        }
1516
1517        return newTopRSN.isOrderedOn(crs, permuteOrdering, (Vector JavaDoc)null);
1518    }
1519
1520    /**
1521     * Ensure that the top of the RSN tree has a PredicateList.
1522     *
1523     * @param numTables The number of tables in the query.
1524     * @return ResultSetNode A RSN tree with a node which has a PredicateList on top.
1525     *
1526     * @exception StandardException Thrown on error
1527     */

1528    public ResultSetNode ensurePredicateList(int numTables)
1529        throws StandardException
1530    {
1531        return this;
1532    }
1533
1534    /**
1535     * Optimize this SelectNode. This means choosing the best access path
1536     * for each table, among other things.
1537     *
1538     * @param dataDictionary The DataDictionary to use for optimization
1539     * @param predicateList The predicate list to optimize against
1540     * @param outerRows The number of outer joining rows
1541     *
1542     * @return ResultSetNode The top of the optimized tree
1543     *
1544     * @exception StandardException Thrown on error
1545     */

1546
1547    public ResultSetNode optimize(DataDictionary dataDictionary,
1548                                  PredicateList predicateList,
1549                                  double outerRows)
1550                throws StandardException
1551    {
1552        Optimizer optimizer;
1553
1554        /* Optimize any subquerys before optimizing the underlying result set */
1555
1556        /* selectSubquerys is always allocated at bind() time */
1557        if (SanityManager.DEBUG)
1558        SanityManager.ASSERT(selectSubquerys != null,
1559            "selectSubquerys is expected to be non-null");
1560
1561        /* If this select node is the child of an outer node that is
1562         * being optimized, we can get here multiple times (once for
1563         * every permutation that is done for the outer node). With
1564         * DERBY-805, we can add optimizable predicates to the WHERE
1565         * list as part of this method; thus, before proceeding we
1566         * need go through and remove any opt predicates that we added
1567         * to our WHERE list the last time we were here; if we don't
1568         * do that, we'll end up with the same predicates in our
1569         * WHERE list multiple times, which can lead to incorrect
1570         * optimization.
1571         */

1572
1573        if (wherePredicates != null)
1574        {
1575            // Iterate backwards because we might be deleting entries.
1576
for (int i = wherePredicates.size() - 1; i >= 0; i--)
1577            {
1578                if (((Predicate)wherePredicates.elementAt(i)).isScopedForPush())
1579                    wherePredicates.removeOptPredicate(i);
1580            }
1581        }
1582
1583        /* Get a new optimizer */
1584
1585        /* With DERBY-805 we take any optimizable predicates that
1586         * were pushed into this node and we add them to the list of
1587         * predicates that we pass to the optimizer, thus allowing
1588         * the optimizer to use them when choosing an access path
1589         * for this SELECT node. We do that by adding the predicates
1590         * to our WHERE list, since the WHERE predicate list is what
1591         * we pass to the optimizer for this select node (see below).
1592         * We have to pass the WHERE list directly (as opposed to
1593         * passing a copy) because the optimizer is only created one
1594         * time; it then uses the list we pass it for the rest of the
1595         * optimization phase and finally for "modifyAccessPaths()".
1596         * Since the optimizer can update/modify the list based on the
1597         * WHERE predicates (such as by adding internal predicates or
1598         * by modifying the actual predicates themselves), we need
1599         * those changes to be applied to the WHERE list directly for
1600         * subsequent processing (esp. for modification of the access
1601         * path). Note that by adding outer opt predicates directly
1602         * to the WHERE list, we're changing the semantics of this
1603         * SELECT node. This is only temporary, though--once the
1604         * optimizer is done with all of its work, any predicates
1605         * that were pushed here will have been pushed even further
1606         * down and thus will have been removed from the WHERE list
1607         * (if it's not possible to push them further down, then they
1608         * shouldn't have made it this far to begin with).
1609         */

1610        if (predicateList != null)
1611        {
1612            if (wherePredicates == null) {
1613                wherePredicates = (PredicateList) getNodeFactory().getNode(
1614                        C_NodeTypes.PREDICATE_LIST,
1615                        getContextManager());
1616            }
1617
1618            Predicate pred = null;
1619            int sz = predicateList.size();
1620            for (int i = sz - 1; i >= 0; i--)
1621            {
1622                // We can tell if a predicate was pushed into this select
1623
// node because it will have been "scoped" for this node
1624
// or for some result set below this one.
1625
pred = (Predicate)predicateList.getOptPredicate(i);
1626                if (pred.isScopedToSourceResultSet())
1627                {
1628                    // If we're pushing the predicate down here, we have to
1629
// remove it from the predicate list of the node above
1630
// this select, in order to keep in line with established
1631
// push 'protocol'.
1632
wherePredicates.addOptPredicate(pred);
1633                    predicateList.removeOptPredicate(pred);
1634                }
1635            }
1636        }
1637
1638        optimizer = getOptimizer(fromList,
1639                                wherePredicates,
1640                                dataDictionary,
1641                                orderByList);
1642        optimizer.setOuterRows(outerRows);
1643
1644        /* Optimize this SelectNode */
1645        while (optimizer.getNextPermutation())
1646        {
1647            while (optimizer.getNextDecoratedPermutation())
1648            {
1649                optimizer.costPermutation();
1650            }
1651        }
1652
1653        /* When we're done optimizing, any scoped predicates that
1654         * we pushed down the tree should now be sitting again
1655         * in our wherePredicates list. Put those back in the
1656         * the list from which we received them, to allow them
1657         * to be "pulled" back up to where they came from.
1658         */

1659        if (wherePredicates != null)
1660        {
1661            Predicate pred = null;
1662            for (int i = wherePredicates.size() - 1; i >= 0; i--)
1663            {
1664                pred = (Predicate)wherePredicates.getOptPredicate(i);
1665                if (pred.isScopedForPush())
1666                {
1667                    predicateList.addOptPredicate(pred);
1668                    wherePredicates.removeOptPredicate(pred);
1669                }
1670            }
1671        }
1672
1673        /* Get the cost */
1674        costEstimate = optimizer.getOptimizedCost();
1675
1676        /* Update row counts if this is a scalar aggregate */
1677        if ((selectAggregates != null) && (selectAggregates.size() > 0))
1678        {
1679            costEstimate.setEstimatedRowCount((long) outerRows);
1680            costEstimate.setSingleScanRowCount(1);
1681        }
1682
1683        selectSubquerys.optimize(dataDictionary, costEstimate.rowCount());
1684
1685        if (whereSubquerys != null && whereSubquerys.size() > 0)
1686        {
1687            whereSubquerys.optimize(dataDictionary, costEstimate.rowCount());
1688        }
1689
1690        return this;
1691    }
1692
1693    /**
1694     * Modify the access paths according to the decisions the optimizer
1695     * made. This can include adding project/restrict nodes,
1696     * index-to-base-row nodes, etc.
1697     *
1698     * @param predList A list of optimizable predicates that should
1699     * be pushed to this ResultSetNode, as determined by optimizer.
1700     * @return The modified query tree
1701     * @exception StandardException Thrown on error
1702     */

1703    public ResultSetNode modifyAccessPaths(PredicateList predList)
1704        throws StandardException
1705    {
1706        // Take the received list of predicates and propagate them to the
1707
// predicate list for this node's optimizer. Then, when we call
1708
// optimizer.modifyAccessPaths(), the optimizer will have the
1709
// predicates and can push them down as necessary, according
1710
// the join order that it has chosen.
1711

1712        if (SanityManager.DEBUG)
1713        {
1714            SanityManager.ASSERT(optimizer != null,
1715                "SelectNode's optimizer not expected to be null when " +
1716                "modifying access paths.");
1717        }
1718
1719        ((OptimizerImpl)optimizer).addScopedPredicatesToList(predList);
1720        return modifyAccessPaths();
1721    }
1722
1723    /**
1724     * Modify the access paths according to the choices the optimizer made.
1725     *
1726     * @return A QueryTree with the necessary modifications made
1727     *
1728     * @exception StandardException Thrown on error
1729     */

1730    public ResultSetNode modifyAccessPaths() throws StandardException
1731    {
1732        int origFromListSize = fromList.size();
1733        ResultColumnList leftRCList;
1734        ResultColumnList rightRCList;
1735        ResultSetNode leftResultSet;
1736        ResultSetNode rightResultSet;
1737
1738        /*
1739        ** Modify the access path for each Optimizable, as necessary
1740        **
1741        ** This should be the same optimizer we got above.
1742        */

1743        optimizer.modifyAccessPaths();
1744
1745        // Load the costEstimate for the final "best" join order.
1746
costEstimate = optimizer.getFinalCost();
1747
1748        if (SanityManager.DEBUG)
1749        {
1750            // When we optimized this select node, we may have added pushable
1751
// outer predicates to the wherePredicates list for this node
1752
// (see the optimize() method above). When we did so, we said
1753
// that all such predicates should have been removed from the
1754
// where list by the time optimization was completed. So we
1755
// check that here, just to be safe. NOTE: We do this _after_
1756
// calling optimizer.modifyAccessPaths(), because it's only in
1757
// that call that the scoped predicates are officially pushed
1758
// and thus removed from the list.
1759
if (wherePredicates != null)
1760            {
1761                Predicate pred = null;
1762                for (int i = wherePredicates.size() - 1; i >= 0; i--)
1763                {
1764                    pred = (Predicate)wherePredicates.getOptPredicate(i);
1765                    if (pred.isScopedForPush())
1766                    {
1767                        SanityManager.THROWASSERT("Found scoped predicate " +
1768                            pred.binaryRelOpColRefsToString() +
1769                            " in WHERE list when no scoped predicates were" +
1770                            " expected.");
1771                    }
1772                }
1773            }
1774        }
1775
1776        selectSubquerys.modifyAccessPaths();
1777
1778        if (whereSubquerys != null && whereSubquerys.size() > 0)
1779        {
1780            whereSubquerys.modifyAccessPaths();
1781        }
1782
1783        /* Build a temp copy of the current FromList for sort elimination, etc. */
1784        preJoinFL.removeAllElements();
1785        preJoinFL.nondestructiveAppend(fromList);
1786
1787        /* Now we build a JoinNode tree from the bottom up until there is only
1788         * a single entry in the fromList and that entry points to the top of
1789         * the JoinNode tree.
1790         *
1791         * While there is still more than 1 entry in the list, create a JoinNode
1792         * which points to the 1st 2 entries in the list. This JoinNode becomes
1793         * the new 1st entry in the list and the 2nd entry is deleted. The
1794         * old 1st and 2nd entries will get shallow copies of their
1795         * ResultColumnLists. The JoinNode's ResultColumnList will be the
1796         * concatenation of the originals from the old 1st and 2nd entries.
1797         * The virtualColumnIds will be updated to reflect there new positions
1798         * and each ResultColumn.expression will be replaced with a new
1799         * VirtualColumnNode.
1800         */

1801        while (fromList.size() > 1)
1802        {
1803            /* Get left's ResultColumnList, assign shallow copy back to it
1804             * and create new VirtualColumnNodes for the original's
1805             * ResultColumn.expressions.
1806             */

1807            leftResultSet = (ResultSetNode) fromList.elementAt(0);
1808            leftRCList = leftResultSet.getResultColumns();
1809            leftResultSet.setResultColumns(leftRCList.copyListAndObjects());
1810            leftRCList.genVirtualColumnNodes(leftResultSet, leftResultSet.resultColumns);
1811
1812            /* Get right's ResultColumnList, assign shallow copy back to it,
1813             * create new VirtualColumnNodes for the original's
1814             * ResultColumn.expressions and increment the virtualColumnIds.
1815             * (Right gets appended to left, so only right's ids need updating.)
1816             */

1817            rightResultSet = (ResultSetNode) fromList.elementAt(1);
1818            rightRCList = rightResultSet.getResultColumns();
1819            rightResultSet.setResultColumns(rightRCList.copyListAndObjects());
1820            rightRCList.genVirtualColumnNodes(rightResultSet, rightResultSet.resultColumns);
1821            rightRCList.adjustVirtualColumnIds(leftRCList.size());
1822
1823            /* Concatenate the 2 ResultColumnLists */
1824            leftRCList.nondestructiveAppend(rightRCList);
1825
1826            /* Now we're finally ready to generate the JoinNode and have it
1827             * replace the 1st 2 entries in the FromList.
1828             */

1829            fromList.setElementAt(
1830                         (JoinNode) getNodeFactory().getNode(
1831                                                C_NodeTypes.JOIN_NODE,
1832                                                leftResultSet,
1833                                                rightResultSet,
1834                                                null,
1835                                                null,
1836                                                leftRCList,
1837                                                null,
1838                                                //user supplied optimizer overrides
1839
fromList.properties,
1840                                                getContextManager()
1841                                                ),
1842                            0
1843                        );
1844
1845            fromList.removeElementAt(1);
1846        }
1847
1848        return genProjectRestrict(origFromListSize);
1849    }
1850
1851    /**
1852     * Get the final CostEstimate for this SelectNode.
1853     *
1854     * @return The final CostEstimate for this SelectNode, which is
1855     * the final cost estimate for the best join order of
1856     * this SelectNode's optimizer.
1857     */

1858    public CostEstimate getFinalCostEstimate()
1859        throws StandardException
1860    {
1861        return optimizer.getFinalCost();
1862    }
1863
1864    /**
1865        Determine if this select is updatable or not, for a cursor.
1866     */

1867    boolean isUpdatableCursor(DataDictionary dd) throws StandardException
1868    {
1869        TableDescriptor targetTableDescriptor;
1870
1871        if (isDistinct)
1872        {
1873            if (SanityManager.DEBUG)
1874            SanityManager.DEBUG("DumpUpdateCheck","cursor select has distinct");
1875            return false;
1876        }
1877
1878        if ((selectAggregates == null) || (selectAggregates.size() > 0))
1879        {
1880            return false;
1881        }
1882
1883        if (groupByList != null || generatedForHavingClause)
1884        {
1885            return false;
1886        }
1887
1888        if (SanityManager.DEBUG)
1889        SanityManager.ASSERT(fromList!=null, "select must have from tables");
1890        if (fromList.size() != 1)
1891        {
1892            if (SanityManager.DEBUG)
1893            SanityManager.DEBUG("DumpUpdateCheck","cursor select has more than one from table");
1894            return false;
1895        }
1896
1897        targetTable = (FromTable)(fromList.elementAt(0));
1898
1899        if (targetTable instanceof FromVTI) {
1900
1901            return ((FromVTI) targetTable).isUpdatableCursor();
1902        }
1903
1904        if (! (targetTable instanceof FromBaseTable))
1905        {
1906            if (SanityManager.DEBUG)
1907            SanityManager.DEBUG("DumpUpdateCheck","cursor select has non base table as target table");
1908            return false;
1909        }
1910
1911
1912        /* Get the TableDescriptor and verify that it is not for a
1913         * view or a system table.
1914         * NOTE: We need to use the base table name for the table.
1915         * Simplest way to get it is from a FromBaseTable. We
1916         * know that targetTable is a FromBaseTable because of check
1917         * just above us.
1918         * NOTE: We also need to use the base table's schema name; otherwise
1919         * we will think it is the default schema Beetle 4417
1920         */

1921        targetTableDescriptor = getTableDescriptor(
1922                        ((FromBaseTable)targetTable).getBaseTableName(),
1923            getSchemaDescriptor(((FromBaseTable)targetTable).getTableNameField().getSchemaName()));
1924        if (targetTableDescriptor.getTableType() == TableDescriptor.SYSTEM_TABLE_TYPE)
1925        {
1926            if (SanityManager.DEBUG)
1927            SanityManager.DEBUG("DumpUpdateCheck","cursor select is on system table");
1928            return false;
1929        }
1930        if (targetTableDescriptor.getTableType() == TableDescriptor.VIEW_TYPE)
1931        {
1932            if (SanityManager.DEBUG)
1933            SanityManager.DEBUG("DumpUpdateCheck","cursor select is on view");
1934            return false;
1935        }
1936        if ((getSelectSubquerys() != null) &&
1937            (getSelectSubquerys().size() != 0))
1938        {
1939            if (SanityManager.DEBUG)
1940            SanityManager.DEBUG("DumpUpdateCheck","cursor select has subquery in SELECT list");
1941            return false;
1942        }
1943
1944        if ((getWhereSubquerys() != null) &&
1945            (getWhereSubquerys().size() != 0))
1946        {
1947            if (SanityManager.DEBUG)
1948            SanityManager.DEBUG("DumpUpdateCheck","cursor select has subquery in WHERE clause");
1949            return false;
1950        }
1951
1952        return true;
1953    }
1954
1955    /**
1956        Assumes that isCursorUpdatable has been called, and that it
1957        is only called for updatable cursors.
1958     */

1959    FromTable getCursorTargetTable()
1960    {
1961        if (SanityManager.DEBUG)
1962        SanityManager.ASSERT(targetTable!=null,
1963            "must call isUpdatableCursor() first, and must be updatable");
1964        return targetTable;
1965    }
1966
1967    /**
1968     * Search to see if a query references the specifed table name.
1969     *
1970     * @param name Table name (String) to search for.
1971     * @param baseTable Whether or not name is for a base table
1972     *
1973     * @return true if found, else false
1974     *
1975     * @exception StandardException Thrown on error
1976     */

1977    public boolean referencesTarget(String JavaDoc name, boolean baseTable)
1978        throws StandardException
1979    {
1980        if (fromList.referencesTarget(name, baseTable) ||
1981            (selectSubquerys != null && selectSubquerys.referencesTarget(name, baseTable)) ||
1982            (whereSubquerys != null && whereSubquerys.referencesTarget(name, baseTable))
1983           )
1984        {
1985            return true;
1986        }
1987        return false;
1988    }
1989
1990    /**
1991     * @see QueryTreeNode#disablePrivilegeCollection
1992     */

1993    public void disablePrivilegeCollection()
1994    {
1995        super.disablePrivilegeCollection();
1996        int fromListSize = fromList.size();
1997        for( int i = 0; i < fromListSize; i++)
1998            ((FromTable) fromList.elementAt(i)).disablePrivilegeCollection();
1999    }
2000
2001    /**
2002     * Return whether or not this ResultSetNode contains a subquery with a
2003     * reference to the specified target table.
2004     *
2005     * @param name The table name.
2006     * @param baseTable Whether or not table is a base table.
2007     *
2008     * @return boolean Whether or not a reference to the table was found.
2009     *
2010     * @exception StandardException Thrown on error
2011     */

2012    boolean subqueryReferencesTarget(String JavaDoc name, boolean baseTable)
2013        throws StandardException
2014    {
2015        if ((selectSubquerys != null && selectSubquerys.referencesTarget(name, baseTable)) ||
2016            (whereSubquerys != null && whereSubquerys.referencesTarget(name, baseTable))
2017           )
2018        {
2019            return true;
2020        }
2021        return false;
2022    }
2023
2024    /**
2025     * Bind any untyped null nodes to the types in the given ResultColumnList.
2026     *
2027     * @param bindingRCL The ResultColumnList with the types to bind to.
2028     *
2029     * @exception StandardException Thrown on error
2030     */

2031    public void bindUntypedNullsToResultColumns(ResultColumnList bindingRCL)
2032                throws StandardException
2033    {
2034        fromList.bindUntypedNullsToResultColumns(bindingRCL);
2035    }
2036
2037    /**
2038     * Decrement (query block) level (0-based) for
2039     * all of the tables in this ResultSet tree.
2040     * This is useful when flattening a subquery.
2041     *
2042     * @param decrement The amount to decrement by.
2043     */

2044    void decrementLevel(int decrement)
2045    {
2046        /* Decrement the level in the tables */
2047        fromList.decrementLevel(decrement);
2048        selectSubquerys.decrementLevel(decrement);
2049        whereSubquerys.decrementLevel(decrement);
2050        /* Decrement the level in any CRs in predicates
2051         * that are interesting to transitive closure.
2052         */

2053        wherePredicates.decrementLevel(fromList, decrement);
2054    }
2055    
2056    /**
2057     * Determine whether or not this subquery,
2058     * the SelectNode is in a subquery, can be flattened
2059     * into the outer query block based on a uniqueness condition.
2060     * A uniqueness condition exists when we can guarantee
2061     * that at most 1 row will qualify in each table in the
2062     * subquery. This is true if every table in the from list is
2063     * (a base table and the set of columns from the table that
2064     * are in equality comparisons with expressions that do not
2065     * include a column from the same table is a superset of any unique index
2066     * on the table) or an ExistsBaseTable.
2067     *
2068     * @param additionalEQ Whether or not the column returned
2069     * by this select, if it is a ColumnReference,
2070     * is in an equality comparison.
2071     *
2072     * @return Whether or not this subquery can be flattened based
2073     * on a uniqueness condition.
2074     *
2075     * @exception StandardException Thrown on error
2076     */

2077    boolean uniqueSubquery(boolean additionalEQ)
2078        throws StandardException
2079    {
2080        ColumnReference additionalCR = null;
2081        ResultColumn rc = (ResultColumn) getResultColumns().elementAt(0);
2082
2083        /* Figure out if we have an additional ColumnReference
2084         * in an equality comparison.
2085         */

2086        if (additionalEQ &&
2087            rc.getExpression() instanceof ColumnReference)
2088        {
2089            additionalCR = (ColumnReference) rc.getExpression();
2090
2091            /* ColumnReference only interesting if it is
2092             * not correlated.
2093             */

2094            if (additionalCR.getCorrelated())
2095            {
2096                additionalCR = null;
2097            }
2098        }
2099
2100        return fromList.returnsAtMostSingleRow((additionalCR == null) ? null : getResultColumns(),
2101                                               whereClause, wherePredicates,
2102                                               getDataDictionary());
2103    }
2104
2105    /**
2106     * Get the lock mode for the target of an update statement
2107     * (a delete or update). The update mode will always be row for
2108     * CurrentOfNodes. It will be table if there is no where clause.
2109     *
2110     * @see TransactionController
2111     *
2112     * @return The lock mode
2113     */

2114    public int updateTargetLockMode()
2115    {
2116        /* Do row locking if there is a restriction */
2117        return fromList.updateTargetLockMode();
2118    }
2119
2120    /**
2121     * Return whether or not this ResultSet tree is guaranteed to return
2122     * at most 1 row based on heuristics. (A RowResultSetNode and a
2123     * SELECT with a non-grouped aggregate will return at most 1 row.)
2124     *
2125     * @return Whether or not this ResultSet tree is guaranteed to return
2126     * at most 1 row based on heuristics.
2127     */

2128    boolean returnsAtMostOneRow()
2129    {
2130        return (groupByList == null && selectAggregates != null && selectAggregates.size() != 0);
2131    }
2132
2133    /**
2134     * Return true if the node references SESSION schema tables (temporary or permanent)
2135     *
2136     * @return true if references SESSION schema tables, else false
2137     *
2138     * @exception StandardException Thrown on error
2139     */

2140    public boolean referencesSessionSchema()
2141        throws StandardException
2142    {
2143        if (fromList.referencesSessionSchema() ||
2144            (selectSubquerys != null && selectSubquerys.referencesSessionSchema()) ||
2145            (whereSubquerys != null && whereSubquerys.referencesSessionSchema()))
2146                    return true;
2147
2148        return false;
2149    }
2150
2151    /**
2152     * Accept a visitor, and call v.visit()
2153     * on child nodes as necessary.
2154     *
2155     * @param v the visitor
2156     *
2157     * @exception StandardException on error
2158     */

2159    public Visitable accept(Visitor v)
2160        throws StandardException
2161    {
2162        Visitable returnNode = v.visit(this);
2163
2164        if (v.skipChildren(this))
2165        {
2166            return returnNode;
2167        }
2168
2169        if (!v.stopTraversal())
2170        {
2171            super.accept(v);
2172        }
2173
2174        if (fromList != null && !v.stopTraversal())
2175        {
2176            fromList = (FromList)fromList.accept(v);
2177        }
2178
2179        if (whereClause != null && !v.stopTraversal())
2180        {
2181            whereClause = (ValueNode)whereClause.accept(v);
2182        }
2183
2184        if (wherePredicates != null && !v.stopTraversal())
2185        {
2186            wherePredicates = (PredicateList)wherePredicates.accept(v);
2187        }
2188
2189        return returnNode;
2190    }
2191}
2192
Popular Tags