Source Code Cross Referenced for FromList.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.FromList
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.services.sanity.SanityManager;
0025:
0026:        import org.apache.derby.iapi.sql.compile.CompilerContext;
0027:        import org.apache.derby.iapi.sql.compile.Optimizable;
0028:        import org.apache.derby.iapi.sql.compile.OptimizableList;
0029:        import org.apache.derby.iapi.sql.compile.Optimizer;
0030:        import org.apache.derby.iapi.sql.compile.Visitable;
0031:        import org.apache.derby.iapi.sql.compile.Visitor;
0032:        import org.apache.derby.iapi.sql.compile.C_NodeTypes;
0033:
0034:        import org.apache.derby.iapi.sql.dictionary.DataDictionary;
0035:
0036:        import org.apache.derby.iapi.error.StandardException;
0037:
0038:        import org.apache.derby.iapi.reference.SQLState;
0039:
0040:        import org.apache.derby.iapi.util.JBitSet;
0041:        import org.apache.derby.iapi.util.StringUtil;
0042:
0043:        import java.util.Properties;
0044:        import java.util.Enumeration;
0045:        import java.util.Vector;
0046:
0047:        /**
0048:         * A FromList represents the list of tables in a FROM clause in a DML
0049:         * statement.  It extends QueryTreeNodeVector.
0050:         *
0051:         * @author Jeff Lichtman
0052:         */
0053:
0054:        public class FromList extends QueryTreeNodeVector implements 
0055:                OptimizableList {
0056:            Properties properties;
0057:            // RESOLVE: The default should be false
0058:            boolean fixedJoinOrder = true;
0059:            // true by default.
0060:            boolean useStatistics = true;
0061:
0062:            // FromList could have a view in it's list. If the view is defined in SESSION
0063:            // schema, then we do not want to cache the statement's plan. This boolean
0064:            // will help keep track of such a condition.
0065:            private boolean referencesSessionSchema;
0066:
0067:            /** Initializer for a FromList */
0068:
0069:            public void init(Object optimizeJoinOrder) {
0070:                fixedJoinOrder = !(((Boolean) optimizeJoinOrder).booleanValue());
0071:            }
0072:
0073:            /**
0074:             * Initializer for a FromList
0075:             *
0076:             * @exception StandardException		Thrown on error
0077:             */
0078:            public void init(Object optimizeJoinOrder, Object fromTable)
0079:                    throws StandardException {
0080:                init(optimizeJoinOrder);
0081:
0082:                addFromTable((FromTable) fromTable);
0083:            }
0084:
0085:            /*
0086:             * OptimizableList interface
0087:             */
0088:
0089:            /**
0090:             * @see org.apache.derby.iapi.sql.compile.OptimizableList#getOptimizable
0091:             */
0092:            public Optimizable getOptimizable(int index) {
0093:                return (Optimizable) elementAt(index);
0094:            }
0095:
0096:            /**
0097:             * @see org.apache.derby.iapi.sql.compile.OptimizableList#setOptimizable
0098:             */
0099:            public void setOptimizable(int index, Optimizable optimizable) {
0100:                setElementAt((FromTable) optimizable, index);
0101:            }
0102:
0103:            /** 
0104:             * @see OptimizableList#verifyProperties
0105:             * @exception StandardException		Thrown on error
0106:             */
0107:            public void verifyProperties(DataDictionary dDictionary)
0108:                    throws StandardException {
0109:                int size = size();
0110:                for (int index = 0; index < size; index++) {
0111:                    ((Optimizable) elementAt(index))
0112:                            .verifyProperties(dDictionary);
0113:                }
0114:            }
0115:
0116:            /**
0117:             * Add a table to the FROM list.
0118:             *
0119:             * @param fromTable	A FromTable to add to the list
0120:             *
0121:             * @exception StandardException		Thrown on error
0122:             */
0123:
0124:            public void addFromTable(FromTable fromTable)
0125:                    throws StandardException {
0126:                /* Don't worry about checking TableOperatorNodes since
0127:                 * they don't have exposed names.  This will potentially
0128:                 * allow duplicate exposed names in some degenerate cases,
0129:                 * but the binding of the ColumnReferences will catch those
0130:                 * cases with a different error.  If the query does not have
0131:                 * any ColumnReferences from the duplicate exposed name, the
0132:                 * user is executing a really dumb query and we won't throw
0133:                 * and exception - consider it an ANSI extension.
0134:                 */
0135:                TableName leftTable = null;
0136:                TableName rightTable = null;
0137:                if (!(fromTable instanceof  TableOperatorNode)) {
0138:                    /* Check for duplicate table name in FROM list */
0139:                    int size = size();
0140:                    for (int index = 0; index < size; index++) {
0141:                        leftTable = fromTable.getTableName();
0142:
0143:                        if (((FromTable) elementAt(index)) instanceof  TableOperatorNode) {
0144:                            continue;
0145:                        }
0146:
0147:                        else {
0148:                            rightTable = ((FromTable) elementAt(index))
0149:                                    .getTableName();
0150:                        }
0151:                        if (leftTable.equals(rightTable)) {
0152:                            throw StandardException
0153:                                    .newException(
0154:                                            SQLState.LANG_FROM_LIST_DUPLICATE_TABLE_NAME,
0155:                                            fromTable.getExposedName());
0156:                        }
0157:                    }
0158:                }
0159:
0160:                addElement(fromTable);
0161:            }
0162:
0163:            /**
0164:             * Search to see if a query references the specifed table name.
0165:             *
0166:             * @param name		Table name (String) to search for.
0167:             * @param baseTable	Whether or not name is for a base table
0168:             *
0169:             * @return	true if found, else false
0170:             *
0171:             * @exception StandardException		Thrown on error
0172:             */
0173:            public boolean referencesTarget(String name, boolean baseTable)
0174:                    throws StandardException {
0175:                FromTable fromTable;
0176:                boolean found = false;
0177:
0178:                /* Check for table or VTI name in FROM list */
0179:                int size = size();
0180:                for (int index = 0; index < size; index++) {
0181:                    fromTable = (FromTable) elementAt(index);
0182:
0183:                    if (fromTable.referencesTarget(name, baseTable)) {
0184:                        found = true;
0185:                        break;
0186:                    }
0187:                }
0188:
0189:                return found;
0190:            }
0191:
0192:            /**
0193:             * Return true if the node references SESSION schema tables (temporary or permanent)
0194:             *
0195:             * @return	true if references SESSION schema tables, else false
0196:             *
0197:             * @exception StandardException		Thrown on error
0198:             */
0199:            public boolean referencesSessionSchema() throws StandardException {
0200:                FromTable fromTable;
0201:                boolean found = false;
0202:
0203:                // Following if will return true if this FromList object had any VIEWs
0204:                // from SESSION schema as elements.  This information is gathered during
0205:                // the bindTables method. At the end of the bindTables, we loose
0206:                // the information on VIEWs since they get replaced with their view
0207:                // definition. Hence, we need to intercept in the middle on the bindTables
0208:                // method and save that information in referencesSeesionSchema field.
0209:                if (referencesSessionSchema)
0210:                    return true;
0211:
0212:                /* Check for table or VTI name in FROM list */
0213:                int size = size();
0214:                for (int index = 0; index < size; index++) {
0215:                    fromTable = (FromTable) elementAt(index);
0216:
0217:                    if (fromTable.referencesSessionSchema()) {
0218:                        found = true;
0219:                        break;
0220:                    }
0221:                }
0222:
0223:                return found;
0224:            }
0225:
0226:            /** 
0227:             * Determine whether or not the specified name is an exposed name in
0228:             * the current query block.
0229:             *
0230:             * @param name	The specified name to search for as an exposed name.
0231:             * @param schemaName	Schema name, if non-null.
0232:             * @param exactMatch	Whether or not we need an exact match on specified schema and table
0233:             *						names or match on table id.
0234:             *
0235:             * @return The FromTable, if any, with the exposed name.
0236:             *
0237:             * @exception StandardException		Thrown on error
0238:             */
0239:            protected FromTable getFromTableByName(String name,
0240:                    String schemaName, boolean exactMatch)
0241:                    throws StandardException {
0242:                boolean found = false;
0243:                FromTable fromTable;
0244:                FromTable result = null;
0245:
0246:                int size = size();
0247:                for (int index = 0; index < size; index++) {
0248:                    fromTable = (FromTable) elementAt(index);
0249:
0250:                    result = fromTable.getFromTableByName(name, schemaName,
0251:                            exactMatch);
0252:
0253:                    if (result != null) {
0254:                        return result;
0255:                    }
0256:                }
0257:                return result;
0258:            }
0259:
0260:            /**
0261:             * Bind the tables in this FromList.  This includes looking them up in
0262:             * the DataDictionary, getting their TableDescriptors and assigning the
0263:             * table numbers.
0264:             *
0265:             * @param dataDictionary	The DataDictionary to use for binding
0266:             * @param fromListParam		FromList to use/append to.
0267:             *
0268:             * @exception StandardException		Thrown on error
0269:             */
0270:
0271:            public void bindTables(DataDictionary dataDictionary,
0272:                    FromList fromListParam) throws StandardException {
0273:                FromTable fromTable;
0274:
0275:                /* Now we bind the tables - this is a 2 step process.
0276:                 * We first bind all of the non-VTIs, then we bind the VTIs.
0277:                 * This enables us to handle the passing of correlation
0278:                 * columns in VTI parameters.
0279:                 * NOTE: We set the table numbers for all of the VTIs in the
0280:                 * first step, when we find them, in order to avoid an ordering
0281:                 * problem with join columns in parameters.
0282:                 */
0283:                int size = size();
0284:                for (int index = 0; index < size; index++) {
0285:                    fromTable = (FromTable) elementAt(index);
0286:                    ResultSetNode newNode = fromTable.bindNonVTITables(
0287:                            dataDictionary, fromListParam);
0288:                    // If the fromTable is a view in the SESSION schema, then we need to save that information
0289:                    // in referencesSessionSchema element. The reason for this is that the view will get
0290:                    // replaced by it's view definition and we will loose the information that the statement
0291:                    // was referencing a SESSION schema object. 
0292:                    if (fromTable.referencesSessionSchema())
0293:                        referencesSessionSchema = true;
0294:                    setElementAt(newNode, index);
0295:                }
0296:                for (int index = 0; index < size; index++) {
0297:                    fromTable = (FromTable) elementAt(index);
0298:                    ResultSetNode newNode = fromTable
0299:                            .bindVTITables(fromListParam);
0300:                    if (fromTable.referencesSessionSchema())
0301:                        referencesSessionSchema = true;
0302:                    setElementAt(newNode, index);
0303:                }
0304:            }
0305:
0306:            /**
0307:             * Bind the expressions in this FromList.  This means 
0308:             * binding the sub-expressions, as well as figuring out what the return 
0309:             * type is for each expression.
0310:             *
0311:             * @exception StandardException		Thrown on error
0312:             */
0313:
0314:            public void bindExpressions(FromList fromListParam)
0315:                    throws StandardException {
0316:                FromTable fromTable;
0317:
0318:                int size = size();
0319:                for (int index = 0; index < size; index++) {
0320:                    fromTable = (FromTable) elementAt(index);
0321:                    fromTable.bindExpressions(makeFromList(fromListParam,
0322:                            fromTable));
0323:                }
0324:            }
0325:
0326:            /**
0327:             * Construct an appropriate from list for binding an individual
0328:             * table element. Normally, this is just this list. However,
0329:             * for the special wrapper queries which the parser creates for
0330:             * GROUP BY and HAVING clauses, the appropriate list is the
0331:             * outer list passed into us--it will contain the appropriate
0332:             * tables needed to resolve correlated columns.
0333:             */
0334:            private FromList makeFromList(FromList fromListParam,
0335:                    FromTable fromTable) {
0336:                if (fromTable instanceof  FromSubquery) {
0337:                    FromSubquery fromSubquery = (FromSubquery) fromTable;
0338:
0339:                    if (fromSubquery.generatedForGroupByClause
0340:                            || fromSubquery.generatedForHavingClause) {
0341:                        return fromListParam;
0342:                    }
0343:                }
0344:
0345:                return this ;
0346:            }
0347:
0348:            /**
0349:             * Bind the result columns of the ResultSetNodes in this FromList when there is no
0350:             * base table to bind them to.  This is useful for SELECT statements,
0351:             * where the result columns get their types from the expressions that
0352:             * live under them.
0353:             *
0354:             * @param fromListParam		FromList to use/append to.
0355:             *
0356:             * @exception StandardException		Thrown on error
0357:             */
0358:
0359:            public void bindResultColumns(FromList fromListParam)
0360:                    throws StandardException {
0361:                FromTable fromTable;
0362:
0363:                int origList = fromListParam.size();
0364:                int size = size();
0365:                for (int index = 0; index < size; index++) {
0366:                    fromTable = (FromTable) elementAt(index);
0367:                    if (fromTable.needsSpecialRCLBinding())
0368:                        fromTable.bindResultColumns(fromListParam);
0369:
0370:                    fromListParam.insertElementAt(fromTable, 0);
0371:                }
0372:
0373:                /* Remove all references added here */
0374:                while (fromListParam.size() > origList)
0375:                    fromListParam.removeElementAt(0);
0376:            }
0377:
0378:            /**
0379:             * Returns true if any Outer joins present. Used to set Nullability
0380:             *
0381:             * @return	True if has any outer joins. False otherwise.
0382:             */
0383:            public boolean hasOuterJoins() throws StandardException {
0384:                FromTable fromTable;
0385:
0386:                int size = size();
0387:                for (int index = 0; index < size; index++) {
0388:                    fromTable = (FromTable) elementAt(index);
0389:                    if (fromTable instanceof  HalfOuterJoinNode)
0390:                        return true;
0391:                }
0392:
0393:                return false;
0394:            }
0395:
0396:            /**
0397:             * Expand a "*" into the appropriate ResultColumnList. If the "*"
0398:             * is unqualified it will expand into a list of all columns in all
0399:             * of the base tables in the from list, otherwise it will expand
0400:             * into a list of all of the columns in the base table that matches
0401:             * the qualification.
0402:             *
0403:             * @param allTableName		The qualification on the "*" as a String.
0404:             *
0405:             * @return ResultColumnList representing expansion
0406:             *
0407:             * @exception StandardException		Thrown on error
0408:             */
0409:            public ResultColumnList expandAll(TableName allTableName)
0410:                    throws StandardException {
0411:                ResultColumnList resultColumnList = null;
0412:                ResultColumnList tempRCList = null;
0413:                boolean matchfound = false;
0414:                FromTable fromTable;
0415:
0416:                /* Expand the "*" for the table that matches, if it is qualified 
0417:                 * (allTableName is not null) or for all tables in the list if the 
0418:                 * "*" is not qualified (allTableName is null).
0419:                 */
0420:                int size = size();
0421:                for (int index = 0; index < size; index++) {
0422:                    fromTable = (FromTable) elementAt(index);
0423:
0424:                    /* We let the FromTable decide if there is a match on
0425:                     * the exposed name.  (A JoinNode will not have an
0426:                     * exposed name, so it will need to pass the info to its
0427:                     * left and right children.)
0428:                     */
0429:                    tempRCList = fromTable.getAllResultColumns(allTableName);
0430:
0431:                    if (tempRCList == null) {
0432:                        continue;
0433:                    }
0434:
0435:                    /* Expand the column list and append to the list that
0436:                     * we will return.
0437:                     */
0438:                    if (resultColumnList == null) {
0439:                        resultColumnList = tempRCList;
0440:                    } else {
0441:                        resultColumnList.nondestructiveAppend(tempRCList);
0442:                    }
0443:
0444:                    /* If the "*" is qualified, then we can stop the
0445:                     * expansion as soon as we find the matching table.
0446:                     */
0447:                    if (allTableName != null) {
0448:                        matchfound = true;
0449:                    }
0450:                }
0451:
0452:                /* Give an error if the qualification name did not match 
0453:                 * an exposed name 
0454:                 */
0455:                if (resultColumnList == null) {
0456:                    throw StandardException.newException(
0457:                            SQLState.LANG_EXPOSED_NAME_NOT_FOUND, allTableName);
0458:                }
0459:
0460:                return resultColumnList;
0461:            }
0462:
0463:            /**
0464:             * Bind a column reference to one of the tables in this FromList.  The column name
0465:             * must be unique within the tables in the FromList.  An exception is thrown
0466:             * if a column name is not unique.
0467:             *
0468:             * NOTE: Callers are responsible for ordering the FromList by nesting level,
0469:             * with tables at the deepest (current) nesting level first.  We will try to 
0470:             * match against all FromTables at a given nesting level.  If no match is
0471:             * found at a nesting level, then we proceed to the next level.  We stop
0472:             * walking the list when the nesting level changes and we have found a match.
0473:             *
0474:             * NOTE: If the ColumnReference is qualified, then we will stop the search
0475:             * at the first nesting level where there is a match on the exposed table name.
0476:             * For example, s (a, b, c), t (d, e, f)
0477:             *		select * from s where exists (select * from t s where s.c = a)
0478:             * will not find a match for s.c, which is the expected ANSI behavior.
0479:             *
0480:             * bindTables() must have already been called on this FromList before
0481:             * calling this method.
0482:             *
0483:             * @param columnReference	The ColumnReference describing the column to bind
0484:             *
0485:             * @return	ResultColumn	The matching ResultColumn
0486:             *
0487:             * @exception StandardException		Thrown on error
0488:             */
0489:
0490:            public ResultColumn bindColumnReference(
0491:                    ColumnReference columnReference) throws StandardException {
0492:                boolean columnNameMatch = false;
0493:                boolean tableNameMatch = false;
0494:                FromTable fromTable;
0495:                int currentLevel = -1;
0496:                int previousLevel = -1;
0497:                ResultColumn matchingRC = null;
0498:                ResultColumn resultColumn;
0499:                String crTableName = columnReference.getTableName();
0500:
0501:                /*
0502:                 ** Find the first table with matching column name.  If there
0503:                 ** is more than one table with a matching column name at the same
0504:                 ** nesting level, give an error.
0505:                 */
0506:                int size = size();
0507:                for (int index = 0; index < size; index++) {
0508:                    fromTable = (FromTable) elementAt(index);
0509:
0510:                    /* We can stop if we've found a matching column or table name 
0511:                     * at the previous nesting level.
0512:                     */
0513:                    currentLevel = fromTable.getLevel();
0514:                    if (previousLevel != currentLevel) {
0515:                        if (columnNameMatch) {
0516:                            break;
0517:                        }
0518:
0519:                        if (tableNameMatch) {
0520:                            break;
0521:                        }
0522:                    }
0523:                    /* Simpler to always set previousLevel then to test and set */
0524:                    previousLevel = currentLevel;
0525:
0526:                    resultColumn = fromTable.getMatchingColumn(columnReference);
0527:
0528:                    if (resultColumn != null) {
0529:                        if (!columnNameMatch) {
0530:                            /* TableNumbers are set in the CR in the underlying
0531:                             * FromTable.  This ensures that they get the table
0532:                             * number from the underlying table, not the join node.
0533:                             * This is important for beging able to push predicates 
0534:                             * down through join nodes.
0535:                             */
0536:                            matchingRC = resultColumn;
0537:                            columnReference.setSource(resultColumn);
0538:                            columnReference.setType(resultColumn
0539:                                    .getTypeServices());
0540:                            /* Set the nesting level at which the CR appears and the nesting level
0541:                             * of its source RC.
0542:                             */
0543:                            columnReference
0544:                                    .setNestingLevel(((FromTable) elementAt(0))
0545:                                            .getLevel());
0546:                            columnReference.setSourceLevel(currentLevel);
0547:                            columnNameMatch = true;
0548:
0549:                            if (fromTable.isPrivilegeCollectionRequired())
0550:                                getCompilerContext()
0551:                                        .addRequiredColumnPriv(
0552:                                                resultColumn
0553:                                                        .getTableColumnDescriptor());
0554:                        } else {
0555:                            throw StandardException.newException(
0556:                                    SQLState.LANG_AMBIGUOUS_COLUMN_NAME,
0557:                                    columnReference.getSQLColumnName());
0558:                        }
0559:                    }
0560:
0561:                    /* Remember if we get a match on the exposed table name, so that
0562:                     * we can stop at the beginning of the next level.
0563:                     */
0564:                    tableNameMatch = tableNameMatch
0565:                            || (crTableName != null && crTableName
0566:                                    .equals(fromTable.getExposedName()));
0567:                }
0568:
0569:                return matchingRC;
0570:            }
0571:
0572:            /**
0573:             * Check for (and reject) all ? parameters directly under the ResultColumns.
0574:             * This is done for SELECT statements.
0575:             *
0576:             * @exception StandardException		Thrown if a ? parameter found
0577:             *									directly under a ResultColumn
0578:             */
0579:
0580:            public void rejectParameters() throws StandardException {
0581:                FromTable fromTable;
0582:
0583:                int size = size();
0584:                for (int index = 0; index < size; index++) {
0585:                    fromTable = (FromTable) elementAt(index);
0586:                    fromTable.rejectParameters();
0587:                }
0588:            }
0589:
0590:            // This method reorders LOJs in the FROM clause.
0591:            // For now, we process only a LOJ.  For example, "... from LOJ_1, LOJ2 ..."
0592:            // will not be processed. 
0593:            public boolean LOJ_reorderable(int numTables)
0594:                    throws StandardException {
0595:                boolean anyChange = false;
0596:
0597:                if (size() > 1)
0598:                    return anyChange;
0599:
0600:                FromTable ft = (FromTable) elementAt(0);
0601:
0602:                anyChange = ft.LOJ_reorderable(numTables);
0603:
0604:                return anyChange;
0605:            }
0606:
0607:            /**
0608:             * Preprocess the query tree - this currently means:
0609:             *	o  Generating a referenced table map for each ResultSetNode.
0610:             *  o  Putting the WHERE and HAVING clauses in conjunctive normal form (CNF).
0611:             *  o  Converting the WHERE and HAVING clauses into PredicateLists and
0612:             *	   classifying them.
0613:             *  o  Flatten those FromSubqueries which can be flattened.
0614:             *  o  Ensuring that a ProjectRestrictNode is generated on top of every 
0615:             *     FromBaseTable and generated in place of every FromSubquery which
0616:             *	   could not be flattened.  
0617:             *  o  Pushing single table predicates down to the new ProjectRestrictNodes.
0618:             *
0619:             * @param numTables			The number of tables in the DML Statement
0620:             * @param gbl				The group by list, if any
0621:             *
0622:             * @exception StandardException		Thrown on error
0623:             */
0624:            public void preprocess(int numTables, GroupByList gbl,
0625:                    ValueNode predicateTree) throws StandardException {
0626:                int size = size();
0627:
0628:                /* Preprocess each FromTable in the list */
0629:                for (int index = 0; index < size; index++) {
0630:                    FromTable ft = (FromTable) elementAt(index);
0631:
0632:                    /* Transform any outer joins to inner joins where appropriate */
0633:                    ft = ft.transformOuterJoins(predicateTree, numTables);
0634:                    /* Preprocess this FromTable */
0635:                    setElementAt(ft.preprocess(numTables, gbl, this ), index);
0636:                }
0637:            }
0638:
0639:            /**
0640:             * Flatten all the FromTables that are flattenable.
0641:             * RESOLVE - right now we just flatten FromSubqueries.  We
0642:             * should also flatten flattenable JoinNodes here.
0643:             *
0644:             * @param rcl				The RCL from the outer query
0645:             * @param predicateList		The PredicateList from the outer query
0646:             * @param sql				The SubqueryList from the outer query
0647:             * @param gbl				The group by list, if any
0648:             *
0649:             * @exception StandardException		Thrown on error
0650:             */
0651:            public void flattenFromTables(ResultColumnList rcl,
0652:                    PredicateList predicateList, SubqueryList sql,
0653:                    GroupByList gbl) throws StandardException {
0654:                boolean flattened = true;
0655:                Vector flattenedTableNumbers = new Vector();
0656:
0657:                if (SanityManager.DEBUG) {
0658:                    SanityManager.ASSERT(rcl != null,
0659:                            "rcl is expected to be non-null");
0660:                    SanityManager.ASSERT(predicateList != null,
0661:                            "predicateList is expected to be non-null");
0662:                    SanityManager.ASSERT(sql != null,
0663:                            "sql is expected to be non-null");
0664:                }
0665:
0666:                /* Loop until all flattenable entries are flattened.
0667:                 * We restart the inner loop after flattening an in place
0668:                 * to simplify the logic and so that we don't have to worry
0669:                 * about walking a list while we are modifying it.
0670:                 */
0671:                while (flattened) {
0672:                    flattened = false;
0673:
0674:                    for (int index = 0; index < size() && !flattened; index++) {
0675:                        FromTable ft = (FromTable) elementAt(index);
0676:
0677:                        /* Flatten FromSubquerys and flattenable JoinNodes */
0678:                        if ((ft instanceof  FromSubquery)
0679:                                || ft.isFlattenableJoinNode()) {
0680:                            //save the table number of the node to be flattened
0681:                            flattenedTableNumbers.addElement(new Integer(ft
0682:                                    .getTableNumber()));
0683:
0684:                            /* Remove the node from the list and insert its
0685:                             * FromList here.
0686:                             */
0687:                            FromList flatteningFL = ft.flatten(rcl,
0688:                                    predicateList, sql, gbl);
0689:                            if (SanityManager.DEBUG) {
0690:                                SanityManager
0691:                                        .ASSERT(flatteningFL == null
0692:                                                || flatteningFL.size() > 0,
0693:                                                "flatteningFL expected to be null or size > 0");
0694:                            }
0695:
0696:                            if (flatteningFL != null) {
0697:                                setElementAt(flatteningFL.elementAt(0), index);
0698:
0699:                                int innerSize = flatteningFL.size();
0700:                                for (int inner = 1; inner < innerSize; inner++) {
0701:                                    insertElementAt(flatteningFL
0702:                                            .elementAt(inner), index + inner);
0703:                                }
0704:                            } else {
0705:                                /*
0706:                                 ** If flatten returns null, that means it wants to
0707:                                 ** be removed from the FromList.
0708:                                 */
0709:                                removeElementAt(index);
0710:                            }
0711:                            flattened = true;
0712:                        }
0713:                    }
0714:                }
0715:
0716:                /* fix up dependency maps for exists base tables since they might have a
0717:                 * dependency on this join node
0718:                 */
0719:                if (flattenedTableNumbers.size() > 0) {
0720:                    for (int i = 0; i < size(); i++) {
0721:                        FromTable ft = (FromTable) elementAt(i);
0722:                        if (ft instanceof  ProjectRestrictNode) {
0723:                            ResultSetNode rst = ((ProjectRestrictNode) ft)
0724:                                    .getChildResult();
0725:                            if (rst instanceof  FromBaseTable) {
0726:                                ((FromBaseTable) rst)
0727:                                        .clearDependency(flattenedTableNumbers);
0728:                            }
0729:                        }
0730:                    }
0731:                }
0732:            }
0733:
0734:            /**
0735:             * Categorize and push the predicates that are pushable.
0736:             *
0737:             * @param predicateList		The query's PredicateList
0738:             *
0739:             * @exception StandardException		Thrown on error
0740:             */
0741:            void pushPredicates(PredicateList predicateList)
0742:                    throws StandardException {
0743:                if (SanityManager.DEBUG) {
0744:                    SanityManager.ASSERT(predicateList != null,
0745:                            "predicateList is expected to be non-null");
0746:                }
0747:
0748:                /* We can finally categorize each Predicate and try to push them down.
0749:                 * NOTE: The PredicateList may be empty, but that's okay, we still
0750:                 * call pushExpressions() for each entry in the FromList because that's
0751:                 * where any outer join conditions will get pushed down.
0752:                 */
0753:                predicateList.categorize();
0754:
0755:                int size = size();
0756:                for (int index = 0; index < size; index++) {
0757:                    FromTable fromTable = (FromTable) elementAt(index);
0758:                    fromTable.pushExpressions(predicateList);
0759:                }
0760:            }
0761:
0762:            /**
0763:             * Prints the sub-nodes of this object.  See QueryTreeNode.java for
0764:             * how tree printing is supposed to work.
0765:             *
0766:             * @param depth		The depth of this node in the tree
0767:             */
0768:
0769:            public void printSubNodes(int depth) {
0770:                if (SanityManager.DEBUG) {
0771:                    FromTable fromTable;
0772:
0773:                    super .printSubNodes(depth);
0774:
0775:                    int size = size();
0776:                    for (int index = 0; index < size; index++) {
0777:                        fromTable = (FromTable) elementAt(index);
0778:                        fromTable.treePrint(depth + 1);
0779:                    }
0780:                }
0781:            }
0782:
0783:            /**
0784:             * Set the (query block) level (0-based) for the FromTables in this
0785:             * FromList.
0786:             *
0787:             * @param level		The query block level for this table.
0788:             */
0789:            public void setLevel(int level) {
0790:                int size = size();
0791:                for (int index = 0; index < size; index++) {
0792:                    FromTable fromTable = (FromTable) elementAt(index);
0793:                    fromTable.setLevel(level);
0794:                }
0795:            }
0796:
0797:            /**
0798:             * Get the FromTable from this list which has the specified ResultColumn in
0799:             * its RCL.
0800:             *
0801:             * @param rc	The ResultColumn match on.
0802:             *
0803:             * @return FromTable	The matching FromTable.
0804:             */
0805:            public FromTable getFromTableByResultColumn(ResultColumn rc) {
0806:                FromTable fromTable = null;
0807:
0808:                int size = size();
0809:                for (int index = 0; index < size; index++) {
0810:                    fromTable = (FromTable) elementAt(index);
0811:
0812:                    if (fromTable.getResultColumns().indexOf(rc) != -1) {
0813:                        break;
0814:                    }
0815:                }
0816:
0817:                if (SanityManager.DEBUG) {
0818:                    SanityManager.ASSERT(fromTable != null,
0819:                            "No matching FromTable found");
0820:                }
0821:                return fromTable;
0822:            }
0823:
0824:            /**
0825:             * Set the Properties list for this FromList.
0826:             *
0827:             * @exception StandardException		Thrown on error
0828:             */
0829:            public void setProperties(Properties props)
0830:                    throws StandardException {
0831:                properties = props;
0832:
0833:                /*
0834:                 ** Validate the properties list now.  This is possible because
0835:                 ** there is nothing in this properties list that relies on binding
0836:                 ** or optimization to validate.
0837:                 */
0838:                Enumeration e = properties.keys();
0839:                while (e.hasMoreElements()) {
0840:                    String key = (String) e.nextElement();
0841:                    String value = (String) properties.get(key);
0842:
0843:                    if (key.equals("joinOrder")) {
0844:                        if (StringUtil.SQLEqualsIgnoreCase(value, "fixed")) {
0845:                            fixedJoinOrder = true;
0846:                        } else if (StringUtil.SQLEqualsIgnoreCase(value,
0847:                                "unfixed")) {
0848:                            fixedJoinOrder = false;
0849:                        } else {
0850:                            throw StandardException.newException(
0851:                                    SQLState.LANG_INVALID_JOIN_ORDER_SPEC,
0852:                                    value);
0853:                        }
0854:                    } else if (key.equals("useStatistics")) {
0855:                        if (StringUtil.SQLEqualsIgnoreCase(value, "true")) {
0856:                            useStatistics = true;
0857:                        } else if (StringUtil.SQLEqualsIgnoreCase(value,
0858:                                "false")) {
0859:                            useStatistics = false;
0860:                        } else {
0861:                            throw StandardException.newException(
0862:                                    SQLState.LANG_INVALID_STATISTICS_SPEC,
0863:                                    value);
0864:                        }
0865:                    } else {
0866:                        throw StandardException.newException(
0867:                                SQLState.LANG_INVALID_FROM_LIST_PROPERTY, key,
0868:                                value);
0869:                    }
0870:                }
0871:            }
0872:
0873:            /** @see OptimizableList#reOrder */
0874:            public void reOrder(int[] joinOrder) {
0875:                int posn;
0876:
0877:                if (SanityManager.DEBUG) {
0878:                    if (joinOrder.length != size()) {
0879:                        SanityManager
0880:                                .THROWASSERT("In reOrder(), size of FromList is "
0881:                                        + size()
0882:                                        + " while size of joinOrder array is "
0883:                                        + joinOrder.length);
0884:                    }
0885:
0886:                    /*
0887:                     ** Determine that the values in the list are unique and in range.
0888:                     ** The easiest way to determine that they are unique is to add
0889:                     ** them all up and see whether the result is what's expected
0890:                     ** for that array size.
0891:                     */
0892:                    int sum = 0;
0893:                    for (int i = 0; i < joinOrder.length; i++) {
0894:                        if (joinOrder[i] < 0
0895:                                || joinOrder[i] > (joinOrder.length - 1)) {
0896:                            SanityManager
0897:                                    .THROWASSERT("joinOrder["
0898:                                            + i
0899:                                            + "] == "
0900:                                            + joinOrder[i]
0901:                                            + " is out of range - must be between 0 and "
0902:                                            + (joinOrder.length - 1)
0903:                                            + " inclusive.");
0904:                        }
0905:
0906:                        sum += joinOrder[i];
0907:                    }
0908:
0909:                    /*
0910:                     ** The sum of all integers from 0 through n is (n * (n - 1)) / 2.
0911:                     */
0912:                    if (sum != ((joinOrder.length * (joinOrder.length - 1)) / 2)) {
0913:                        String arrayVals = "";
0914:                        for (int i = 0; i < joinOrder.length; i++)
0915:                            arrayVals = arrayVals + joinOrder[i] + " ";
0916:                        SanityManager
0917:                                .THROWASSERT("joinOrder array has some duplicate value: "
0918:                                        + arrayVals);
0919:                    }
0920:                }
0921:
0922:                /* Form a list that's in the order we want */
0923:                QueryTreeNode[] orderedFL = new FromTable[joinOrder.length];
0924:                for (posn = 0; posn < joinOrder.length; posn++) {
0925:                    /*
0926:                     ** Get the element at the i'th join order position from the
0927:                     ** current list and make it the next element of orderedList.
0928:                     */
0929:                    orderedFL[posn] = elementAt(joinOrder[posn]);
0930:                }
0931:
0932:                /* Now orderedList has been built, so set this list to the same order */
0933:                for (posn = 0; posn < joinOrder.length; posn++) {
0934:                    setElementAt(orderedFL[posn], posn);
0935:                }
0936:            }
0937:
0938:            /** @see OptimizableList#useStatistics */
0939:            public boolean useStatistics() {
0940:                return useStatistics;
0941:            }
0942:
0943:            /** @see OptimizableList#optimizeJoinOrder */
0944:            public boolean optimizeJoinOrder() {
0945:                return !fixedJoinOrder;
0946:            }
0947:
0948:            /** @see OptimizableList#legalJoinOrder */
0949:            public boolean legalJoinOrder(int numTablesInQuery) {
0950:                JBitSet assignedTableMap = new JBitSet(numTablesInQuery);
0951:
0952:                int size = size();
0953:                for (int index = 0; index < size; index++) {
0954:                    FromTable ft = (FromTable) elementAt(index);
0955:                    assignedTableMap.or(ft.getReferencedTableMap());
0956:                    if (!ft.legalJoinOrder(assignedTableMap)) {
0957:                        return false;
0958:                    }
0959:                }
0960:                return true;
0961:            }
0962:
0963:            /** @see OptimizableList#initAccessPaths */
0964:            public void initAccessPaths(Optimizer optimizer) {
0965:                int size = size();
0966:                for (int index = 0; index < size; index++) {
0967:                    FromTable ft = (FromTable) elementAt(index);
0968:                    ft.initAccessPaths(optimizer);
0969:                }
0970:            }
0971:
0972:            /**
0973:             * Bind any untyped null nodes to the types in the given ResultColumnList.
0974:             *
0975:             * @param bindingRCL	The ResultColumnList with the types to bind to.
0976:             *
0977:             * @exception StandardException		Thrown on error
0978:             */
0979:            public void bindUntypedNullsToResultColumns(
0980:                    ResultColumnList bindingRCL) throws StandardException {
0981:                int size = size();
0982:                for (int index = 0; index < size; index++) {
0983:                    FromTable fromTable = (FromTable) elementAt(index);
0984:                    fromTable.bindUntypedNullsToResultColumns(bindingRCL);
0985:                }
0986:            }
0987:
0988:            /**
0989:             * Decrement (query block) level (0-based) for
0990:             * all of the tables in this from list.
0991:             * This is useful when flattening a subquery.
0992:             *
0993:             * @param decrement	The amount to decrement by.
0994:             */
0995:            void decrementLevel(int decrement) {
0996:                int size = size();
0997:                for (int index = 0; index < size; index++) {
0998:                    FromTable fromTable = (FromTable) elementAt(index);
0999:                    fromTable.decrementLevel(decrement);
1000:
1001:                    /* Decrement the level of any CRs in single table
1002:                     * predicates that are interesting to transitive
1003:                     * closure.
1004:                     */
1005:                    ProjectRestrictNode prn = (ProjectRestrictNode) fromTable;
1006:                    PredicateList pl = prn.getRestrictionList();
1007:                    if (pl != null) {
1008:                        pl.decrementLevel(this , decrement);
1009:                    }
1010:                }
1011:            }
1012:
1013:            /**
1014:             * This method is used for both subquery flattening and distinct
1015:             * elimination based on a uniqueness condition.  For subquery
1016:             * flattening we want to make sure that the query block
1017:             * will return at most 1 row.  For distinct elimination we
1018:             * want to make sure that the query block will not return
1019:             * any duplicates.
1020:             * This is true if every table in the from list is
1021:             * (a base table and the set of columns from the table that
1022:             * are in equality comparisons with expressions that do not include columns
1023:             * from the same table is a superset of any unique index
1024:             * on the table) or an EXISTS FBT.  In addition, at least 1 of the tables
1025:             * in the list has a set of columns in equality comparisons with expressions
1026:             * that do not include column references from the same query block
1027:             * is a superset of a unique index
1028:             * on that table.  (This ensures that the query block will onlyr
1029:             * return a single row.)
1030:             * This method is expected to be called after normalization and
1031:             * after the from list has been preprocessed.
1032:             * It can be called both before and after the predicates have
1033:             * been pulled from the where clause.
1034:             * The algorithm for this is as follows
1035:             *
1036:             *	If any table in the query block is not a base table, give up.
1037:             * 	For each table in the query
1038:             *		Ignore exists table since they can only produce one row
1039:             *
1040:             *		create a matrix of tables and columns from the table (tableColMap)
1041:             *		(this is used to keep track of the join columns and constants
1042:             *		that can be used to figure out whether the rows from a join
1043:             *		or in a select list are distinct based on unique indexes)
1044:             *
1045:             *		create an array of columns from the table(eqOuterCol)
1046:             *		(this is used to determine that only one row will be returned
1047:             *		from a join)
1048:             *
1049:             *		if the current table is the table for the result columns
1050:             *			set the result columns in the eqOuterCol and tableColMap
1051:             *			(if these columns are a superset of a unique index and
1052:             *			all joining tables result in only one row, the
1053:             *			results will be distinct)
1054:             *		go through all the predicates and update tableColMap  and
1055:             *		eqOuterCol with join columns and correlation variables,
1056:             *		parameters and constants
1057:             *		since setting constants, correlation variables and parameters,
1058:             * 		reduces the number of columns required for uniqueness in a
1059:             *		multi-column index, they are set for all the tables (if the
1060:             *		table is not the result table, in this case only the column of the
1061:             *		result table is set)
1062:             *		join columns are just updated for the column in the row of the
1063:             *		joining table.
1064:             *
1065:             *		check if the marked columns in tableColMap are a superset of a unique
1066:             *			index
1067:             *			(This means that the join will only produce 1 row when joined
1068:             *			with 1 row of another table)
1069:             *		check that there is a least one table for which the columns in
1070:             *			eqOuterCol(i.e. constant values) are a superset of a unique index
1071:             *			(This quarantees that there will be only one row selected
1072:             *			from this table).
1073:             *
1074:             *	Once all tables have been evaluated, check that all the tables can be
1075:             * 	joined by unique index or will have only one row
1076:             *
1077:             *
1078:             *
1079:             * @param rcl				If non-null, the RCL from the query block.
1080:             *							If non-null for subqueries, then entry can
1081:             *							be considered as part of an = comparison.
1082:             * @param whereClause		The WHERE clause to consider.
1083:             * @param wherePredicates	The predicates that have already been
1084:             *							pulled from the WHERE clause.
1085:             * @param dd				The DataDictionary to use.
1086:             *
1087:             * @return	Whether or not query block will return
1088:             *			at most 1 row for a subquery, no duplicates
1089:             *			for a distinct.
1090:             *
1091:             * @exception StandardException		Thrown on error
1092:             */
1093:            boolean returnsAtMostSingleRow(ResultColumnList rcl,
1094:                    ValueNode whereClause, PredicateList wherePredicates,
1095:                    DataDictionary dd) throws StandardException {
1096:                boolean satisfiesOuter = false;
1097:                int[] tableNumbers;
1098:                ColumnReference additionalCR = null;
1099:
1100:                PredicateList predicatesTemp;
1101:                predicatesTemp = (PredicateList) getNodeFactory().getNode(
1102:                        C_NodeTypes.PREDICATE_LIST, getContextManager());
1103:                int wherePredicatesSize = wherePredicates.size();
1104:                for (int index = 0; index < wherePredicatesSize; index++)
1105:                    predicatesTemp.addPredicate((Predicate) wherePredicates
1106:                            .elementAt(index));
1107:
1108:                /* When considering subquery flattening, we are interested
1109:                 * in the 1st (and only) entry in the RCL.  (The RCL will be
1110:                 * null if result column is not of interest for subquery flattening.)
1111:                 * We are interested in all entries in the RCL for distinct
1112:                 * elimination.
1113:                 */
1114:                if (rcl != null) {
1115:                    ResultColumn rc = (ResultColumn) rcl.elementAt(0);
1116:                    if (rc.getExpression() instanceof  ColumnReference) {
1117:                        additionalCR = (ColumnReference) rc.getExpression();
1118:                    }
1119:                }
1120:
1121:                /* First see if all entries are FromBaseTables.  No point
1122:                 * in continuing if not.
1123:                 */
1124:                int size = size();
1125:                for (int index = 0; index < size; index++) {
1126:                    FromTable fromTable = (FromTable) elementAt(index);
1127:                    if (!(fromTable instanceof  ProjectRestrictNode)) {
1128:                        return false;
1129:                    }
1130:
1131:                    ProjectRestrictNode prn = (ProjectRestrictNode) fromTable;
1132:
1133:                    if (!(prn.getChildResult() instanceof  FromBaseTable)) {
1134:                        return false;
1135:                    }
1136:                    FromBaseTable fbt = (FromBaseTable) prn.getChildResult();
1137:                    //Following for loop code is to take care of Derby-251 (DISTINCT returns
1138:                    //duplicate rows).
1139:                    //Derby-251 returned duplicate rows because we were looking at predicates
1140:                    //that belong to existsTable to determine DISTINCT elimination
1141:                    //
1142:                    //(Check method level comments to understand DISTINCT elimination rules.)
1143:                    //
1144:                    //For one specific example, consider the query below
1145:                    //select  distinct  q1."NO1" from IDEPT q1, IDEPT q2
1146:                    //where  ( q2."DISCRIM_DEPT" = 'HardwareDept')
1147:                    //and  ( q1."DISCRIM_DEPT" = 'SoftwareDept')  and  ( q1."NO1" <> ALL
1148:                    //(select  q3."NO1" from IDEPT q3 where  (q3."REPORTTO_NO" =  q2."NO1")))
1149:                    //(select  q3."NO1" from IDEPT q3 where  ( ABS(q3."REPORTTO_NO") =  q2."NO1")))
1150:                    //
1151:                    //Table IDEPT in the query above has a primary key defined on column "NO1"
1152:                    //This query gets converted to following during optimization
1153:                    //
1154:                    //select  distinct  q1."NO1" from IDEPT q1, IDEPT q2
1155:                    //where  ( q2."DISCRIM_DEPT" = 'HardwareDept')
1156:                    //and  ( q1."DISCRIM_DEPT" = 'SoftwareDept')  and  not exists (
1157:                    //(select  q3."NO1" from IDEPT q3 where
1158:                    //(  ( ABS(q3."REPORTTO_NO") =  q2."NO1")  and q3."NO1" = q1."NO1") ) )  ;
1159:                    //
1160:                    //For the optimized query above, Derby generates following predicates.
1161:                    //ABS(q3.reportto_no) = q2.no1
1162:                    //q2.discrim_dept = 'HardwareDept'
1163:                    //q1.descrim_dept = 'SoftwareDept'
1164:                    //q1.no1 = q3.no1
1165:                    //The predicate ABS(q3."NO1") = q1."NO1" should not be considered when trying
1166:                    //to determine if q1 in the outer query has equality comparisons. 
1167:                    //Similarly, the predicate q3.reportto_no = q2.no1 should not be
1168:                    //considered when trying to determine if q2 in the outer query has
1169:                    //equality comparisons. To achieve this, predicates based on exists base
1170:                    //table q3 (the first and the last predicate) should be removed while
1171:                    //evaluating outer query for uniqueness.
1172:                    //
1173:                    if (fbt.getExistsBaseTable()) {
1174:                        int existsTableNumber = fbt.getTableNumber();
1175:                        int predicatesTempSize = predicatesTemp.size();
1176:                        for (int predicatesTempIndex = predicatesTempSize - 1; predicatesTempIndex >= 0; predicatesTempIndex--) {
1177:                            AndNode topAndNode = (AndNode) ((Predicate) predicatesTemp
1178:                                    .elementAt(predicatesTempIndex))
1179:                                    .getAndNode();
1180:
1181:                            for (ValueNode whereWalker = topAndNode; whereWalker instanceof  AndNode; whereWalker = ((AndNode) whereWalker)
1182:                                    .getRightOperand()) {
1183:                                // See if this is a candidate =
1184:                                AndNode and = (AndNode) whereWalker;
1185:
1186:                                //we only need to worry about equality predicates because only those
1187:                                //predicates are considered during DISTINCT elimination.
1188:                                if (!and.getLeftOperand()
1189:                                        .isRelationalOperator()
1190:                                        || !(((RelationalOperator) (and
1191:                                                .getLeftOperand()))
1192:                                                .getOperator() == RelationalOperator.EQUALS_RELOP)) {
1193:                                    continue;
1194:                                }
1195:
1196:                                JBitSet referencedTables = and.getLeftOperand()
1197:                                        .getTablesReferenced();
1198:                                if (referencedTables.get(existsTableNumber)) {
1199:                                    predicatesTemp
1200:                                            .removeElementAt(predicatesTempIndex);
1201:                                    break;
1202:                                }
1203:                            }
1204:                        }
1205:                    }
1206:                }
1207:
1208:                /* Build an array of tableNumbers from this query block.
1209:                 * We will use that array to find out if we have at least
1210:                 * one table with a uniqueness condition based only on
1211:                 * constants, parameters and correlation columns.
1212:                 */
1213:                tableNumbers = getTableNumbers();
1214:                JBitSet[][] tableColMap = new JBitSet[size][size];
1215:                boolean[] oneRow = new boolean[size];
1216:                boolean oneRowResult = false;
1217:
1218:                /* See if each table has a uniqueness condition */
1219:                for (int index = 0; index < size; index++) {
1220:                    ProjectRestrictNode prn = (ProjectRestrictNode) elementAt(index);
1221:                    FromBaseTable fbt = (FromBaseTable) prn.getChildResult();
1222:
1223:                    // Skip over EXISTS FBT since they cannot introduce duplicates
1224:                    if (fbt.getExistsBaseTable()) {
1225:                        oneRow[index] = true;
1226:                        continue;
1227:                    }
1228:
1229:                    int numColumns = fbt.getTableDescriptor()
1230:                            .getNumberOfColumns();
1231:                    boolean[] eqOuterCols = new boolean[numColumns + 1];
1232:                    int tableNumber = fbt.getTableNumber();
1233:                    boolean resultColTable = false;
1234:                    for (int i = 0; i < size; i++)
1235:                        tableColMap[index][i] = new JBitSet(numColumns + 1);
1236:
1237:                    if (additionalCR != null
1238:                            && additionalCR.getTableNumber() == tableNumber) {
1239:                        rcl.recordColumnReferences(eqOuterCols,
1240:                                tableColMap[index], index);
1241:                        resultColTable = true;
1242:                    }
1243:
1244:                    /* Now see if there are any equality conditions
1245:                     * of interest in the where clause.
1246:                     */
1247:                    if (whereClause != null) {
1248:                        whereClause.checkTopPredicatesForEqualsConditions(
1249:                                tableNumber, eqOuterCols, tableNumbers,
1250:                                tableColMap[index], resultColTable);
1251:                    }
1252:
1253:                    /* Now see if there are any equality conditions
1254:                     * of interest in the where predicates.
1255:                     */
1256:                    predicatesTemp.checkTopPredicatesForEqualsConditions(
1257:                            tableNumber, eqOuterCols, tableNumbers,
1258:                            tableColMap[index], resultColTable);
1259:
1260:                    /* Now see if there are any equality conditions
1261:                     * of interest that were already pushed down to the
1262:                     * PRN above the FBT. (Single table predicates.)
1263:                     */
1264:                    if (prn.getRestrictionList() != null) {
1265:                        prn.getRestrictionList()
1266:                                .checkTopPredicatesForEqualsConditions(
1267:                                        tableNumber, eqOuterCols, tableNumbers,
1268:                                        tableColMap[index], resultColTable);
1269:                    }
1270:
1271:                    /* We can finally check to see if the marked columns
1272:                     * are a superset of any unique index.
1273:                     */
1274:                    if (!fbt.super setOfUniqueIndex(tableColMap[index])) {
1275:                        return false;
1276:                    }
1277:
1278:                    /* Do we have at least 1 table whose equality condition
1279:                     * is based solely on constants, parameters and correlation columns.
1280:                     */
1281:                    oneRowResult = fbt.super setOfUniqueIndex(eqOuterCols);
1282:                    if (oneRowResult) {
1283:                        oneRow[index] = true;
1284:                        satisfiesOuter = true;
1285:                    }
1286:                }
1287:
1288:                /* Have we met all of the criteria */
1289:                if (satisfiesOuter) {
1290:                    /* check that all the tables are joined by unique indexes 
1291:                     * or only produce 1 row
1292:                     */
1293:                    boolean foundOneRow = true;
1294:                    while (foundOneRow) {
1295:                        foundOneRow = false;
1296:                        for (int index = 0; index < size; index++) {
1297:                            if (oneRow[index]) {
1298:                                for (int i = 0; i < size; i++) {
1299:                                    /* unique key join - exists tables already marked as 
1300:                                     * 1 row - so don't need to look at them
1301:                                     */
1302:                                    if (!oneRow[i]
1303:                                            && tableColMap[i][index].get(0)) {
1304:                                        oneRow[i] = true;
1305:                                        foundOneRow = true;
1306:                                    }
1307:                                }
1308:                            }
1309:                        }
1310:                    }
1311:                    /* does any table produce more than one row */
1312:                    for (int index = 0; index < size; index++) {
1313:                        if (!oneRow[index]) {
1314:                            satisfiesOuter = false;
1315:                            break;
1316:                        }
1317:                    }
1318:                }
1319:                return satisfiesOuter;
1320:            }
1321:
1322:            int[] getTableNumbers() {
1323:                int size = size();
1324:                int[] tableNumbers = new int[size];
1325:                for (int index = 0; index < size; index++) {
1326:                    ProjectRestrictNode prn = (ProjectRestrictNode) elementAt(index);
1327:                    if (!(prn.getChildResult() instanceof  FromTable)) {
1328:                        continue;
1329:                    }
1330:                    FromTable ft = (FromTable) prn.getChildResult();
1331:                    tableNumbers[index] = ft.getTableNumber();
1332:                }
1333:
1334:                return tableNumbers;
1335:            }
1336:
1337:            /**
1338:             * Mark all of the FromBaseTables in the list as EXISTS FBTs.
1339:             * Each EBT has the same dependency list - those tables that are referenced
1340:             * minus the tables in the from list.
1341:             *
1342:             * @param referencedTableMap	The referenced table map.
1343:             * @param outerFromList			FromList from outer query block
1344:             * @param isNotExists			Whether or not for NOT EXISTS
1345:             *
1346:             * @exception StandardException		Thrown on error
1347:             */
1348:            void genExistsBaseTables(JBitSet referencedTableMap,
1349:                    FromList outerFromList, boolean isNotExists)
1350:                    throws StandardException {
1351:                JBitSet dependencyMap = (JBitSet) referencedTableMap.clone();
1352:
1353:                // We currently only flatten single table from lists
1354:                if (SanityManager.DEBUG) {
1355:                    if (size() != 1) {
1356:                        SanityManager
1357:                                .THROWASSERT("size() expected to be 1, not "
1358:                                        + size());
1359:                    }
1360:                }
1361:
1362:                /* Create the dependency map */
1363:                int size = size();
1364:                for (int index = 0; index < size; index++) {
1365:                    ResultSetNode ft = ((ProjectRestrictNode) elementAt(index))
1366:                            .getChildResult();
1367:                    if (ft instanceof  FromTable) {
1368:                        dependencyMap.clear(((FromTable) ft).getTableNumber());
1369:                    }
1370:                }
1371:
1372:                /* Degenerate case - If flattening a non-correlated EXISTS subquery
1373:                 * then we need to make the table that is getting flattened dependendent on
1374:                 * all of the tables in the outer query block.  Gross but true.  Otherwise
1375:                 * that table can get chosen as an outer table and introduce duplicates.
1376:                 * The reason that duplicates can be introduced is that we do special processing
1377:                 * in the join to make sure only one qualified row from the right side is
1378:                 * returned.  If the exists table is on the left, we can return all the
1379:                 * qualified rows. 
1380:                 */
1381:                if (dependencyMap.getFirstSetBit() == -1) {
1382:                    int outerSize = outerFromList.size();
1383:                    for (int outer = 0; outer < outerSize; outer++)
1384:                        dependencyMap.or(((FromTable) outerFromList
1385:                                .elementAt(outer)).getReferencedTableMap());
1386:                }
1387:
1388:                /* Do the marking */
1389:                for (int index = 0; index < size; index++) {
1390:                    FromTable fromTable = (FromTable) elementAt(index);
1391:                    if (fromTable instanceof  ProjectRestrictNode) {
1392:                        ProjectRestrictNode prn = (ProjectRestrictNode) fromTable;
1393:                        if (prn.getChildResult() instanceof  FromBaseTable) {
1394:                            FromBaseTable fbt = (FromBaseTable) prn
1395:                                    .getChildResult();
1396:                            fbt.setExistsBaseTable(true,
1397:                                    (JBitSet) dependencyMap.clone(),
1398:                                    isNotExists);
1399:                        }
1400:                    }
1401:                }
1402:            }
1403:
1404:            /**
1405:             * Get the lock mode for the target of an update statement
1406:             * (a delete or update).  The update mode will always be row for
1407:             * CurrentOfNodes.  It will be table if there is no where clause.
1408:             *
1409:             * @return	The lock mode
1410:             */
1411:            public int updateTargetLockMode() {
1412:                if (SanityManager.DEBUG) {
1413:                    if (size() != 1) {
1414:                        SanityManager.THROWASSERT("size() expected to be 1");
1415:                    }
1416:                }
1417:                return ((ResultSetNode) elementAt(0)).updateTargetLockMode();
1418:            }
1419:
1420:            /**
1421:             * Return whether or not the user specified a hash join for any of the 
1422:             * tables in this list.
1423:             *
1424:             * @return	Whether or not the user specified a hash join for any of the 
1425:             *			tables in this list.
1426:             */
1427:            boolean hashJoinSpecified() {
1428:                int size = size();
1429:                for (int index = 0; index < size; index++) {
1430:                    FromTable ft = (FromTable) elementAt(index);
1431:                    String joinStrategy = ft.getUserSpecifiedJoinStrategy();
1432:
1433:                    if (joinStrategy != null
1434:                            && StringUtil.SQLToUpperCase(joinStrategy).equals(
1435:                                    "HASH")) {
1436:                        return true;
1437:                    }
1438:                }
1439:
1440:                return false;
1441:            }
1442:
1443:            /**
1444:             * Accept a visitor, and call v.visit()
1445:             * on child nodes as necessary.  
1446:             * 
1447:             * @param v the visitor
1448:             *
1449:             * @exception StandardException on error
1450:             */
1451:            public Visitable accept(Visitor v) throws StandardException {
1452:                int size = size();
1453:                for (int index = 0; index < size; index++) {
1454:                    FromTable fromTable = (FromTable) elementAt(index);
1455:                    setElementAt((QueryTreeNode) fromTable.accept(v), index);
1456:                }
1457:
1458:                return this;
1459:            }
1460:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.