Source Code Cross Referenced for SelectNode.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » impl » sql » compile » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » db derby 10.2 » org.apache.derby.impl.sql.compile 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:
0003:           Derby - Class org.apache.derby.impl.sql.compile.SelectNode
0004:
0005:           Licensed to the Apache Software Foundation (ASF) under one or more
0006:           contributor license agreements.  See the NOTICE file distributed with
0007:           this work for additional information regarding copyright ownership.
0008:           The ASF licenses this file to you under the Apache License, Version 2.0
0009:           (the "License"); you may not use this file except in compliance with
0010:           the License.  You may obtain a copy of the License at
0011:
0012:              http://www.apache.org/licenses/LICENSE-2.0
0013:
0014:           Unless required by applicable law or agreed to in writing, software
0015:           distributed under the License is distributed on an "AS IS" BASIS,
0016:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017:           See the License for the specific language governing permissions and
0018:           limitations under the License.
0019:
0020:         */
0021:
0022:        package org.apache.derby.impl.sql.compile;
0023:
0024:        import org.apache.derby.iapi.sql.compile.CostEstimate;
0025:        import org.apache.derby.iapi.sql.compile.Optimizer;
0026:        import org.apache.derby.iapi.sql.compile.Visitable;
0027:        import org.apache.derby.iapi.sql.compile.Visitor;
0028:        import org.apache.derby.iapi.sql.compile.C_NodeTypes;
0029:
0030:        import org.apache.derby.iapi.sql.conn.Authorizer;
0031:
0032:        import org.apache.derby.iapi.sql.dictionary.DataDictionary;
0033:        import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
0034:
0035:        import org.apache.derby.iapi.types.TypeId;
0036:        import org.apache.derby.iapi.types.DataTypeDescriptor;
0037:
0038:        import org.apache.derby.iapi.reference.Limits;
0039:        import org.apache.derby.iapi.reference.SQLState;
0040:        import org.apache.derby.iapi.error.StandardException;
0041:
0042:        import org.apache.derby.iapi.store.access.TransactionController;
0043:
0044:        import org.apache.derby.iapi.services.sanity.SanityManager;
0045:
0046:        import org.apache.derby.iapi.util.JBitSet;
0047:
0048:        import java.util.Vector;
0049:        import java.util.HashSet;
0050:
0051:        /**
0052:         * A SelectNode represents the result set for any of the basic DML
0053:         * operations: SELECT, INSERT, UPDATE, and DELETE.  (A RowResultSetNode
0054:         * will be used for an INSERT with a VALUES clause.)  For INSERT - SELECT,
0055:         * any of the fields in a SelectNode can be used (the SelectNode represents
0056:         * the SELECT statement in the INSERT - SELECT).  For UPDATE and
0057:         * DELETE, there will be one table in the fromList, and the groupByList
0058:         * fields will be null. For both INSERT and UPDATE,
0059:         * the resultColumns in the selectList will contain the names of the columns
0060:         * being inserted into or updated.
0061:         *
0062:         * @author Jeff Lichtman
0063:         */
0064:
0065:        public class SelectNode extends ResultSetNode {
0066:            /**
0067:             * List of tables in the FROM clause of this SELECT
0068:             */
0069:            FromList fromList;
0070:            FromTable targetTable;
0071:
0072:            /* Aggregate Vectors for select and where clauses */
0073:            Vector selectAggregates;
0074:            Vector whereAggregates;
0075:
0076:            /**
0077:             * The ValueNode for the WHERE clause must represent a boolean
0078:             * expression.  The binding phase will enforce this - the parser
0079:             * does not have enough information to enforce it in all cases
0080:             * (for example, user methods that return boolean).
0081:             */
0082:            ValueNode whereClause;
0083:            ValueNode originalWhereClause;
0084:
0085:            /**
0086:             * List of result columns in GROUP BY clause
0087:             */
0088:            GroupByList groupByList;
0089:
0090:            /* List of columns in ORDER BY list */
0091:            OrderByList orderByList;
0092:            boolean orderByQuery;
0093:
0094:            /* PredicateLists for where clause */
0095:            PredicateList wherePredicates;
0096:
0097:            /* SubqueryLists for select and where clauses */
0098:            SubqueryList selectSubquerys;
0099:            SubqueryList whereSubquerys;
0100:
0101:            /* Whether or not we are only binding the target list */
0102:            private boolean bindTargetListOnly;
0103:
0104:            private boolean isDistinct;
0105:
0106:            private boolean orderByAndDistinctMerged;
0107:
0108:            private boolean generatedForGroupByClause;
0109:            private boolean generatedForHavingClause;
0110:
0111:            /* Copy of fromList prior to generating join tree */
0112:            private FromList preJoinFL;
0113:
0114:            /**
0115:             * Initializer for a SelectNode.
0116:             *
0117:             * @param selectList	The result column list for the SELECT statement
0118:             * @param aggregateVector	The aggregate vector for this SELECT 
0119:             * @param fromList	The FROM list for the SELECT statement
0120:             * @param whereClause	An expression representing the WHERE clause.
0121:             *			It must be a boolean expression, but this is
0122:             *			not checked until binding.
0123:             * @param groupByList	The GROUP BY list, if any.
0124:             * @exception StandardException		Thrown on error
0125:             */
0126:
0127:            public void init(Object selectList, Object aggregateVector,
0128:                    Object fromList, Object whereClause, Object groupByList)
0129:                    throws StandardException {
0130:                /* RESOLVE - remove aggregateList from constructor.
0131:                 * Consider adding selectAggregates and whereAggregates 
0132:                 */
0133:                resultColumns = (ResultColumnList) selectList;
0134:                if (resultColumns != null)
0135:                    resultColumns.markInitialSize();
0136:                this .fromList = (FromList) fromList;
0137:                this .whereClause = (ValueNode) whereClause;
0138:                this .originalWhereClause = (ValueNode) whereClause;
0139:                this .groupByList = (GroupByList) groupByList;
0140:                bindTargetListOnly = false;
0141:            }
0142:
0143:            /**
0144:             * Convert this object to a String.  See comments in QueryTreeNode.java
0145:             * for how this should be done for tree printing.
0146:             *
0147:             * @return	This object as a String
0148:             */
0149:
0150:            public String toString() {
0151:                if (SanityManager.DEBUG) {
0152:                    return "isDistinct: "
0153:                            + isDistinct
0154:                            + "\n"
0155:                            + "groupByList: "
0156:                            + (groupByList != null ? groupByList.toString()
0157:                                    : "null")
0158:                            + "\n"
0159:                            + "orderByList: "
0160:                            + (orderByList != null ? orderByList.toString()
0161:                                    : "null") + "\n"
0162:                            + "generatedForGroupByClause: "
0163:                            + generatedForGroupByClause + "\n"
0164:                            + "generatedForHavingClause: "
0165:                            + generatedForHavingClause + "\n"
0166:                            + super .toString();
0167:                } else {
0168:                    return "";
0169:                }
0170:            }
0171:
0172:            public String statementToString() {
0173:                return "SELECT";
0174:            }
0175:
0176:            public void makeDistinct() {
0177:                isDistinct = true;
0178:            }
0179:
0180:            public void clearDistinct() {
0181:                isDistinct = false;
0182:            }
0183:
0184:            boolean hasDistinct() {
0185:                return isDistinct;
0186:            }
0187:
0188:            /**
0189:             * Mark this SelectNode as being generated for a GROUP BY clause.
0190:             */
0191:            public void markAsForGroupByClause() {
0192:                generatedForGroupByClause = true;
0193:            }
0194:
0195:            /**
0196:             * Return whether or not this SelectNode was generated for a GROUP BY clause.
0197:             *
0198:             * @return boolean	Whether or not this SelectNode was generated for a GROUP BY clause.
0199:             */
0200:            public boolean getGeneratedForGroupbyClause() {
0201:                return generatedForGroupByClause;
0202:            }
0203:
0204:            /**
0205:             * Mark this SelectNode as being generated for a HAVING clause.
0206:             */
0207:            public void markAsForHavingClause() {
0208:                generatedForHavingClause = true;
0209:            }
0210:
0211:            /**
0212:             * Prints the sub-nodes of this object.  See QueryTreeNode.java for
0213:             * how tree printing is supposed to work.
0214:             *
0215:             * @param depth		The depth of this node in the tree
0216:             */
0217:
0218:            public void printSubNodes(int depth) {
0219:                if (SanityManager.DEBUG) {
0220:                    super .printSubNodes(depth);
0221:
0222:                    if (selectSubquerys != null) {
0223:                        printLabel(depth, "selectSubquerys: ");
0224:                        selectSubquerys.treePrint(depth + 1);
0225:                    }
0226:
0227:                    printLabel(depth, "fromList: ");
0228:
0229:                    if (fromList != null) {
0230:                        fromList.treePrint(depth + 1);
0231:                    }
0232:
0233:                    if (whereClause != null) {
0234:                        printLabel(depth, "whereClause: ");
0235:                        whereClause.treePrint(depth + 1);
0236:                    }
0237:
0238:                    if ((wherePredicates != null) && wherePredicates.size() > 0) {
0239:                        printLabel(depth, "wherePredicates: ");
0240:                        wherePredicates.treePrint(depth + 1);
0241:                    }
0242:
0243:                    if (whereSubquerys != null) {
0244:                        printLabel(depth, "whereSubquerys: ");
0245:                        whereSubquerys.treePrint(depth + 1);
0246:                    }
0247:
0248:                    printLabel(depth, "preJoinFL: ");
0249:
0250:                    if (preJoinFL != null) {
0251:                        preJoinFL.treePrint(depth + 1);
0252:                    }
0253:                }
0254:            }
0255:
0256:            /**
0257:             * Return the fromList for this SelectNode.
0258:             *
0259:             * @return FromList	The fromList for this SelectNode.
0260:             */
0261:            public FromList getFromList() {
0262:                return fromList;
0263:            }
0264:
0265:            /**
0266:             * Find colName in the result columns and return underlying columnReference.
0267:             * Note that this function returns null if there are more than one FromTable
0268:             * for this SelectNode and the columnReference needs to be directly under
0269:             * the resultColumn. So having an expression under the resultSet would cause
0270:             * returning null.
0271:             *
0272:             * @param	colName		Name of the column
0273:             *
0274:             * @return	ColumnReference	ColumnReference to the column, if found
0275:             */
0276:            public ColumnReference findColumnReferenceInResult(String colName)
0277:                    throws StandardException {
0278:                if (fromList.size() != 1)
0279:                    return null;
0280:
0281:                // This logic is similar to SubQueryNode.singleFromBaseTable(). Refactor
0282:                FromTable ft = (FromTable) fromList.elementAt(0);
0283:                if (!((ft instanceof  ProjectRestrictNode) && ((ProjectRestrictNode) ft)
0284:                        .getChildResult() instanceof  FromBaseTable)
0285:                        && !(ft instanceof  FromBaseTable))
0286:                    return null;
0287:
0288:                // Loop through the result columns looking for a match
0289:                int rclSize = resultColumns.size();
0290:                for (int index = 0; index < rclSize; index++) {
0291:                    ResultColumn rc = (ResultColumn) resultColumns
0292:                            .elementAt(index);
0293:                    if (!(rc.getExpression() instanceof  ColumnReference))
0294:                        return null;
0295:
0296:                    ColumnReference crNode = (ColumnReference) rc
0297:                            .getExpression();
0298:
0299:                    if (crNode.columnName.equals(colName))
0300:                        return (ColumnReference) crNode.getClone();
0301:                }
0302:
0303:                return null;
0304:            }
0305:
0306:            /**
0307:             * Return the whereClause for this SelectNode.
0308:             *
0309:             * @return ValueNode	The whereClause for this SelectNode.
0310:             */
0311:            public ValueNode getWhereClause() {
0312:                return whereClause;
0313:            }
0314:
0315:            /**
0316:             * Return the wherePredicates for this SelectNode.
0317:             *
0318:             * @return PredicateList	The wherePredicates for this SelectNode.
0319:             */
0320:            public PredicateList getWherePredicates() {
0321:                return wherePredicates;
0322:            }
0323:
0324:            /**
0325:             * Return the selectSubquerys for this SelectNode.
0326:             *
0327:             * @return SubqueryList	The selectSubquerys for this SelectNode.
0328:             */
0329:            public SubqueryList getSelectSubquerys() {
0330:                return selectSubquerys;
0331:            }
0332:
0333:            /**
0334:             * Return the specified aggregate vector for this SelectNode.
0335:             *
0336:             * @param clause	Which clause to get the aggregate list for
0337:             *
0338:             * @return aggregateVector	The specified aggregate vector for this SelectNode.
0339:             */
0340:            public Vector getAggregateVector(int clause) {
0341:                switch (clause) {
0342:                case ValueNode.IN_SELECT_LIST:
0343:                    return selectAggregates;
0344:
0345:                case ValueNode.IN_WHERE_CLAUSE:
0346:                    if (generatedForHavingClause) {
0347:                        return null;
0348:                    } else {
0349:                        return whereAggregates;
0350:                    }
0351:
0352:                case ValueNode.IN_HAVING_CLAUSE:
0353:                    if (generatedForHavingClause) {
0354:                        return whereAggregates;
0355:                    } else {
0356:                        return null;
0357:                    }
0358:
0359:                default:
0360:                    if (SanityManager.DEBUG) {
0361:                        SanityManager.ASSERT(false,
0362:                                "Unexpected value for clause");
0363:                    }
0364:                    return null;
0365:                }
0366:            }
0367:
0368:            /**
0369:             * Return the whereSubquerys for this SelectNode.
0370:             *
0371:             * @return SubqueryList	The whereSubquerys for this SelectNode.
0372:             */
0373:            public SubqueryList getWhereSubquerys() {
0374:                return whereSubquerys;
0375:            }
0376:
0377:            /**
0378:             * Bind the tables in this SelectNode.  This includes getting their
0379:             * TableDescriptors from the DataDictionary and numbering the FromTables.
0380:             * NOTE: Because this node represents the top of a new query block, we bind
0381:             * both the non VTI and VTI tables under this node in this method call.
0382:             *
0383:             * @param dataDictionary	The DataDictionary to use for binding
0384:             * @param fromListParam		FromList to use/append to.
0385:             *
0386:             * @return	ResultSetNode
0387:             *
0388:             * @exception StandardException		Thrown on error
0389:             */
0390:
0391:            public ResultSetNode bindNonVTITables(
0392:                    DataDictionary dataDictionary, FromList fromListParam)
0393:                    throws StandardException {
0394:                int fromListParamSize = fromListParam.size();
0395:                int fromListSize = fromList.size();
0396:                int nestingLevel;
0397:                FromList fromListClone = (FromList) getNodeFactory().getNode(
0398:                        C_NodeTypes.FROM_LIST,
0399:                        getNodeFactory().doJoinOrderOptimization(),
0400:                        getContextManager());
0401:
0402:                wherePredicates = (PredicateList) getNodeFactory().getNode(
0403:                        C_NodeTypes.PREDICATE_LIST, getContextManager());
0404:                preJoinFL = (FromList) getNodeFactory().getNode(
0405:                        C_NodeTypes.FROM_LIST,
0406:                        getNodeFactory().doJoinOrderOptimization(),
0407:                        getContextManager());
0408:
0409:                /* Set the nesting level in the fromList */
0410:                if (fromListParam.size() == 0) {
0411:                    nestingLevel = 0;
0412:                } else {
0413:                    nestingLevel = ((FromTable) fromListParam.elementAt(0))
0414:                            .getLevel() + 1;
0415:                }
0416:                fromList.setLevel(nestingLevel);
0417:
0418:                /* Splice a clone of our FromList on to the beginning of fromListParam, before binding
0419:                 * the tables, for correlated column resolution in VTIs.
0420:                 */
0421:                for (int index = 0; index < fromListSize; index++) {
0422:                    fromListParam.insertElementAt(fromList.elementAt(index), 0);
0423:                }
0424:
0425:                // Now bind our from list
0426:                fromList.bindTables(dataDictionary, fromListParam);
0427:
0428:                /* Restore fromListParam */
0429:                for (int index = 0; index < fromListSize; index++) {
0430:                    fromListParam.removeElementAt(0);
0431:                }
0432:                return this ;
0433:            }
0434:
0435:            /**
0436:             * Bind the expressions in this SelectNode.  This means binding the
0437:             * sub-expressions, as well as figuring out what the return type is
0438:             * for each expression.
0439:             *
0440:             * @param fromListParam		FromList to use/append to.
0441:             *
0442:             * @exception StandardException		Thrown on error
0443:             */
0444:            public void bindExpressions(FromList fromListParam)
0445:                    throws StandardException {
0446:                int fromListParamSize = fromListParam.size();
0447:                int fromListSize = fromList.size();
0448:                int numDistinctAggs;
0449:
0450:                if (SanityManager.DEBUG)
0451:                    SanityManager
0452:                            .ASSERT(fromList != null && resultColumns != null,
0453:                                    "Both fromList and resultColumns are expected to be non-null");
0454:
0455:                /* NOTE - a lot of this code would be common to bindTargetExpression(),
0456:                 * so we use a private boolean to share the code instead of duplicating
0457:                 * it.  bindTargetExpression() is responsible for toggling the boolean.
0458:                 */
0459:                if (!bindTargetListOnly) {
0460:                    /* Bind the expressions in FromSubquerys, JoinNodes, etc. */
0461:                    fromList.bindExpressions(fromListParam);
0462:                }
0463:
0464:                selectSubquerys = (SubqueryList) getNodeFactory().getNode(
0465:                        C_NodeTypes.SUBQUERY_LIST, getContextManager());
0466:                selectAggregates = new Vector();
0467:
0468:                /* Splice our FromList on to the beginning of fromListParam, before binding
0469:                 * the expressions, for correlated column resolution.
0470:                 */
0471:                for (int index = 0; index < fromListSize; index++) {
0472:                    fromListParam.insertElementAt(fromList.elementAt(index),
0473:                            index);
0474:                }
0475:
0476:                resultColumns.setClause(ValueNode.IN_SELECT_LIST);
0477:                resultColumns.bindExpressions(fromListParam, selectSubquerys,
0478:                        selectAggregates);
0479:
0480:                /* We're done if we're only binding the target list.
0481:                 * (After we restore the fromList, of course.)
0482:                 */
0483:                if (bindTargetListOnly) {
0484:                    for (int index = 0; index < fromListSize; index++) {
0485:                        fromListParam.removeElementAt(0);
0486:                    }
0487:                    return;
0488:                }
0489:
0490:                whereAggregates = new Vector();
0491:                whereSubquerys = (SubqueryList) getNodeFactory().getNode(
0492:                        C_NodeTypes.SUBQUERY_LIST, getContextManager());
0493:                if (whereClause != null) {
0494:                    getCompilerContext().pushCurrentPrivType(
0495:                            Authorizer.SELECT_PRIV);
0496:                    whereClause = whereClause.bindExpression(fromListParam,
0497:                            whereSubquerys, whereAggregates);
0498:
0499:                    /* RESOLVE - Temporarily disable aggregates in the HAVING clause.
0500:                     ** (We may remove them in the parser anyway.)
0501:                     ** RESOLVE - Disable aggregates in the WHERE clause.  Someday
0502:                     ** Aggregates will be allowed iff they are in a subquery
0503:                     ** of the having clause and they correlate to an outer
0504:                     ** query block.  For now, aggregates are not supported
0505:                     ** in the WHERE clause at all.
0506:                     ** Note: a similar check is made in JoinNode.
0507:                     */
0508:                    if ((whereAggregates.size() > 0)
0509:                            && !generatedForHavingClause) {
0510:                        throw StandardException
0511:                                .newException(SQLState.LANG_NO_AGGREGATES_IN_WHERE_CLAUSE);
0512:                    }
0513:
0514:                    /* If whereClause is a parameter, (where ?/where -?/where +?), then we should catch it and throw exception
0515:                     */
0516:                    if (whereClause.isParameterNode())
0517:                        throw StandardException.newException(
0518:                                SQLState.LANG_NON_BOOLEAN_WHERE_CLAUSE,
0519:                                "PARAMETER");
0520:                    if ((whereClause instanceof  UnaryOperatorNode)
0521:                            && ((UnaryOperatorNode) whereClause)
0522:                                    .isUnaryMinusOrPlusWithParameter())
0523:                        throw StandardException.newException(
0524:                                SQLState.LANG_NON_BOOLEAN_WHERE_CLAUSE,
0525:                                "PARAMETER");
0526:
0527:                    whereClause = whereClause.checkIsBoolean();
0528:                    getCompilerContext().popCurrentPrivType();
0529:                }
0530:
0531:                /* Restore fromList */
0532:                for (int index = 0; index < fromListSize; index++) {
0533:                    fromListParam.removeElementAt(0);
0534:                }
0535:
0536:                if (SanityManager.DEBUG) {
0537:                    SanityManager.ASSERT(
0538:                            fromListParam.size() == fromListParamSize,
0539:                            "fromListParam.size() = " + fromListParam.size()
0540:                                    + ", expected to be restored to "
0541:                                    + fromListParamSize);
0542:                    SanityManager.ASSERT(fromList.size() == fromListSize,
0543:                            "fromList.size() = " + fromList.size()
0544:                                    + ", expected to be restored to "
0545:                                    + fromListSize);
0546:                }
0547:
0548:                /* If query is grouped, bind the group by list. */
0549:                if (groupByList != null) {
0550:                    Vector gbAggregateVector = new Vector();
0551:
0552:                    groupByList.bindGroupByColumns(this , gbAggregateVector);
0553:
0554:                    /*
0555:                     ** There should be no aggregates in the Group By list.
0556:                     ** We don't expect any, but just to be on the safe side
0557:                     ** we will check under sanity.
0558:                     */
0559:                    if (SanityManager.DEBUG) {
0560:                        SanityManager
0561:                                .ASSERT(gbAggregateVector.size() == 0,
0562:                                        "Unexpected Aggregate vector generated by Group By clause");
0563:                    }
0564:                }
0565:                /* If ungrouped query with aggregates in SELECT list, verify
0566:                 * that all result columns are valid aggregate expressions -
0567:                 * no column references outside of an aggregate.
0568:                 * If grouped query with aggregates in SELECT list, verify that all
0569:                 * result columns are either grouping expressions or valid
0570:                 * grouped aggregate expressions - the only column references
0571:                 * allowed outside of an aggregate are columns in expressions in 
0572:                 * the group by list.
0573:                 */
0574:                if (groupByList != null || selectAggregates.size() > 0) {
0575:
0576:                    VerifyAggregateExpressionsVisitor visitor = new VerifyAggregateExpressionsVisitor(
0577:                            groupByList);
0578:                    resultColumns.accept(visitor);
0579:                }
0580:
0581:                /*
0582:                 ** RESOLVE: for now, only one distinct aggregate is supported
0583:                 ** in the select list.
0584:                 */
0585:                numDistinctAggs = numDistinctAggregates(selectAggregates);
0586:                if (numDistinctAggs > 1) {
0587:                    throw StandardException
0588:                            .newException(SQLState.LANG_USER_AGGREGATE_MULTIPLE_DISTINCTS);
0589:                }
0590:            }
0591:
0592:            /**
0593:             * Bind the expressions in this ResultSetNode if it has tables.  This means binding the
0594:             * sub-expressions, as well as figuring out what the return type is for
0595:             * each expression.
0596:             *
0597:             * @param fromListParam		FromList to use/append to.
0598:             *
0599:             * @exception StandardException		Thrown on error
0600:             */
0601:            public void bindExpressionsWithTables(FromList fromListParam)
0602:                    throws StandardException {
0603:                /* We have tables, so simply call bindExpressions() */
0604:                bindExpressions(fromListParam);
0605:            }
0606:
0607:            /**
0608:             * Bind the expressions in the target list.  This means binding the
0609:             * sub-expressions, as well as figuring out what the return type is
0610:             * for each expression.  This is useful for EXISTS subqueries, where we
0611:             * need to validate the target list before blowing it away and replacing
0612:             * it with a SELECT true.
0613:             *
0614:             * @exception StandardException		Thrown on error
0615:             */
0616:
0617:            public void bindTargetExpressions(FromList fromListParam)
0618:                    throws StandardException {
0619:                bindTargetListOnly = true;
0620:                bindExpressions(fromListParam);
0621:                bindTargetListOnly = false;
0622:            }
0623:
0624:            /**
0625:             * Bind the result columns of this ResultSetNode when there is no
0626:             * base table to bind them to.  This is useful for SELECT statements,
0627:             * where the result columns get their types from the expressions that
0628:             * live under them.
0629:             *
0630:             * @param fromListParam		FromList to use/append to.
0631:             *
0632:             * @exception StandardException		Thrown on error
0633:             */
0634:
0635:            public void bindResultColumns(FromList fromListParam)
0636:                    throws StandardException {
0637:                /* We first bind the resultColumns for any FromTable which
0638:                 * needs its own binding, such as JoinNodes.
0639:                 * We pass through the fromListParam without adding our fromList
0640:                 * to it, since the elements in our fromList can only be correlated
0641:                 * with outer query blocks.
0642:                 */
0643:                fromList.bindResultColumns(fromListParam);
0644:                super .bindResultColumns(fromListParam);
0645:
0646:                /* Only 1012 elements allowed in select list */
0647:                if (resultColumns.size() > Limits.DB2_MAX_ELEMENTS_IN_SELECT_LIST) {
0648:                    throw StandardException
0649:                            .newException(SQLState.LANG_TOO_MANY_ELEMENTS);
0650:                }
0651:
0652:                /* Fix nullability in case of any outer joins in the fromList */
0653:                if (fromList.hasOuterJoins())
0654:                    resultColumns.setNullability(true);
0655:            }
0656:
0657:            /**
0658:             * Bind the result columns for this ResultSetNode to a base table.
0659:             * This is useful for INSERT and UPDATE statements, where the
0660:             * result columns get their types from the table being updated or
0661:             * inserted into.
0662:             * If a result column list is specified, then the verification that the 
0663:             * result column list does not contain any duplicates will be done when
0664:             * binding them by name.
0665:             *
0666:             * @param targetTableDescriptor	The TableDescriptor for the table being
0667:             *				updated or inserted into
0668:             * @param targetColumnList	For INSERT statements, the user
0669:             *					does not have to supply column
0670:             *					names (for example, "insert into t
0671:             *					values (1,2,3)".  When this
0672:             *					parameter is null, it means that
0673:             *					the user did not supply column
0674:             *					names, and so the binding should
0675:             *					be done based on order.  When it
0676:             *					is not null, it means do the binding
0677:             *					by name, not position.
0678:             * @param statement			Calling DMLStatementNode (Insert or Update)
0679:             * @param fromListParam		FromList to use/append to.
0680:             *
0681:             * @exception StandardException		Thrown on error
0682:             */
0683:
0684:            public void bindResultColumns(
0685:                    TableDescriptor targetTableDescriptor, FromVTI targetVTI,
0686:                    ResultColumnList targetColumnList,
0687:                    DMLStatementNode statement, FromList fromListParam)
0688:                    throws StandardException {
0689:                /* We first bind the resultColumns for any FromTable which
0690:                 * needs its own binding, such as JoinNodes.
0691:                 * We pass through the fromListParam without adding our fromList
0692:                 * to it, since the elements in our fromList can only be correlated
0693:                 * with outer query blocks.
0694:                 */
0695:                fromList.bindResultColumns(fromListParam);
0696:                super .bindResultColumns(targetTableDescriptor, targetVTI,
0697:                        targetColumnList, statement, fromListParam);
0698:            }
0699:
0700:            /** 
0701:             * Push an expression into this SELECT (and possibly down into
0702:             * one of the tables in the FROM list).  This is useful when
0703:             * trying to push predicates into unflattened views or
0704:             * derived tables.
0705:             *
0706:             * @param predicate	The predicate that we attempt to push
0707:             *
0708:             * @exception StandardException		Thrown on error
0709:             */
0710:            void pushExpressionsIntoSelect(Predicate predicate)
0711:                    throws StandardException {
0712:                wherePredicates.pullExpressions(referencedTableMap.size(),
0713:                        predicate.getAndNode());
0714:                fromList.pushPredicates(wherePredicates);
0715:            }
0716:
0717:            /**
0718:             * Verify that a SELECT * is valid for this type of subquery.
0719:             *
0720:             * @param outerFromList	The FromList from the outer query block(s)
0721:             * @param subqueryType	The subquery type
0722:             *
0723:             * @exception StandardException		Thrown on error
0724:             */
0725:            public void verifySelectStarSubquery(FromList outerFromList,
0726:                    int subqueryType) throws StandardException {
0727:                if (!((ResultColumn) resultColumns.elementAt(0) instanceof  AllResultColumn)) {
0728:                    return;
0729:                }
0730:
0731:                /* Select * always okay when SelectNode generated to wrap
0732:                 * GROUP BY or HAVING.
0733:                 */
0734:                if (generatedForGroupByClause || generatedForHavingClause) {
0735:                    return;
0736:                }
0737:
0738:                /* Select * currently only valid for EXISTS/NOT EXISTS.
0739:                 * NOT EXISTS does not appear prior to preprocessing.
0740:                 */
0741:                if (subqueryType != SubqueryNode.EXISTS_SUBQUERY) {
0742:                    throw StandardException
0743:                            .newException(SQLState.LANG_CANT_SELECT_STAR_SUBQUERY);
0744:                }
0745:
0746:                /* If the AllResultColumn is qualified, then we have to verify
0747:                 * that the qualification is a valid exposed name.
0748:                 * NOTE: The exposed name can come from an outer query block.
0749:                 */
0750:                String fullTableName;
0751:
0752:                fullTableName = ((AllResultColumn) resultColumns.elementAt(0))
0753:                        .getFullTableName();
0754:
0755:                if (fullTableName != null) {
0756:                    if (fromList.getFromTableByName(fullTableName, null, true) == null
0757:                            && outerFromList.getFromTableByName(fullTableName,
0758:                                    null, true) == null) {
0759:                        if (fromList.getFromTableByName(fullTableName, null,
0760:                                false) == null
0761:                                && outerFromList.getFromTableByName(
0762:                                        fullTableName, null, false) == null) {
0763:                            throw StandardException.newException(
0764:                                    SQLState.LANG_EXPOSED_NAME_NOT_FOUND,
0765:                                    fullTableName);
0766:                        }
0767:                    }
0768:                }
0769:            }
0770:
0771:            /** 
0772:             * Determine whether or not the specified name is an exposed name in
0773:             * the current query block.
0774:             *
0775:             * @param name	The specified name to search for as an exposed name.
0776:             * @param schemaName	Schema name, if non-null.
0777:             * @param exactMatch	Whether or not we need an exact match on specified schema and table
0778:             *						names or match on table id.
0779:             *
0780:             * @return The FromTable, if any, with the exposed name.
0781:             *
0782:             * @exception StandardException		Thrown on error
0783:             */
0784:            protected FromTable getFromTableByName(String name,
0785:                    String schemaName, boolean exactMatch)
0786:                    throws StandardException {
0787:                return fromList
0788:                        .getFromTableByName(name, schemaName, exactMatch);
0789:            }
0790:
0791:            /**
0792:             * Check for (and reject) ? parameters directly under the ResultColumns.
0793:             * This is done for SELECT statements.
0794:             *
0795:             * @exception StandardException		Thrown if a ? parameter found
0796:             *									directly under a ResultColumn
0797:             */
0798:
0799:            public void rejectParameters() throws StandardException {
0800:                super .rejectParameters();
0801:                fromList.rejectParameters();
0802:            }
0803:
0804:            /**
0805:             * Push the order by list down from the cursor node
0806:             * into its child result set so that the optimizer
0807:             * has all of the information that it needs to 
0808:             * consider sort avoidance.
0809:             *
0810:             * @param orderByList	The order by list
0811:             */
0812:            void pushOrderByList(OrderByList orderByList) {
0813:                this .orderByList = orderByList;
0814:                // remember that there was an order by list
0815:                orderByQuery = true;
0816:            }
0817:
0818:            /** 
0819:             * Put a ProjectRestrictNode on top of each FromTable in the FromList.
0820:             * ColumnReferences must continue to point to the same ResultColumn, so
0821:             * that ResultColumn must percolate up to the new PRN.  However,
0822:             * that ResultColumn will point to a new expression, a VirtualColumnNode, 
0823:             * which points to the FromTable and the ResultColumn that is the source for
0824:             * the ColumnReference.  
0825:             * (The new PRN will have the original of the ResultColumnList and
0826:             * the ResultColumns from that list.  The FromTable will get shallow copies
0827:             * of the ResultColumnList and its ResultColumns.  ResultColumn.expression
0828:             * will remain at the FromTable, with the PRN getting a new 
0829:             * VirtualColumnNode for each ResultColumn.expression.)
0830:             * We then project out the non-referenced columns.  If there are no referenced
0831:             * columns, then the PRN's ResultColumnList will consist of a single ResultColumn
0832:             * whose expression is 1.
0833:             *
0834:             * @param numTables			The number of tables in the DML Statement
0835:             * @param gbl				The outer group by list, if any
0836:             * @param fl			The from list, if any
0837:             *
0838:             * @return The generated ProjectRestrictNode atop the original FromTable.
0839:             *
0840:             * @exception StandardException		Thrown on error
0841:             */
0842:
0843:            public ResultSetNode preprocess(int numTables, GroupByList gbl,
0844:                    FromList fl) throws StandardException {
0845:                ResultSetNode newTop = this ;
0846:
0847:                /* Put the expression trees in conjunctive normal form.
0848:                 * NOTE - This needs to occur before we preprocess the subqueries
0849:                 * because the subquery transformations assume that any subquery operator 
0850:                 * negation has already occurred.
0851:                 */
0852:                normExpressions();
0853:
0854:                /**
0855:                 * This method determines if (1) the query is a LOJ, and (2) if the LOJ is a candidate for
0856:                 * reordering (i.e., linearization).  The condition for LOJ linearization is:
0857:                 * 1. either LOJ or ROJ in the fromList, i.e., no INNER, NO FULL JOINs
0858:                 * 2. ON clause must be equality join between left and right operands and in CNF (i.e., AND is allowed)
0859:                 */
0860:                boolean anyChange = fromList.LOJ_reorderable(numTables);
0861:                if (anyChange) {
0862:                    FromList afromList = (FromList) getNodeFactory().getNode(
0863:                            C_NodeTypes.FROM_LIST,
0864:                            getNodeFactory().doJoinOrderOptimization(),
0865:                            getContextManager());
0866:                    bindExpressions(afromList);
0867:                }
0868:
0869:                /* Preprocess the fromList.  For each FromTable, if it is a FromSubquery
0870:                 * then we will preprocess it, replacing the FromSubquery with a
0871:                 * ProjectRestrictNode. If it is a FromBaseTable, then we will generate
0872:                 * the ProjectRestrictNode above it.
0873:                 */
0874:                fromList.preprocess(numTables, groupByList, whereClause);
0875:
0876:                /* selectSubquerys is always allocated at bind() time */
0877:                if (SanityManager.DEBUG) {
0878:                    SanityManager.ASSERT(selectSubquerys != null,
0879:                            "selectSubquerys is expected to be non-null");
0880:                }
0881:
0882:                /* Preprocess the RCL after the from list so that
0883:                 * we can flatten/optimize any subqueries in the
0884:                 * select list.
0885:                 */
0886:                resultColumns.preprocess(numTables, fromList, whereSubquerys,
0887:                        wherePredicates);
0888:
0889:                /* Preprocess the expressions.  (This is necessary for subqueries.
0890:                 * This is also where we do tranformations such as for LIKE.)
0891:                 *
0892:                 * NOTE: We do this after preprocessing the fromList so that, for
0893:                 * quantified subqueries, the join expression with the outer
0894:                 * expression will be pushable (to be pushable, the ColumnReference
0895:                 * has to point to a VirtualColumnNode, and not to a BaseColumnNode).
0896:                 */
0897:                if (whereClause != null) {
0898:                    whereClause.preprocess(numTables, fromList, whereSubquerys,
0899:                            wherePredicates);
0900:                }
0901:
0902:                /* Preprocess the group by list too. We need to compare 
0903:                 * expressions in the group by list with the select list and we 
0904:                 * can't rewrite one and not the other.
0905:                 */
0906:                if (groupByList != null) {
0907:                    groupByList.preprocess(numTables, fromList, whereSubquerys,
0908:                            wherePredicates);
0909:                }
0910:
0911:                /* Pull apart the expression trees */
0912:                if (whereClause != null) {
0913:                    wherePredicates.pullExpressions(numTables, whereClause);
0914:                    whereClause = null;
0915:                }
0916:
0917:                /* RESOLVE - Where should we worry about expression pull up for
0918:                 * expensive predicates?
0919:                 */
0920:
0921:                // Flatten any flattenable FromSubquerys or JoinNodes
0922:                fromList.flattenFromTables(resultColumns, wherePredicates,
0923:                        whereSubquerys, groupByList);
0924:
0925:                if (wherePredicates != null && wherePredicates.size() > 0
0926:                        && fromList.size() > 0) {
0927:                    // Perform various forms of transitive closure on wherePredicates
0928:                    if (fromList.size() > 1) {
0929:                        performTransitiveClosure(numTables);
0930:                    }
0931:
0932:                    if (orderByList != null) {
0933:                        // Remove constant columns from order by list.  Constant
0934:                        // columns are ones that have equality comparisons with
0935:                        // constant expressions (e.g. x = 3)
0936:                        orderByList.removeConstantColumns(wherePredicates);
0937:
0938:                        /*
0939:                         ** It's possible for the order by list to shrink to nothing
0940:                         ** as a result of removing constant columns.  If this happens,
0941:                         ** get rid of the list entirely.
0942:                         */
0943:                        if (orderByList.size() == 0) {
0944:                            orderByList = null;
0945:                        }
0946:                    }
0947:                }
0948:
0949:                /* A valid group by without any aggregates is equivalent to 
0950:                 * a distinct without the group by.  We do the transformation
0951:                 * in order to simplify the group by code.
0952:                 */
0953:                if (groupByList != null && selectAggregates.size() == 0
0954:                        && whereAggregates.size() == 0) {
0955:                    isDistinct = true;
0956:                    groupByList = null;
0957:                }
0958:
0959:                /* Consider distinct elimination based on a uniqueness condition.
0960:                 * In order to do this:
0961:                 *	o  All top level ColumnReferences in the select list are
0962:                 *	   from the same base table.  (select t1.c1, t2.c2 + t3.c3 is 
0963:                 *	   okay - t1 is the table of interest.)
0964:                 *  o  If the from list is a single table then the columns in the
0965:                 *	   select list plus the columns in the where clause that are
0966:                 *	   in = comparisons with constants or parameters must be a
0967:                 *	   superset of any unique index.
0968:                 *  o  If the from list has multiple tables then at least 1 table
0969:                 *	   meet the following - the set of columns in = comparisons
0970:                 *	   with constants or parameters is a superset of any unique
0971:                 *	   index on the table.  All of the other tables must meet
0972:                 *	   the following - the set of columns in = comparisons with
0973:                 *	   constants, parameters or join columns is a superset of
0974:                 *	   any unique index on the table.  If the table from which
0975:                 *	   the columns in the select list are coming from is in this
0976:                 *     later group then the rule for it is to also include
0977:                 *     the columns in the select list in the set of columns that
0978:                 *     needs to be a superset of the unique index.  Whew!
0979:                 */
0980:                if (isDistinct && groupByList == null) {
0981:                    int distinctTable = resultColumns.allTopCRsFromSameTable();
0982:
0983:                    if (distinctTable != -1) {
0984:                        if (fromList.returnsAtMostSingleRow(resultColumns,
0985:                                whereClause, wherePredicates,
0986:                                getDataDictionary())) {
0987:                            isDistinct = false;
0988:                        }
0989:                    }
0990:
0991:                    /* If we were unable to eliminate the distinct and we have
0992:                     * an order by then we can consider eliminating the sort for the
0993:                     * order by.  All of the columns in the order by list must
0994:                     * be ascending in order to do this.  There are 2 cases:
0995:                     *	o	The order by list is an in order prefix of the columns
0996:                     *		in the select list.  In this case the output of the
0997:                     *		sort from the distinct will be in the right order
0998:                     *		so we simply eliminate the order by list.
0999:                     *	o	The order by list is a subset of the columns in the
1000:                     *		the select list.  In this case we need to reorder the
1001:                     *		columns in the select list so that the ordering columns
1002:                     *		are an in order prefix of the select list and put a PRN
1003:                     *		above the select so that the shape of the result set
1004:                     *		is as expected.
1005:                     */
1006:                    if (isDistinct && orderByList != null
1007:                            && orderByList.allAscending()) {
1008:                        /* Order by list currently restricted to columns in select
1009:                         * list, so we will always eliminate the order by here.
1010:                         */
1011:                        if (orderByList.isInOrderPrefix(resultColumns)) {
1012:                            orderByList = null;
1013:                        } else {
1014:                            /* Order by list is not an in order prefix of the select list
1015:                             * so we must reorder the columns in the the select list to
1016:                             * match the order by list and generate the PRN above us to
1017:                             * preserve the expected order.
1018:                             */
1019:                            newTop = genProjectRestrictForReordering();
1020:                            orderByList.resetToSourceRCs();
1021:                            resultColumns = orderByList
1022:                                    .reorderRCL(resultColumns);
1023:                            orderByList = null;
1024:                        }
1025:                        orderByAndDistinctMerged = true;
1026:                    }
1027:                }
1028:
1029:                /*
1030:                 * Push predicates that are pushable.
1031:                 *
1032:                 * NOTE: We pass the wherePredicates down to the new PRNs here,
1033:                 * so they can pull any clauses and possibily push them down further.
1034:                 * NOTE: We wait until all of the FromTables have been preprocessed
1035:                 * until we attempt to push down predicates, because we cannot push down
1036:                 * a predicate if the immediate source of any of its column references
1037:                 * is not a ColumnReference or a VirtualColumnNode.
1038:                 */
1039:                fromList.pushPredicates(wherePredicates);
1040:
1041:                /* Set up the referenced table map */
1042:                referencedTableMap = new JBitSet(numTables);
1043:                int flSize = fromList.size();
1044:                for (int index = 0; index < flSize; index++) {
1045:                    referencedTableMap.or(((FromTable) fromList
1046:                            .elementAt(index)).getReferencedTableMap());
1047:                }
1048:
1049:                /* Copy the referenced table map to the new tree top, if necessary */
1050:                if (newTop != this ) {
1051:                    newTop.setReferencedTableMap((JBitSet) referencedTableMap
1052:                            .clone());
1053:                }
1054:                return newTop;
1055:            }
1056:
1057:            /**
1058:             * Peform the various types of transitive closure on the where clause.
1059:             * The 2 types are transitive closure on join clauses and on search clauses.
1060:             * Join clauses will be processed first to maximize benefit for search clauses.
1061:             *
1062:             * @param numTables		The number of tables in the query
1063:             *
1064:             * @exception StandardException		Thrown on error
1065:             */
1066:            private void performTransitiveClosure(int numTables)
1067:                    throws StandardException {
1068:                // Join clauses
1069:                wherePredicates.joinClauseTransitiveClosure(numTables,
1070:                        fromList, getCompilerContext());
1071:
1072:                // Search clauses
1073:                wherePredicates.searchClauseTransitiveClosure(numTables,
1074:                        fromList.hashJoinSpecified());
1075:            }
1076:
1077:            /** Put the expression trees in conjunctive normal form 
1078:             *
1079:             * @exception StandardException		Thrown on error
1080:             */
1081:            private void normExpressions() throws StandardException {
1082:                /* For each expression tree:
1083:                 *	o Eliminate NOTs (eliminateNots())
1084:                 *	o Ensure that there is an AndNode on top of every
1085:                 *	  top level expression. (putAndsOnTop())
1086:                 *	o Finish the job (changeToCNF())
1087:                 */
1088:                if (whereClause != null) {
1089:                    whereClause = whereClause.eliminateNots(false);
1090:                    if (SanityManager.DEBUG) {
1091:                        if (!(whereClause.verifyEliminateNots())) {
1092:                            whereClause.treePrint();
1093:                            SanityManager
1094:                                    .THROWASSERT("whereClause in invalid form: "
1095:                                            + whereClause);
1096:                        }
1097:                    }
1098:                    whereClause = whereClause.putAndsOnTop();
1099:                    if (SanityManager.DEBUG) {
1100:                        if (!((whereClause instanceof  AndNode) && (whereClause
1101:                                .verifyPutAndsOnTop()))) {
1102:                            whereClause.treePrint();
1103:                            SanityManager
1104:                                    .THROWASSERT("whereClause in invalid form: "
1105:                                            + whereClause);
1106:                        }
1107:                    }
1108:                    whereClause = whereClause.changeToCNF(true);
1109:                    if (SanityManager.DEBUG) {
1110:                        if (!((whereClause instanceof  AndNode) && (whereClause
1111:                                .verifyChangeToCNF()))) {
1112:                            whereClause.treePrint();
1113:                            SanityManager
1114:                                    .THROWASSERT("whereClause in invalid form: "
1115:                                            + whereClause);
1116:                        }
1117:                    }
1118:                }
1119:            }
1120:
1121:            /**
1122:             * Add a new predicate to the list.  This is useful when doing subquery
1123:             * transformations, when we build a new predicate with the left side of
1124:             * the subquery operator and the subquery's result column.
1125:             *
1126:             * @param predicate		The predicate to add
1127:             *
1128:             * @return ResultSetNode	The new top of the tree.
1129:             *
1130:             * @exception StandardException		Thrown on error
1131:             */
1132:            public ResultSetNode addNewPredicate(Predicate predicate)
1133:                    throws StandardException {
1134:                wherePredicates.addPredicate(predicate);
1135:                return this ;
1136:            }
1137:
1138:            /**
1139:             * Evaluate whether or not the subquery in a FromSubquery is flattenable.  
1140:             * Currently, a FSqry is flattenable if all of the following are true:
1141:             *		o  Subquery is a SelectNode. (ie, not a RowResultSetNode or a UnionNode)
1142:             *		o  It contains a single table in its FROM list.
1143:             *		o  It contains no subqueries in the SELECT list.
1144:             *		o  It does not contain a group by or having clause
1145:             *		o  It does not contain aggregates.
1146:             *		o  It is not a DISTINCT.
1147:             *
1148:             * @param fromList	The outer from list
1149:             *
1150:             * @return boolean	Whether or not the FromSubquery is flattenable.
1151:             */
1152:            public boolean flattenableInFromSubquery(FromList fromList) {
1153:                if (isDistinct) {
1154:                    return false;
1155:                }
1156:                if (this .fromList.size() > 1) {
1157:                    return false;
1158:                }
1159:
1160:                /* Don't flatten (at least for now) if selectNode's SELECT list contains a subquery */
1161:                if ((selectSubquerys != null) && (selectSubquerys.size() > 0)) {
1162:                    return false;
1163:                }
1164:
1165:                /* Don't flatten if selectNode contains a group by or having clause */
1166:                if ((groupByList != null) || generatedForHavingClause) {
1167:                    return false;
1168:                }
1169:
1170:                /* Don't flatten if select list contains something that isn't cloneable.
1171:                 */
1172:                if (!resultColumns.isCloneable()) {
1173:                    return false;
1174:                }
1175:
1176:                /* Don't flatten if selectNode contains an aggregate */
1177:                if ((selectAggregates != null) && (selectAggregates.size() > 0)) {
1178:                    return false;
1179:                }
1180:
1181:                return true;
1182:            }
1183:
1184:            /**
1185:             * Replace this SelectNode with a ProjectRestrictNode,
1186:             * since it has served its purpose.
1187:             *
1188:             * @param origFromListSize	The size of the original FROM list, before
1189:             *							generation of join tree.
1190:             * @return ResultSetNode	new ResultSetNode atop the query tree.
1191:             *
1192:             * @exception StandardException		Thrown on error
1193:             */
1194:
1195:            public ResultSetNode genProjectRestrict(int origFromListSize)
1196:                    throws StandardException {
1197:                boolean orderingDependent = false;
1198:                PredicateList restrictionList;
1199:                ResultColumnList prRCList;
1200:                ResultSetNode prnRSN;
1201:
1202:                prnRSN = (ResultSetNode) getNodeFactory().getNode(
1203:                        C_NodeTypes.PROJECT_RESTRICT_NODE,
1204:                        fromList.elementAt(0), /* Child ResultSet */
1205:                        resultColumns, /* Projection */
1206:                        whereClause, /* Restriction */
1207:                        wherePredicates,/* Restriction as PredicateList */
1208:                        selectSubquerys,/* Subquerys in Projection */
1209:                        whereSubquerys, /* Subquerys in Restriction */
1210:                        null, getContextManager());
1211:
1212:                /*
1213:                 ** If we have aggregates OR a select list we want
1214:                 ** to generate a GroupByNode.  In the case of a
1215:                 ** scalar aggregate we have no grouping columns.
1216:                 **
1217:                 ** JRESOLVE: what about correlated aggregates from another
1218:                 ** block.
1219:                 */
1220:                if (((selectAggregates != null) && (selectAggregates.size() > 0))
1221:                        || (groupByList != null)) {
1222:                    GroupByNode gbn = (GroupByNode) getNodeFactory().getNode(
1223:                            C_NodeTypes.GROUP_BY_NODE, prnRSN, groupByList,
1224:                            selectAggregates, null, getContextManager());
1225:                    gbn
1226:                            .considerPostOptimizeOptimizations(originalWhereClause != null);
1227:                    gbn.assignCostEstimate(optimizer.getOptimizedCost());
1228:
1229:                    groupByList = null;
1230:                    prnRSN = gbn.getParent();
1231:
1232:                    // Remember if the result is dependent on the ordering
1233:                    orderingDependent = orderingDependent
1234:                            || gbn.getIsInSortedOrder();
1235:                }
1236:
1237:                // if it is distinct, that must also be taken care of.
1238:                if (isDistinct) {
1239:                    // We first verify that a distinct is valid on the
1240:                    // RCL.
1241:                    resultColumns.verifyAllOrderable();
1242:
1243:                    /* See if we can push duplicate elimination into the store
1244:                     * via a hash scan.  This is possible iff:
1245:                     *	o  A single table query
1246:                     *	o  We haven't merged the order by and distinct sorts.
1247:                     *	   (Results do not have to be in a particular order.)
1248:                     *	o  All entries in the select's RCL are ColumnReferences.
1249:                     *	o  No predicates (This is because we currently do not
1250:                     *	   differentiate between columns referenced in the select
1251:                     *	   list and columns referenced in other clauses.  In other
1252:                     *	   words, the store will do duplicate elimination based on
1253:                     *	   all referenced columns.)
1254:                     *	   RESOLVE - We can change this to be all referenced columns
1255:                     *	   have to be in the select list.  In that case, we need to
1256:                     *	   refine which predicates are allowed.  Basically, all predicates
1257:                     *	   must have been pushed down to the index/table scan.(If we make
1258:                     *	   this change, then we need to verify that non of the columns in
1259:                     *	   the predicates are correlated columns.)
1260:                     *	o  NOTE: The implementation of isPossibleDistinctScan() will return
1261:                     *	   false if there is an IndexRowToBaseRow above the 
1262:                     *	   FromBaseTable.  This is because all of a table's columns must come
1263:                     *	   from the same conglomerate in order to get consistent data.
1264:                     */
1265:                    boolean distinctScanPossible = false;
1266:                    if (origFromListSize == 1
1267:                            && (!orderByAndDistinctMerged)
1268:                            && resultColumns
1269:                                    .countNumberOfSimpleColumnReferences() == resultColumns
1270:                                    .size()) {
1271:                        boolean simpleColumns = true;
1272:                        HashSet distinctColumns = new HashSet();
1273:                        int size = resultColumns.size();
1274:                        for (int i = 1; i <= size; i++) {
1275:                            BaseColumnNode bc = resultColumns
1276:                                    .getResultColumn(i).getBaseColumnNode();
1277:                            if (bc == null) {
1278:                                simpleColumns = false;
1279:                                break;
1280:                            }
1281:                            distinctColumns.add(bc);
1282:                        }
1283:                        if (simpleColumns
1284:                                && prnRSN
1285:                                        .isPossibleDistinctScan(distinctColumns)) {
1286:                            prnRSN.markForDistinctScan();
1287:                            distinctScanPossible = true;
1288:                        }
1289:                    }
1290:
1291:                    if (!distinctScanPossible) {
1292:                        /* We can't do a distinct scan. Determine if we can filter out 
1293:                         * duplicates without a sorter. 
1294:                         */
1295:                        boolean inSortedOrder = isOrderedResult(resultColumns,
1296:                                prnRSN, !(orderByAndDistinctMerged));
1297:                        prnRSN = (ResultSetNode) getNodeFactory().getNode(
1298:                                C_NodeTypes.DISTINCT_NODE, prnRSN,
1299:                                new Boolean(inSortedOrder), null,
1300:                                getContextManager());
1301:                        prnRSN.costEstimate = costEstimate.cloneMe();
1302:
1303:                        // Remember if the result is dependent on the ordering
1304:                        orderingDependent = orderingDependent || inSortedOrder;
1305:                    }
1306:                }
1307:
1308:                /* Generate the OrderByNode if a sort is still required for
1309:                 * the order by.
1310:                 */
1311:                if (orderByList != null) {
1312:                    if (orderByList.getSortNeeded()) {
1313:                        prnRSN = (ResultSetNode) getNodeFactory().getNode(
1314:                                C_NodeTypes.ORDER_BY_NODE, prnRSN, orderByList,
1315:                                null, getContextManager());
1316:                        prnRSN.costEstimate = costEstimate.cloneMe();
1317:                    }
1318:
1319:                    int orderBySelect = this .getResultColumns()
1320:                            .getOrderBySelect();
1321:                    if (orderBySelect > 0) {
1322:                        ResultColumnList selectRCs = prnRSN.getResultColumns()
1323:                                .copyListAndObjects();
1324:                        int wholeSize = selectRCs.size();
1325:                        for (int i = wholeSize - 1; orderBySelect > 0; i--, orderBySelect--)
1326:                            selectRCs.removeElementAt(i);
1327:                        selectRCs.genVirtualColumnNodes(prnRSN, prnRSN
1328:                                .getResultColumns());
1329:                        prnRSN = (ResultSetNode) getNodeFactory().getNode(
1330:                                C_NodeTypes.PROJECT_RESTRICT_NODE, prnRSN,
1331:                                selectRCs, null, null, null, null, null,
1332:                                getContextManager());
1333:                    }
1334:                }
1335:
1336:                if (!(orderByList != null && orderByList.getSortNeeded())
1337:                        && orderByQuery) {
1338:                    // Remember if the result is dependent on the ordering
1339:                    orderingDependent = true;
1340:                }
1341:
1342:                /* If the result is ordering dependent, then we must
1343:                 * tell the underlying tree.  At minimum, this means no
1344:                 * group fetch on an index under an IndexRowToBaseRow
1345:                 * since that could lead to incorrect results.  (Bug 2347.)
1346:                 */
1347:                if (orderingDependent) {
1348:                    prnRSN.markOrderingDependent();
1349:                }
1350:
1351:                /* Set the cost of this node in the generated node */
1352:                prnRSN.costEstimate = costEstimate.cloneMe();
1353:
1354:                return prnRSN;
1355:            }
1356:
1357:            /**
1358:             * Is the result of this node an ordered result set.  An ordered result set
1359:             * means that the results from this node will come in a known sorted order.
1360:             * This means that the data is ordered according to the order of the elements in the RCL.
1361:             * Today, the data is considered ordered if:
1362:             *		o The RCL is composed entirely of CRs or ConstantNodes
1363:             *		o The underlying tree is ordered on the CRs in the order in which
1364:             *			they appear in the RCL, taking equality predicates into account.
1365:             * Future Enhancements:
1366:             *		o The prefix will not be required to be in order.  (We will need to 
1367:             *		  reorder the RCL and generate a PRN with an RCL in the expected order.)
1368:             *
1369:             * @return boolean	Whether or not this node returns an ordered result set.
1370:             *
1371:             * @exception StandardException		Thrown on error
1372:             */
1373:            private boolean isOrderedResult(ResultColumnList resultColumns,
1374:                    ResultSetNode newTopRSN, boolean permuteOrdering)
1375:                    throws StandardException {
1376:                int rclSize = resultColumns.size();
1377:
1378:                /* Not ordered if RCL contains anything other than a ColumnReference
1379:                 * or a ConstantNode.
1380:                 */
1381:                int numCRs = 0;
1382:                for (int index = 0; index < rclSize; index++) {
1383:                    ResultColumn rc = (ResultColumn) resultColumns
1384:                            .elementAt(index);
1385:                    if (rc.getExpression() instanceof  ColumnReference) {
1386:                        numCRs++;
1387:                    } else if (!(rc.getExpression() instanceof  ConstantNode)) {
1388:                        return false;
1389:                    }
1390:                }
1391:
1392:                // Corner case, all constants
1393:                if (numCRs == 0) {
1394:                    return true;
1395:                }
1396:
1397:                ColumnReference[] crs = new ColumnReference[numCRs];
1398:
1399:                // Now populate the CR array and see if ordered
1400:                int crsIndex = 0;
1401:                for (int index = 0; index < rclSize; index++) {
1402:                    ResultColumn rc = (ResultColumn) resultColumns
1403:                            .elementAt(index);
1404:                    if (rc.getExpression() instanceof  ColumnReference) {
1405:                        crs[crsIndex++] = (ColumnReference) rc.getExpression();
1406:                    }
1407:                }
1408:
1409:                return newTopRSN.isOrderedOn(crs, permuteOrdering,
1410:                        (Vector) null);
1411:            }
1412:
1413:            /**
1414:             * Ensure that the top of the RSN tree has a PredicateList.
1415:             *
1416:             * @param numTables			The number of tables in the query.
1417:             * @return ResultSetNode	A RSN tree with a node which has a PredicateList on top.
1418:             *
1419:             * @exception StandardException		Thrown on error
1420:             */
1421:            public ResultSetNode ensurePredicateList(int numTables)
1422:                    throws StandardException {
1423:                return this ;
1424:            }
1425:
1426:            /**
1427:             * Optimize this SelectNode.  This means choosing the best access path
1428:             * for each table, among other things.
1429:             *
1430:             * @param dataDictionary	The DataDictionary to use for optimization
1431:             * @param predicateList		The predicate list to optimize against
1432:             * @param outerRows			The number of outer joining rows
1433:             *
1434:             * @return	ResultSetNode	The top of the optimized tree
1435:             *
1436:             * @exception StandardException		Thrown on error
1437:             */
1438:
1439:            public ResultSetNode optimize(DataDictionary dataDictionary,
1440:                    PredicateList predicateList, double outerRows)
1441:                    throws StandardException {
1442:                Optimizer optimizer;
1443:
1444:                /* Optimize any subquerys before optimizing the underlying result set */
1445:
1446:                /* selectSubquerys is always allocated at bind() time */
1447:                if (SanityManager.DEBUG)
1448:                    SanityManager.ASSERT(selectSubquerys != null,
1449:                            "selectSubquerys is expected to be non-null");
1450:
1451:                /* If this select node is the child of an outer node that is
1452:                 * being optimized, we can get here multiple times (once for
1453:                 * every permutation that is done for the outer node).  With
1454:                 * DERBY-805, we can add optimizable predicates to the WHERE
1455:                 * list as part of this method; thus, before proceeding we
1456:                 * need go through and remove any opt predicates that we added
1457:                 * to our WHERE list the last time we were here; if we don't
1458:                 * do that, we'll end up with the same predicates in our
1459:                 * WHERE list multiple times, which can lead to incorrect
1460:                 * optimization.
1461:                 */
1462:
1463:                if (wherePredicates != null) {
1464:                    // Iterate backwards because we might be deleting entries.
1465:                    for (int i = wherePredicates.size() - 1; i >= 0; i--) {
1466:                        if (((Predicate) wherePredicates.elementAt(i))
1467:                                .isScopedForPush())
1468:                            wherePredicates.removeOptPredicate(i);
1469:                    }
1470:                }
1471:
1472:                /* Get a new optimizer */
1473:
1474:                /* With DERBY-805 we take any optimizable predicates that
1475:                 * were pushed into this node and we add them to the list of
1476:                 * predicates that we pass to the optimizer, thus allowing
1477:                 * the optimizer to use them when choosing an access path
1478:                 * for this SELECT node.  We do that by adding the predicates
1479:                 * to our WHERE list, since the WHERE predicate list is what
1480:                 * we pass to the optimizer for this select node (see below).
1481:                 * We have to pass the WHERE list directly (as opposed to
1482:                 * passing a copy) because the optimizer is only created one
1483:                 * time; it then uses the list we pass it for the rest of the
1484:                 * optimization phase and finally for "modifyAccessPaths()".
1485:                 * Since the optimizer can update/modify the list based on the
1486:                 * WHERE predicates (such as by adding internal predicates or
1487:                 * by modifying the actual predicates themselves), we need
1488:                 * those changes to be applied to the WHERE list directly for
1489:                 * subsequent processing (esp. for modification of the access
1490:                 * path).  Note that by adding outer opt predicates directly
1491:                 * to the WHERE list, we're changing the semantics of this
1492:                 * SELECT node.  This is only temporary, though--once the
1493:                 * optimizer is done with all of its work, any predicates
1494:                 * that were pushed here will have been pushed even further
1495:                 * down and thus will have been removed from the WHERE list
1496:                 * (if it's not possible to push them further down, then they
1497:                 * shouldn't have made it this far to begin with).
1498:                 */
1499:                if (predicateList != null) {
1500:                    if (wherePredicates == null) {
1501:                        wherePredicates = (PredicateList) getNodeFactory()
1502:                                .getNode(C_NodeTypes.PREDICATE_LIST,
1503:                                        getContextManager());
1504:                    }
1505:
1506:                    Predicate pred = null;
1507:                    int sz = predicateList.size();
1508:                    for (int i = sz - 1; i >= 0; i--) {
1509:                        // We can tell if a predicate was pushed into this select
1510:                        // node because it will have been "scoped" for this node
1511:                        // or for some result set below this one.
1512:                        pred = (Predicate) predicateList.getOptPredicate(i);
1513:                        if (pred.isScopedToSourceResultSet()) {
1514:                            // If we're pushing the predicate down here, we have to
1515:                            // remove it from the predicate list of the node above
1516:                            // this select, in order to keep in line with established
1517:                            // push 'protocol'.
1518:                            wherePredicates.addOptPredicate(pred);
1519:                            predicateList.removeOptPredicate(pred);
1520:                        }
1521:                    }
1522:                }
1523:
1524:                optimizer = getOptimizer(fromList, wherePredicates,
1525:                        dataDictionary, orderByList);
1526:                optimizer.setOuterRows(outerRows);
1527:
1528:                /* Optimize this SelectNode */
1529:                while (optimizer.getNextPermutation()) {
1530:                    while (optimizer.getNextDecoratedPermutation()) {
1531:                        optimizer.costPermutation();
1532:                    }
1533:                }
1534:
1535:                /* When we're done optimizing, any scoped predicates that
1536:                 * we pushed down the tree should now be sitting again
1537:                 * in our wherePredicates list.  Put those back in the
1538:                 * the list from which we received them, to allow them
1539:                 * to be "pulled" back up to where they came from.
1540:                 */
1541:                if (wherePredicates != null) {
1542:                    Predicate pred = null;
1543:                    for (int i = wherePredicates.size() - 1; i >= 0; i--) {
1544:                        pred = (Predicate) wherePredicates.getOptPredicate(i);
1545:                        if (pred.isScopedForPush()) {
1546:                            predicateList.addOptPredicate(pred);
1547:                            wherePredicates.removeOptPredicate(pred);
1548:                        }
1549:                    }
1550:                }
1551:
1552:                /* Get the cost */
1553:                costEstimate = optimizer.getOptimizedCost();
1554:
1555:                /* Update row counts if this is a scalar aggregate */
1556:                if ((selectAggregates != null) && (selectAggregates.size() > 0)) {
1557:                    costEstimate.setEstimatedRowCount((long) outerRows);
1558:                    costEstimate.setSingleScanRowCount(1);
1559:                }
1560:
1561:                selectSubquerys.optimize(dataDictionary, costEstimate
1562:                        .rowCount());
1563:
1564:                if (whereSubquerys != null && whereSubquerys.size() > 0) {
1565:                    whereSubquerys.optimize(dataDictionary, costEstimate
1566:                            .rowCount());
1567:                }
1568:
1569:                return this ;
1570:            }
1571:
1572:            /**
1573:             * Modify the access paths according to the decisions the optimizer
1574:             * made.  This can include adding project/restrict nodes,
1575:             * index-to-base-row nodes, etc.
1576:             *
1577:             * @param predList A list of optimizable predicates that should
1578:             *  be pushed to this ResultSetNode, as determined by optimizer.
1579:             * @return The modified query tree
1580:             * @exception StandardException        Thrown on error
1581:             */
1582:            public ResultSetNode modifyAccessPaths(PredicateList predList)
1583:                    throws StandardException {
1584:                // Take the received list of predicates and propagate them to the
1585:                // predicate list for this node's optimizer.  Then, when we call
1586:                // optimizer.modifyAccessPaths(), the optimizer will have the
1587:                // predicates and can push them down as necessary, according
1588:                // the join order that it has chosen.
1589:
1590:                if (SanityManager.DEBUG) {
1591:                    SanityManager.ASSERT(optimizer != null,
1592:                            "SelectNode's optimizer not expected to be null when "
1593:                                    + "modifying access paths.");
1594:                }
1595:
1596:                ((OptimizerImpl) optimizer).addScopedPredicatesToList(predList);
1597:                return modifyAccessPaths();
1598:            }
1599:
1600:            /**
1601:             * Modify the access paths according to the choices the optimizer made.
1602:             *
1603:             * @return	A QueryTree with the necessary modifications made
1604:             *
1605:             * @exception StandardException		Thrown on error
1606:             */
1607:            public ResultSetNode modifyAccessPaths() throws StandardException {
1608:                int origFromListSize = fromList.size();
1609:                ResultColumnList leftRCList;
1610:                ResultColumnList rightRCList;
1611:                ResultSetNode leftResultSet;
1612:                ResultSetNode rightResultSet;
1613:
1614:                /*
1615:                 ** Modify the access path for each Optimizable, as necessary
1616:                 **
1617:                 ** This should be the same optimizer we got above.
1618:                 */
1619:                optimizer.modifyAccessPaths();
1620:
1621:                // Load the costEstimate for the final "best" join order.
1622:                costEstimate = optimizer.getFinalCost();
1623:
1624:                if (SanityManager.DEBUG) {
1625:                    // When we optimized this select node, we may have added pushable
1626:                    // outer predicates to the wherePredicates list for this node
1627:                    // (see the optimize() method above).  When we did so, we said
1628:                    // that all such predicates should have been removed from the
1629:                    // where list by the time optimization was completed.   So we
1630:                    // check that here, just to be safe.  NOTE: We do this _after_
1631:                    // calling optimizer.modifyAccessPaths(), because it's only in
1632:                    // that call that the scoped predicates are officially pushed
1633:                    // and thus removed from the list.
1634:                    if (wherePredicates != null) {
1635:                        Predicate pred = null;
1636:                        for (int i = wherePredicates.size() - 1; i >= 0; i--) {
1637:                            pred = (Predicate) wherePredicates
1638:                                    .getOptPredicate(i);
1639:                            if (pred.isScopedForPush()) {
1640:                                SanityManager
1641:                                        .THROWASSERT("Found scoped predicate "
1642:                                                + pred
1643:                                                        .binaryRelOpColRefsToString()
1644:                                                + " in WHERE list when no scoped predicates were"
1645:                                                + " expected.");
1646:                            }
1647:                        }
1648:                    }
1649:                }
1650:
1651:                selectSubquerys.modifyAccessPaths();
1652:
1653:                if (whereSubquerys != null && whereSubquerys.size() > 0) {
1654:                    whereSubquerys.modifyAccessPaths();
1655:                }
1656:
1657:                /* Build a temp copy of the current FromList for sort elimination, etc. */
1658:                preJoinFL.removeAllElements();
1659:                preJoinFL.nondestructiveAppend(fromList);
1660:
1661:                /* Now we build a JoinNode tree from the bottom up until there is only
1662:                 * a single entry in the fromList and that entry points to the top of
1663:                 * the JoinNode tree.
1664:                 *
1665:                 * While there is still more than 1 entry in the list, create a JoinNode
1666:                 * which points to the 1st 2 entries in the list.  This JoinNode becomes 
1667:                 * the new 1st entry in the list and the 2nd entry is deleted.  The
1668:                 * old 1st and 2nd entries will get shallow copies of their 
1669:                 * ResultColumnLists.  The JoinNode's ResultColumnList will be the
1670:                 * concatenation of the originals from the old 1st and 2nd entries.
1671:                 * The virtualColumnIds will be updated to reflect there new positions
1672:                 * and each ResultColumn.expression will be replaced with a new
1673:                 * VirtualColumnNode.
1674:                 */
1675:                while (fromList.size() > 1) {
1676:                    /* Get left's ResultColumnList, assign shallow copy back to it
1677:                     * and create new VirtualColumnNodes for the original's 
1678:                     * ResultColumn.expressions.
1679:                     */
1680:                    leftResultSet = (ResultSetNode) fromList.elementAt(0);
1681:                    leftRCList = leftResultSet.getResultColumns();
1682:                    leftResultSet.setResultColumns(leftRCList
1683:                            .copyListAndObjects());
1684:                    leftRCList.genVirtualColumnNodes(leftResultSet,
1685:                            leftResultSet.resultColumns);
1686:
1687:                    /* Get right's ResultColumnList, assign shallow copy back to it,
1688:                     * create new VirtualColumnNodes for the original's 
1689:                     * ResultColumn.expressions and increment the virtualColumnIds.
1690:                     * (Right gets appended to left, so only right's ids need updating.)
1691:                     */
1692:                    rightResultSet = (ResultSetNode) fromList.elementAt(1);
1693:                    rightRCList = rightResultSet.getResultColumns();
1694:                    rightResultSet.setResultColumns(rightRCList
1695:                            .copyListAndObjects());
1696:                    rightRCList.genVirtualColumnNodes(rightResultSet,
1697:                            rightResultSet.resultColumns);
1698:                    rightRCList.adjustVirtualColumnIds(leftRCList.size());
1699:
1700:                    /* Concatenate the 2 ResultColumnLists */
1701:                    leftRCList.nondestructiveAppend(rightRCList);
1702:
1703:                    /* Now we're finally ready to generate the JoinNode and have it
1704:                     * replace the 1st 2 entries in the FromList.
1705:                     */
1706:                    fromList.setElementAt((JoinNode) getNodeFactory().getNode(
1707:                            C_NodeTypes.JOIN_NODE, leftResultSet,
1708:                            rightResultSet, null, null, leftRCList, null,
1709:                            //user supplied optimizer overrides
1710:                            fromList.properties, getContextManager()), 0);
1711:
1712:                    fromList.removeElementAt(1);
1713:                }
1714:
1715:                return genProjectRestrict(origFromListSize);
1716:            }
1717:
1718:            /**
1719:             * Get the final CostEstimate for this SelectNode.
1720:             *
1721:             * @return	The final CostEstimate for this SelectNode, which is
1722:             * 			the final cost estimate for the best join order of
1723:             *          this SelectNode's optimizer.
1724:             */
1725:            public CostEstimate getFinalCostEstimate() throws StandardException {
1726:                return optimizer.getFinalCost();
1727:            }
1728:
1729:            /**
1730:            	Determine if this select is updatable or not, for a cursor.
1731:             */
1732:            boolean isUpdatableCursor(DataDictionary dd)
1733:                    throws StandardException {
1734:                TableDescriptor targetTableDescriptor;
1735:
1736:                if (isDistinct) {
1737:                    if (SanityManager.DEBUG)
1738:                        SanityManager.DEBUG("DumpUpdateCheck",
1739:                                "cursor select has distinct");
1740:                    return false;
1741:                }
1742:
1743:                if ((selectAggregates == null) || (selectAggregates.size() > 0)) {
1744:                    return false;
1745:                }
1746:
1747:                if (groupByList != null || generatedForHavingClause) {
1748:                    return false;
1749:                }
1750:
1751:                if (SanityManager.DEBUG)
1752:                    SanityManager.ASSERT(fromList != null,
1753:                            "select must have from tables");
1754:                if (fromList.size() != 1) {
1755:                    if (SanityManager.DEBUG)
1756:                        SanityManager.DEBUG("DumpUpdateCheck",
1757:                                "cursor select has more than one from table");
1758:                    return false;
1759:                }
1760:
1761:                targetTable = (FromTable) (fromList.elementAt(0));
1762:
1763:                if (targetTable instanceof  FromVTI) {
1764:
1765:                    return ((FromVTI) targetTable).isUpdatableCursor();
1766:                }
1767:
1768:                if (!(targetTable instanceof  FromBaseTable)) {
1769:                    if (SanityManager.DEBUG)
1770:                        SanityManager
1771:                                .DEBUG("DumpUpdateCheck",
1772:                                        "cursor select has non base table as target table");
1773:                    return false;
1774:                }
1775:
1776:                /* Get the TableDescriptor and verify that it is not for a
1777:                 * view or a system table.  
1778:                 * NOTE: We need to use the base table name for the table.
1779:                 *		 Simplest way to get it is from a FromBaseTable.  We
1780:                 *		 know that targetTable is a FromBaseTable because of check
1781:                 *		 just above us.
1782:                 * NOTE: We also need to use the base table's schema name; otherwise
1783:                 *		we will think it is the default schema Beetle 4417
1784:                 */
1785:                targetTableDescriptor = getTableDescriptor(
1786:                        ((FromBaseTable) targetTable).getBaseTableName(),
1787:                        getSchemaDescriptor(((FromBaseTable) targetTable)
1788:                                .getTableNameField().getSchemaName()));
1789:                if (targetTableDescriptor.getTableType() == TableDescriptor.SYSTEM_TABLE_TYPE) {
1790:                    if (SanityManager.DEBUG)
1791:                        SanityManager.DEBUG("DumpUpdateCheck",
1792:                                "cursor select is on system table");
1793:                    return false;
1794:                }
1795:                if (targetTableDescriptor.getTableType() == TableDescriptor.VIEW_TYPE) {
1796:                    if (SanityManager.DEBUG)
1797:                        SanityManager.DEBUG("DumpUpdateCheck",
1798:                                "cursor select is on view");
1799:                    return false;
1800:                }
1801:                if ((getSelectSubquerys() != null)
1802:                        && (getSelectSubquerys().size() != 0)) {
1803:                    if (SanityManager.DEBUG)
1804:                        SanityManager.DEBUG("DumpUpdateCheck",
1805:                                "cursor select has subquery in SELECT list");
1806:                    return false;
1807:                }
1808:
1809:                if ((getWhereSubquerys() != null)
1810:                        && (getWhereSubquerys().size() != 0)) {
1811:                    if (SanityManager.DEBUG)
1812:                        SanityManager.DEBUG("DumpUpdateCheck",
1813:                                "cursor select has subquery in WHERE clause");
1814:                    return false;
1815:                }
1816:
1817:                return true;
1818:            }
1819:
1820:            /**
1821:            	Assumes that isCursorUpdatable has been called, and that it
1822:            	is only called for updatable cursors.
1823:             */
1824:            FromTable getCursorTargetTable() {
1825:                if (SanityManager.DEBUG)
1826:                    SanityManager
1827:                            .ASSERT(targetTable != null,
1828:                                    "must call isUpdatableCursor() first, and must be updatable");
1829:                return targetTable;
1830:            }
1831:
1832:            /**
1833:             * Search to see if a query references the specifed table name.
1834:             *
1835:             * @param name		Table name (String) to search for.
1836:             * @param baseTable	Whether or not name is for a base table
1837:             *
1838:             * @return	true if found, else false
1839:             *
1840:             * @exception StandardException		Thrown on error
1841:             */
1842:            public boolean referencesTarget(String name, boolean baseTable)
1843:                    throws StandardException {
1844:                if (fromList.referencesTarget(name, baseTable)
1845:                        || (selectSubquerys != null && selectSubquerys
1846:                                .referencesTarget(name, baseTable))
1847:                        || (whereSubquerys != null && whereSubquerys
1848:                                .referencesTarget(name, baseTable))) {
1849:                    return true;
1850:                }
1851:                return false;
1852:            }
1853:
1854:            /** 
1855:             * @see QueryTreeNode#disablePrivilegeCollection
1856:             */
1857:            public void disablePrivilegeCollection() {
1858:                super .disablePrivilegeCollection();
1859:                int fromListSize = fromList.size();
1860:                for (int i = 0; i < fromListSize; i++)
1861:                    ((FromTable) fromList.elementAt(i))
1862:                            .disablePrivilegeCollection();
1863:            }
1864:
1865:            /**
1866:             * Return whether or not this ResultSetNode contains a subquery with a
1867:             * reference to the specified target table.
1868:             * 
1869:             * @param name	The table name.
1870:             * @param baseTable	Whether or not table is a base table.
1871:             *
1872:             * @return boolean	Whether or not a reference to the table was found.
1873:             *
1874:             * @exception StandardException		Thrown on error
1875:             */
1876:            boolean subqueryReferencesTarget(String name, boolean baseTable)
1877:                    throws StandardException {
1878:                if ((selectSubquerys != null && selectSubquerys
1879:                        .referencesTarget(name, baseTable))
1880:                        || (whereSubquerys != null && whereSubquerys
1881:                                .referencesTarget(name, baseTable))) {
1882:                    return true;
1883:                }
1884:                return false;
1885:            }
1886:
1887:            /**
1888:             * Bind any untyped null nodes to the types in the given ResultColumnList.
1889:             *
1890:             * @param bindingRCL	The ResultColumnList with the types to bind to.
1891:             *
1892:             * @exception StandardException		Thrown on error
1893:             */
1894:            public void bindUntypedNullsToResultColumns(
1895:                    ResultColumnList bindingRCL) throws StandardException {
1896:                fromList.bindUntypedNullsToResultColumns(bindingRCL);
1897:            }
1898:
1899:            /**
1900:             * Decrement (query block) level (0-based) for 
1901:             * all of the tables in this ResultSet tree.
1902:             * This is useful when flattening a subquery.
1903:             *
1904:             * @param decrement	The amount to decrement by.
1905:             */
1906:            void decrementLevel(int decrement) {
1907:                /* Decrement the level in the tables */
1908:                fromList.decrementLevel(decrement);
1909:                selectSubquerys.decrementLevel(decrement);
1910:                whereSubquerys.decrementLevel(decrement);
1911:                /* Decrement the level in any CRs in predicates
1912:                 * that are interesting to transitive closure.
1913:                 */
1914:                wherePredicates.decrementLevel(fromList, decrement);
1915:            }
1916:
1917:            /**
1918:             * Determine whether or not this subquery,
1919:             * the SelectNode is in a subquery, can be flattened
1920:             * into the outer query block based on a uniqueness condition.
1921:             * A uniqueness condition exists when we can guarantee
1922:             * that at most 1 row will qualify in each table in the
1923:             * subquery.  This is true if every table in the from list is
1924:             * (a base table and the set of columns from the table that
1925:             * are in equality comparisons with expressions that do not
1926:             * include a column from the same table is a superset of any unique index
1927:             * on the table) or an ExistsBaseTable.
1928:             *
1929:             * @param additionalEQ	Whether or not the column returned
1930:             *						by this select, if it is a ColumnReference,
1931:             *						is in an equality comparison.
1932:             *
1933:             * @return	Whether or not this subquery can be flattened based
1934:             *			on a uniqueness condition.
1935:             *
1936:             * @exception StandardException		Thrown on error
1937:             */
1938:            boolean uniqueSubquery(boolean additionalEQ)
1939:                    throws StandardException {
1940:                ColumnReference additionalCR = null;
1941:                ResultColumn rc = (ResultColumn) getResultColumns()
1942:                        .elementAt(0);
1943:
1944:                /* Figure out if we have an additional ColumnReference
1945:                 * in an equality comparison.
1946:                 */
1947:                if (additionalEQ
1948:                        && rc.getExpression() instanceof  ColumnReference) {
1949:                    additionalCR = (ColumnReference) rc.getExpression();
1950:
1951:                    /* ColumnReference only interesting if it is 
1952:                     * not correlated.
1953:                     */
1954:                    if (additionalCR.getCorrelated()) {
1955:                        additionalCR = null;
1956:                    }
1957:                }
1958:
1959:                return fromList.returnsAtMostSingleRow(
1960:                        (additionalCR == null) ? null : getResultColumns(),
1961:                        whereClause, wherePredicates, getDataDictionary());
1962:            }
1963:
1964:            /**
1965:             * Get the lock mode for the target of an update statement
1966:             * (a delete or update).  The update mode will always be row for
1967:             * CurrentOfNodes.  It will be table if there is no where clause.
1968:             *
1969:             * @see TransactionController
1970:             *
1971:             * @return	The lock mode
1972:             */
1973:            public int updateTargetLockMode() {
1974:                /* Do row locking if there is a restriction */
1975:                return fromList.updateTargetLockMode();
1976:            }
1977:
1978:            /**
1979:             * Return whether or not this ResultSet tree is guaranteed to return
1980:             * at most 1 row based on heuristics.  (A RowResultSetNode and a
1981:             * SELECT with a non-grouped aggregate will return at most 1 row.)
1982:             *
1983:             * @return Whether or not this ResultSet tree is guaranteed to return
1984:             * at most 1 row based on heuristics.
1985:             */
1986:            boolean returnsAtMostOneRow() {
1987:                return (groupByList == null && selectAggregates != null && selectAggregates
1988:                        .size() != 0);
1989:            }
1990:
1991:            /**
1992:             * Return true if the node references SESSION schema tables (temporary or permanent)
1993:             *
1994:             * @return	true if references SESSION schema tables, else false
1995:             *
1996:             * @exception StandardException		Thrown on error
1997:             */
1998:            public boolean referencesSessionSchema() throws StandardException {
1999:                if (fromList.referencesSessionSchema()
2000:                        || (selectSubquerys != null && selectSubquerys
2001:                                .referencesSessionSchema())
2002:                        || (whereSubquerys != null && whereSubquerys
2003:                                .referencesSessionSchema()))
2004:                    return true;
2005:
2006:                return false;
2007:            }
2008:
2009:            /**
2010:             * Accept a visitor, and call v.visit()
2011:             * on child nodes as necessary.  
2012:             * 
2013:             * @param v the visitor
2014:             *
2015:             * @exception StandardException on error
2016:             */
2017:            public Visitable accept(Visitor v) throws StandardException {
2018:                Visitable returnNode = v.visit(this );
2019:
2020:                if (v.skipChildren(this )) {
2021:                    return returnNode;
2022:                }
2023:
2024:                if (!v.stopTraversal()) {
2025:                    super .accept(v);
2026:                }
2027:
2028:                if (fromList != null && !v.stopTraversal()) {
2029:                    fromList = (FromList) fromList.accept(v);
2030:                }
2031:
2032:                if (whereClause != null && !v.stopTraversal()) {
2033:                    whereClause = (ValueNode) whereClause.accept(v);
2034:                }
2035:
2036:                if (wherePredicates != null && !v.stopTraversal()) {
2037:                    wherePredicates = (PredicateList) wherePredicates.accept(v);
2038:                }
2039:
2040:                return returnNode;
2041:            }
2042:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.