Source Code Cross Referenced for SubqueryNode.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.SubqueryNode
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.context.ContextManager;
0025:
0026:        import org.apache.derby.iapi.error.StandardException;
0027:
0028:        import org.apache.derby.iapi.sql.compile.CompilerContext;
0029:        import org.apache.derby.iapi.sql.compile.CostEstimate;
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:        import org.apache.derby.iapi.reference.SQLState;
0036:        import org.apache.derby.iapi.reference.ClassName;
0037:
0038:        import org.apache.derby.iapi.types.DataTypeDescriptor;
0039:
0040:        import org.apache.derby.iapi.sql.execute.ExecRow;
0041:
0042:        import org.apache.derby.iapi.sql.Activation;
0043:        import org.apache.derby.iapi.types.DataValueDescriptor;
0044:        import org.apache.derby.iapi.sql.Row;
0045:        import org.apache.derby.iapi.types.DataTypeDescriptor;
0046:        import org.apache.derby.iapi.sql.ResultSet;
0047:        import org.apache.derby.iapi.types.TypeId;
0048:
0049:        import org.apache.derby.iapi.services.loader.GeneratedMethod;
0050:
0051:        import org.apache.derby.iapi.services.compiler.MethodBuilder;
0052:        import org.apache.derby.iapi.services.compiler.LocalField;
0053:
0054:        import org.apache.derby.iapi.services.sanity.SanityManager;
0055:
0056:        import org.apache.derby.iapi.store.access.Qualifier;
0057:
0058:        import java.lang.reflect.Modifier;
0059:
0060:        import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
0061:        import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
0062:        import org.apache.derby.impl.sql.execute.OnceResultSet;
0063:
0064:        import org.apache.derby.iapi.util.JBitSet;
0065:        import org.apache.derby.iapi.util.ReuseFactory;
0066:        import org.apache.derby.iapi.services.classfile.VMOpcode;
0067:
0068:        import java.util.Properties;
0069:        import java.util.Vector;
0070:
0071:        /**
0072:         * A SubqueryNode represents a subquery.  Subqueries return values to their
0073:         * outer queries. An quantified subquery is one that appears under a quantified
0074:         * operator (like IN or EXISTS) - quantified subqueries can return more than
0075:         * one value per invocation. An expression subquery is one that is not directly
0076:         * under a quantified operator - expression subqueries are allowed to return
0077:         * at most one value per invocation (returning no value is considered to be
0078:         * equivalent to returning NULL).
0079:         *
0080:         * There are a large number of subquery types.  Because of the large number of
0081:         * types, and the large amount of shared code, we have decided to have 1 SubqueryNode
0082:         * without any subclasses.  The subquery type (and operator) is encoded in the
0083:         * subqueryType field.
0084:         *
0085:         * The query optimizer is responsible for optimizing subqueries, and also for
0086:         * transforming them so that code can be generated for them. The optimizer may
0087:         * eliminate some subqueries by transforming them into joins, or it may
0088:         * change the internal form of a subquery (for example, transforming
0089:         * 'where x in (select y from z where ...)' into
0090:         * 'where (select true from z where x = y and ...)').
0091:         *
0092:         * Note that aggregates present some additional issues.  A transformation
0093:         * such as:
0094:         *	<UL> where x in (SELECT <I>expression</I> FROM z) </UL>
0095:         * has to be treated specially if <I>expression</I> has an aggregate.
0096:         * We change it to:
0097:         *	<UL> where x = (SELECT true FROM (SELECT MAX(x) FROM z) WHERE SQLCOL1 = y) </UL>
0098:         *
0099:         * @author Jeff Lichtman
0100:         */
0101:
0102:        public class SubqueryNode extends ValueNode {
0103:            /*
0104:             ** This must be a single-column result set.  If the subquery is
0105:             ** not quantified, it must also be a single-row result set - that is,
0106:             ** expression subqueries are allowed to return only a single value
0107:             ** per invocation.
0108:             ** NOTE: SubqueryNodes are used as an intermediate step within the parser
0109:             ** for building a derived table.  Derived tables can be multi-column and 
0110:             ** multi-table.
0111:             */
0112:            ResultSetNode resultSet;
0113:
0114:            /* Type of this subquery */
0115:            int subqueryType;
0116:
0117:            /* Whether or not this subquery is immediately under a top level AndNode.
0118:             * (Important for subquery flattening.)
0119:             */
0120:            boolean underTopAndNode;
0121:
0122:            /* Whether or not we've been preprocessed. (Only do the work once.) */
0123:            boolean preprocessed;
0124:
0125:            /* Whether or not this subquery began life as a distinct expression subquery */
0126:            boolean distinctExpression;
0127:
0128:            /* Since we do not have separate subquery operator nodes, the
0129:             * type of the subquery is stored in the subqueryType field.  Most subquery
0130:             * types take a left operand (except for expression and exists).  We could
0131:             * either add a leftOperand field here or subclass SubqueryNode for those
0132:             * types that take a left operand.  We have decided to add the left operand
0133:             * here for now.
0134:             */
0135:            ValueNode leftOperand;
0136:            boolean pushedNewPredicate;
0137:
0138:            /* Expression subqueries on the right side of a BinaryComparisonOperatorNode
0139:             * will get passed a pointer to that node prior to preprocess().  This
0140:             * allows us to replace the entire comparison, if we want to, when
0141:             * flattening.
0142:             */
0143:            BinaryComparisonOperatorNode parentComparisonOperator;
0144:
0145:            /* Private fields (all references via private methods) - 
0146:             * We reuse true BooleanConstantNodes within
0147:             * this class, creating them on the first reference.
0148:             */
0149:            private BooleanConstantNode trueNode;
0150:            /* Reuse generated code where possible */
0151:            //private Expression genResult;
0152:            /* Subquery # for this subquery */
0153:            private int subqueryNumber = -1;
0154:
0155:            /* ResultSet # for the point of attachment for this subquery */
0156:            private int pointOfAttachment = -1;
0157:
0158:            /* 
0159:             ** Indicate whether we found a correlation or not.
0160:             ** And track whether we have checked yet.
0161:             */
0162:            private boolean foundCorrelation;
0163:            private boolean doneCorrelationCheck;
0164:
0165:            /* 
0166:             ** Indicate whether we found an invariant node
0167:             ** below us or not. And track whether we have 
0168:             ** checked yet.
0169:             */
0170:            private boolean foundVariant;
0171:            private boolean doneInvariantCheck;
0172:
0173:            /* Subquery types.
0174:             * NOTE: FROM_SUBQUERY only exists for a brief second in the parser.  It
0175:             * should never appear in a query tree.
0176:             * NOTE: NOT EXISTS and NOT IN subquery types do not exist prior to NOT 
0177:             * elimination during preprocessing.  Prior to that, there is a separate
0178:             * NotNode above the SubqueryNode in the tree.
0179:             *
0180:             */
0181:            public final static int NOTIMPLEMENTED_SUBQUERY = -1;
0182:            public final static int FROM_SUBQUERY = 0;
0183:            public final static int IN_SUBQUERY = 1;
0184:            public final static int NOT_IN_SUBQUERY = 2;
0185:            public final static int EQ_ANY_SUBQUERY = 3;
0186:            public final static int EQ_ALL_SUBQUERY = 4;
0187:            public final static int NE_ANY_SUBQUERY = 5;
0188:            public final static int NE_ALL_SUBQUERY = 6;
0189:            public final static int GT_ANY_SUBQUERY = 7;
0190:            public final static int GT_ALL_SUBQUERY = 8;
0191:            public final static int GE_ANY_SUBQUERY = 9;
0192:            public final static int GE_ALL_SUBQUERY = 10;
0193:            public final static int LT_ANY_SUBQUERY = 11;
0194:            public final static int LT_ALL_SUBQUERY = 12;
0195:            public final static int LE_ANY_SUBQUERY = 13;
0196:            public final static int LE_ALL_SUBQUERY = 14;
0197:            public final static int EXISTS_SUBQUERY = 15;
0198:            public final static int NOT_EXISTS_SUBQUERY = 16;
0199:            public final static int EXPRESSION_SUBQUERY = 17;
0200:
0201:            /**
0202:             * Initializer.
0203:             *
0204:             * @param resultSet		The ResultSetNode for the subquery
0205:             * @param subqueryType	The type of the subquery
0206:             * @param leftOperand	The left operand, if any, of the subquery
0207:             */
0208:
0209:            public void init(Object resultSet, Object subqueryType,
0210:                    Object leftOperand) {
0211:                this .resultSet = (ResultSetNode) resultSet;
0212:                this .subqueryType = ((Integer) subqueryType).intValue();
0213:
0214:                /* Subqueries are presumed not to be under a top level AndNode by
0215:                 * default.  This is because expression normalization only recurses
0216:                 * under Ands and Ors, not under comparison operators, method calls,
0217:                 * built-in functions, etc.
0218:                 */
0219:                underTopAndNode = false;
0220:                this .leftOperand = (ValueNode) leftOperand;
0221:            }
0222:
0223:            /**
0224:             * Convert this object to a String.  See comments in QueryTreeNode.java
0225:             * for how this should be done for tree printing.
0226:             *
0227:             * @return	This object as a String
0228:             */
0229:
0230:            public String toString() {
0231:                if (SanityManager.DEBUG) {
0232:                    return "subqueryType: " + subqueryType + "\n"
0233:                            + "underTopAndNode: " + underTopAndNode + "\n"
0234:                            + "subqueryNumber: " + subqueryNumber + "\n"
0235:                            + "pointOfAttachment: " + pointOfAttachment + "\n"
0236:                            + "preprocessed: " + preprocessed + "\n"
0237:                            + "distinctExpression: " + distinctExpression
0238:                            + "\n" + super .toString();
0239:                } else {
0240:                    return "";
0241:                }
0242:            }
0243:
0244:            /**
0245:             * Prints the sub-nodes of this object.  See QueryTreeNode.java for
0246:             * how tree printing is supposed to work.
0247:             *
0248:             * @param depth		The depth of this node in the tree
0249:             */
0250:
0251:            public void printSubNodes(int depth) {
0252:                if (SanityManager.DEBUG) {
0253:                    super .printSubNodes(depth);
0254:
0255:                    if (resultSet != null) {
0256:                        printLabel(depth, "resultSet: ");
0257:                        resultSet.treePrint(depth + 1);
0258:                    }
0259:
0260:                    if (leftOperand != null) {
0261:                        printLabel(depth, "leftOperand: ");
0262:                        leftOperand.treePrint(depth + 1);
0263:                    }
0264:                }
0265:            }
0266:
0267:            /**
0268:             * Return the resultSet for this SubqueryNode.
0269:             *
0270:             * @return ResultSetNode underlying this SubqueryNode.
0271:             */
0272:            public ResultSetNode getResultSet() {
0273:                return resultSet;
0274:            }
0275:
0276:            /**
0277:             * Return the type of this subquery.
0278:             *
0279:             * @return int	Type of this subquery.
0280:             */
0281:            public int getSubqueryType() {
0282:                return subqueryType;
0283:            }
0284:
0285:            /**
0286:             * Set the type of this subquery.
0287:             *
0288:             * @param subqueryType of this subquery.
0289:             */
0290:            public void setSubqueryType(int subqueryType) {
0291:                this .subqueryType = subqueryType;
0292:            }
0293:
0294:            /**
0295:             * Set the point of attachment of this subquery.
0296:             *
0297:             * @param pointOfAttachment	The point of attachment of this subquery.
0298:             *
0299:             * @exception StandardException			Thrown on error
0300:             */
0301:            public void setPointOfAttachment(int pointOfAttachment)
0302:                    throws StandardException {
0303:                /* Materialized subqueries always keep their point of
0304:                 * attachment as -1.
0305:                 */
0306:                if (!isMaterializable()) {
0307:                    this .pointOfAttachment = pointOfAttachment;
0308:                }
0309:            }
0310:
0311:            /**
0312:             * Return whether or not this subquery is immediately under a top level
0313:             * AndNode.
0314:             *
0315:             * @return boolean	Whether or not this subquery is immediately under a
0316:             *					top level AndNode.
0317:             */
0318:            public boolean getUnderTopAndNode() {
0319:                return underTopAndNode;
0320:            }
0321:
0322:            /**
0323:             * Get the ResultSet # for the point of attachment for this SubqueryNode.
0324:             *
0325:             * @return int		The ResultSet # for the point of attachment
0326:             */
0327:            public int getPointOfAttachment() {
0328:                if (SanityManager.DEBUG) {
0329:                    SanityManager.ASSERT(pointOfAttachment >= 0,
0330:                            "pointOfAttachment expected to be >= 0");
0331:                }
0332:                return pointOfAttachment;
0333:            }
0334:
0335:            /**
0336:             * Get whether or not this SubqueryNode has already been
0337:             * preprocessed.
0338:             * 
0339:             * @return	Whether or not this SubqueryNode has already been
0340:             *			preprocessed.
0341:             */
0342:            boolean getPreprocessed() {
0343:                return preprocessed;
0344:            }
0345:
0346:            /**
0347:             * Set the parent BCON.  Useful when considering flattening
0348:             * expression subqueries.
0349:             *
0350:             * @param parent	The parent BCON.
0351:             */
0352:            void setParentComparisonOperator(BinaryComparisonOperatorNode parent) {
0353:                parentComparisonOperator = parent;
0354:            }
0355:
0356:            /**
0357:             * Remap all ColumnReferences in this tree to be clones of the
0358:             * underlying expression.
0359:             *
0360:             * @return ValueNode			The remapped expression tree.
0361:             *
0362:             * @exception StandardException			Thrown on error
0363:             */
0364:            public ValueNode remapColumnReferencesToExpressions()
0365:                    throws StandardException {
0366:                /* We need to remap both the SELECT and Predicate lists 
0367:                 * since there may be correlated columns in either of them.
0368:                 */
0369:                if (resultSet instanceof  SelectNode) {
0370:                    ResultColumnList selectRCL = resultSet.getResultColumns();
0371:                    SelectNode select = (SelectNode) resultSet;
0372:                    PredicateList selectPL = select.getWherePredicates();
0373:
0374:                    if (SanityManager.DEBUG) {
0375:                        SanityManager.ASSERT(selectPL != null,
0376:                                "selectPL expected to be non-null");
0377:                    }
0378:                    selectRCL.remapColumnReferencesToExpressions();
0379:                    selectPL.remapColumnReferencesToExpressions();
0380:                }
0381:                return this ;
0382:            }
0383:
0384:            /**
0385:             * Bind this expression.  This means binding the sub-expressions,
0386:             * as well as figuring out what the return type is for this expression.
0387:             *
0388:             * @param fromList			The FROM list for the query this
0389:             *							expression is in, for binding columns.
0390:             *							NOTE: fromList will be null if the subquery appears
0391:             *							in a VALUES clause.
0392:             * @param subqueryList		The subquery list being built as we find SubqueryNodes
0393:             * @param aggregateVector	The aggregate vector being built as we find AggregateNodes
0394:             *
0395:             * @return	The new top of the expression tree.
0396:             *
0397:             * @exception StandardException		Thrown on error
0398:             */
0399:            public ValueNode bindExpression(FromList fromList,
0400:                    SubqueryList subqueryList, Vector aggregateVector)
0401:                    throws StandardException {
0402:                ResultColumnList resultColumns;
0403:
0404:                //check if subquery is allowed in expression tree
0405:                checkReliability(CompilerContext.SUBQUERY_ILLEGAL,
0406:                        SQLState.LANG_SUBQUERY);
0407:
0408:                resultColumns = resultSet.getResultColumns();
0409:
0410:                /* The parser does not enforce the fact that a subquery can only return
0411:                 * a single column, so we must check here.
0412:                 */
0413:                if (resultColumns.size() != 1) {
0414:                    throw StandardException
0415:                            .newException(SQLState.LANG_NON_SINGLE_COLUMN_SUBQUERY);
0416:                }
0417:
0418:                /* Verify the usage of "*" in the select list:
0419:                 *	o  Only valid in EXISTS subqueries
0420:                 *	o  If the AllResultColumn is qualified, then we have to verify
0421:                 *	   that the qualification is a valid exposed name.
0422:                 *	   NOTE: The exposed name can come from an outer query block.
0423:                 */
0424:                resultSet.verifySelectStarSubquery(fromList, subqueryType);
0425:
0426:                /* For an EXISTS subquery:
0427:                 *	o  If the SELECT list is a "*", then we convert it to a true.
0428:                 *	   (We need to do the conversion since we don't want the "*" to
0429:                 *	   get expanded.)
0430:                 *  o  We then must bind the expression under the SELECT list to
0431:                 *	   verify that it is a valid expression.  (We must do this as a
0432:                 *	   separate step because we need to validate the expression and
0433:                 *	   we need to handle EXISTS (select * ... union all select 1 ...)
0434:                 *	   without getting a type compatability error.)
0435:                 *	o  Finally, we convert the expression to a SELECT true.
0436:                 */
0437:                if (subqueryType == EXISTS_SUBQUERY) {
0438:                    /* Transform the * into true (EXISTS). */
0439:                    resultSet.setResultToBooleanTrueNode(true);
0440:                }
0441:
0442:                /* We need to bind the tables before we can bind the target list
0443:                 * (for exists subqueries).  However, we need to wait until after
0444:                 * any *'s have been replaced, so that they don't get expanded.
0445:                 */
0446:                CompilerContext cc = getCompilerContext();
0447:
0448:                resultSet = resultSet.bindNonVTITables(getDataDictionary(),
0449:                        fromList);
0450:                resultSet = resultSet.bindVTITables(fromList);
0451:
0452:                /* Set the subquery # for this SubqueryNode */
0453:                if (subqueryNumber == -1)
0454:                    subqueryNumber = cc.getNextSubqueryNumber();
0455:
0456:                /* reject ? parameters in the select list of subqueries */
0457:                resultSet.rejectParameters();
0458:
0459:                if (subqueryType == EXISTS_SUBQUERY) {
0460:                    /* Bind the expression in the SELECT list */
0461:                    resultSet.bindTargetExpressions(fromList);
0462:
0463:                    /* Transform the ResultColumn into true.
0464:                     * NOTE: This may be a 2nd instance of the same transformation for
0465:                     * an EXISTS (select * ...), since we had to transform the 
0466:                     * AllResultColumn above, but we have to also handle
0467:                     * EXISTS (select r from s ...)
0468:                     */
0469:                    resultSet.setResultToBooleanTrueNode(false);
0470:                }
0471:
0472:                /* bind the left operand, if there is one */
0473:                if (leftOperand != null) {
0474:                    leftOperand = leftOperand.bindExpression(fromList,
0475:                            subqueryList, aggregateVector);
0476:                }
0477:
0478:                /* bind the expressions in the underlying subquery */
0479:                resultSet.bindExpressions(fromList);
0480:
0481:                resultSet.bindResultColumns(fromList);
0482:
0483:                /* We need to reset resultColumns since the underlying resultSet may
0484:                 * be a UNION (and UnionNode.bindResultColumns() regens a new RCL).
0485:                 */
0486:                resultColumns = resultSet.getResultColumns();
0487:
0488:                /*
0489:                 * A ? parameter to the left of this subquery gets type of the
0490:                 * subquery's sole column.
0491:                 */
0492:                if (leftOperand != null
0493:                        && leftOperand.requiresTypeFromContext()) {
0494:                    leftOperand.setType(((ResultColumn) resultColumns
0495:                            .elementAt(0)).getTypeServices());
0496:                }
0497:
0498:                // Set the DataTypeServices
0499:                setDataTypeServices(resultColumns);
0500:
0501:                /* Add this subquery to the subquery list */
0502:                subqueryList.addSubqueryNode(this );
0503:
0504:                return this ;
0505:            }
0506:
0507:            /**
0508:             * Preprocess an expression tree.  We do a number of transformations
0509:             * here (including subqueries, IN lists, LIKE and BETWEEN) plus
0510:             * subquery flattening.
0511:             * NOTE: This is done before the outer ResultSetNode is preprocessed.
0512:             *
0513:             * @param	numTables			Number of tables in the DML Statement
0514:             * @param	outerFromList		FromList from outer query block
0515:             * @param	outerSubqueryList	SubqueryList from outer query block
0516:             * @param	outerPredicateList	PredicateList from outer query block
0517:             *
0518:             * @return		The modified expression
0519:             *
0520:             * @exception StandardException		Thrown on error
0521:             */
0522:            public ValueNode preprocess(int numTables, FromList outerFromList,
0523:                    SubqueryList outerSubqueryList,
0524:                    PredicateList outerPredicateList) throws StandardException {
0525:                /* Only preprocess this node once.  We may get called multiple times
0526:                 * due to tree transformations.
0527:                 */
0528:                if (preprocessed) {
0529:                    return this ;
0530:                }
0531:                preprocessed = true;
0532:
0533:                boolean flattenable;
0534:                ValueNode topNode = this ;
0535:
0536:                resultSet = resultSet.preprocess(numTables, null,
0537:                        (FromList) null);
0538:
0539:                // Eliminate any unnecessary DISTINCTs
0540:                if (resultSet instanceof  SelectNode) {
0541:                    if (((SelectNode) resultSet).hasDistinct()) {
0542:                        ((SelectNode) resultSet).clearDistinct();
0543:                        /* We need to remember to check for single unique value
0544:                         * at execution time for expression subqueries.
0545:                         */
0546:                        if (subqueryType == EXPRESSION_SUBQUERY) {
0547:                            distinctExpression = true;
0548:                        }
0549:                    }
0550:                }
0551:
0552:                /* Lame transformation - For IN/ANY subqueries, if
0553:                 * result set is guaranteed to return at most 1 row
0554:                 * and it is not correlated
0555:                 * then convert the subquery into the matching expression
0556:                 * subquery type.  For example:
0557:                 *	c1 in (select min(c1) from t2)
0558:                 * becomes:
0559:                 *	c1 = (select min(c1) from t2)
0560:                 * (This actually showed up in an app that a potential customer
0561:                 * was porting from SQL Server.)
0562:                 * The transformed query can then be flattened if appropriate.
0563:                 */
0564:                if ((isIN() || isANY()) && resultSet.returnsAtMostOneRow()) {
0565:                    if (!hasCorrelatedCRs()) {
0566:                        changeToCorrespondingExpressionType();
0567:                    }
0568:                }
0569:
0570:                /* NOTE: Flattening occurs before the pushing of
0571:                 * the predicate, since the pushing will add a node 
0572:                 * above the SubqueryNode.
0573:                 */
0574:
0575:                /* Values subquery is flattenable if:
0576:                 *  o It is not under an OR.
0577:                 *  o It is an expression subquery on the right side
0578:                 *	  of a BinaryComparisonOperatorNode.
0579:                 */
0580:                flattenable = (resultSet instanceof  RowResultSetNode)
0581:                        && underTopAndNode
0582:                        && parentComparisonOperator instanceof  BinaryComparisonOperatorNode;
0583:                if (flattenable) {
0584:                    /* If we got this far and we are an expression subquery
0585:                     * then we want to set leftOperand to be the left side
0586:                     * of the comparison in case we pull the comparison into
0587:                     * the flattened subquery.
0588:                     */
0589:                    leftOperand = parentComparisonOperator.getLeftOperand();
0590:                    // Flatten the subquery
0591:                    RowResultSetNode rrsn = (RowResultSetNode) resultSet;
0592:                    FromList fl = new FromList();
0593:
0594:                    // Remove ourselves from the outer subquery list
0595:                    outerSubqueryList.removeElement(this );
0596:
0597:                    /* We only need to add the table from the subquery into 
0598:                     * the outer from list if the subquery itself contains
0599:                     * another subquery.  Otherwise, it just becomes a constant.
0600:                     */
0601:                    if (rrsn.subquerys.size() != 0) {
0602:                        fl.addElement(rrsn);
0603:                        outerFromList.destructiveAppend(fl);
0604:                    }
0605:
0606:                    /* Append the subquery's subquery list to the 
0607:                     * outer subquery list.
0608:                     */
0609:                    outerSubqueryList.destructiveAppend(rrsn.subquerys);
0610:
0611:                    /* return the new join condition 
0612:                     * If we are flattening an EXISTS then there is no new join
0613:                     * condition since there is no leftOperand.  Simply return
0614:                     * TRUE.
0615:                     *
0616:                     * NOTE: The outer where clause, etc. has already been normalized,
0617:                     * so we simply return the BinaryComparisonOperatorNode above
0618:                     * the new join condition.
0619:                     */
0620:                    ValueNode rightOperand;
0621:                    rightOperand = ((ResultColumn) rrsn.getResultColumns()
0622:                            .elementAt(0)).getExpression();
0623:                    return getNewJoinCondition(leftOperand, rightOperand);
0624:                }
0625:
0626:                /* Select subquery is flattenable if:
0627:                 *  o It is not under an OR.
0628:                 *  o The subquery type is IN, ANY or EXISTS or
0629:                 *    an expression subquery on the right side
0630:                 *	  of a BinaryComparisonOperatorNode.
0631:                 *  o There are no aggregates in the select list
0632:                 *  o There is no group by clause
0633:                 *  o There is a uniqueness condition that ensures
0634:                 *	  that the flattening of the subquery will not
0635:                 *	  introduce duplicates into the result set.
0636:                 *
0637:                 *	OR,
0638:                 *  o The subquery is NOT EXISTS, NOT IN, ALL (beetle 5173).
0639:                 */
0640:                boolean flattenableNotExists = (isNOT_EXISTS() || canAllBeFlattened());
0641:
0642:                flattenable = (resultSet instanceof  SelectNode)
0643:                        && underTopAndNode
0644:                        && (isIN() || isANY() || isEXISTS()
0645:                                || flattenableNotExists || parentComparisonOperator != null);
0646:
0647:                if (flattenable) {
0648:                    SelectNode select = (SelectNode) resultSet;
0649:                    if ((select.getAggregateVector(IN_SELECT_LIST).size() == 0)
0650:                            && (!select.getGeneratedForGroupbyClause())) {
0651:                        ValueNode origLeftOperand = leftOperand;
0652:
0653:                        /* Check for uniqueness condition. */
0654:                        /* Is the column being returned by the subquery
0655:                         * a candidate for an = condition?
0656:                         */
0657:                        boolean additionalEQ = (subqueryType == IN_SUBQUERY)
0658:                                || (subqueryType == EQ_ANY_SUBQUERY);
0659:
0660:                        additionalEQ = additionalEQ
0661:                                && ((leftOperand instanceof  ConstantNode)
0662:                                        || (leftOperand instanceof  ColumnReference) || (leftOperand
0663:                                        .requiresTypeFromContext()));
0664:                        /* If we got this far and we are an expression subquery
0665:                         * then we want to set leftOperand to be the left side
0666:                         * of the comparison in case we pull the comparison into
0667:                         * the flattened subquery.
0668:                         */
0669:                        if (parentComparisonOperator instanceof  BinaryComparisonOperatorNode) {
0670:                            leftOperand = parentComparisonOperator
0671:                                    .getLeftOperand();
0672:                        }
0673:                        /* Never flatten to normal join for NOT EXISTS.
0674:                         */
0675:                        if ((!flattenableNotExists)
0676:                                && select.uniqueSubquery(additionalEQ)) {
0677:                            // Flatten the subquery
0678:                            return flattenToNormalJoin(numTables,
0679:                                    outerFromList, outerSubqueryList,
0680:                                    outerPredicateList);
0681:                        }
0682:                        /* We can flatten into an EXISTS join if all of the above
0683:                         * conditions except for a uniqueness condition are true
0684:                         * and:
0685:                         *	o Subquery only has a single entry in its from list
0686:                         *	  and that entry is a FromBaseTable
0687:                         *	o All predicates in the subquery's where clause are
0688:                         *	  pushable.
0689:                         *  o The leftOperand, if non-null, is pushable.
0690:                         * If the subquery meets these conditions then we will flatten
0691:                         * the FBT into an EXISTS FBT, pushd the subquery's
0692:                         * predicates down to the PRN above the EBT and
0693:                         * mark the predicates to say that they cannot be pulled 
0694:                         * above the PRN. (The only way that we can guarantee correctness
0695:                         * is if the predicates do not get pulled up.  If they get pulled
0696:                         * up then the single next logic for an EXISTS join does not work
0697:                         * because that row may get disqualified at a higher level.)
0698:                         */
0699:                        else if ((isIN() || isANY() || isEXISTS() || flattenableNotExists)
0700:                                && ((leftOperand == null) ? true : leftOperand
0701:                                        .categorize(new JBitSet(numTables),
0702:                                                false))
0703:                                && select.getWherePredicates().allPushable()
0704:                                && singleFromBaseTable(select.getFromList())) {
0705:                            return flattenToExistsJoin(numTables,
0706:                                    outerFromList, outerSubqueryList,
0707:                                    outerPredicateList, flattenableNotExists);
0708:                        }
0709:
0710:                        // restore leftOperand to its original value
0711:                        leftOperand = origLeftOperand;
0712:                    }
0713:                }
0714:
0715:                /* We transform the leftOperand and the select list for quantified 
0716:                 * predicates that have a leftOperand into a new predicate and push it
0717:                 * down to the subquery after we preprocess the subquery's resultSet.
0718:                 * We must do this after preprocessing the underlying subquery so that
0719:                 * we know where to attach the new predicate.
0720:                 * NOTE - If we pushed the predicate before preprocessing the underlying
0721:                 * subquery, then the point of attachment would depend on the form of
0722:                 * that subquery.  (Where clause?  Having clause?)
0723:                 */
0724:                if (leftOperand != null) {
0725:                    topNode = pushNewPredicate(numTables);
0726:                    pushedNewPredicate = true;
0727:                }
0728:                /* Since NOT EXISTS subquery is not flattened, now is good time to create
0729:                 * an IS NULL node on top.  Other cases are taken care of in pushNewPredicate.
0730:                 */
0731:                else if (subqueryType == NOT_EXISTS_SUBQUERY) {
0732:                    topNode = genIsNullTree();
0733:                    subqueryType = EXISTS_SUBQUERY;
0734:                }
0735:
0736:                /*
0737:                 ** Do inVariant and correlated checks now.  We
0738:                 ** aren't going to use the results here, but they
0739:                 ** have been stashed away by isInvariant() and hasCorrelatedCRs()
0740:                 */
0741:                isInvariant();
0742:                hasCorrelatedCRs();
0743:
0744:                /* If parentComparisonOperator is non-null then we are an
0745:                 * expression subquery that was considered to be a candidate 
0746:                 * for flattening, but we didn't get flattened.  In that case
0747:                 * we are the rightOperand of the parent.  We need to update
0748:                 * the parent's rightOperand with the new topNode and return
0749:                 * the parent because the parent is letting us decide whether
0750:                 * or not to replace the entire comparison, which we can do
0751:                 * if we flatten.  Otherwise we simply return the new top node.
0752:                 */
0753:                if (parentComparisonOperator != null) {
0754:                    parentComparisonOperator.setRightOperand(topNode);
0755:                    return parentComparisonOperator;
0756:                }
0757:
0758:                return topNode;
0759:            }
0760:
0761:            /**
0762:             * Does the from list from the subquery contain a
0763:             * single entry which is a FBT or a PRN/FBT.
0764:             *
0765:             * @param fromList	The from list from the subquery
0766:             *
0767:             * @return Whether or not the from list from the subquery contains a
0768:             *			single entry which is a FBT or a PRN/FBT.
0769:             */
0770:            private boolean singleFromBaseTable(FromList fromList) {
0771:                boolean retCode = (fromList.size() == 1);
0772:
0773:                if (retCode) {
0774:                    FromTable ft = (FromTable) fromList.elementAt(0);
0775:
0776:                    if (((ft instanceof  ProjectRestrictNode) && ((ProjectRestrictNode) ft)
0777:                            .getChildResult() instanceof  FromBaseTable)
0778:                            || ft instanceof  FromBaseTable) {
0779:                    } else {
0780:                        retCode = false;
0781:                    }
0782:                }
0783:
0784:                return retCode;
0785:            }
0786:
0787:            /**
0788:             * Can NOT IN, ALL be falttened to NOT EXISTS join?  We can't or the flattening doesn't
0789:             * easily make sense if either side of the comparison is nullable. (beetle 5173)
0790:             *
0791:             * @return Whether or not the NOT IN or ALL subquery can be flattened.
0792:             */
0793:            private boolean canAllBeFlattened() throws StandardException {
0794:                boolean result = false;
0795:                if (isNOT_IN() || isALL()) {
0796:                    ValueNode rightOperand = ((ResultColumn) resultSet
0797:                            .getResultColumns().elementAt(0)).getExpression();
0798:                    result = (!leftOperand.getTypeServices().isNullable() && !rightOperand
0799:                            .getTypeServices().isNullable());
0800:                }
0801:                return result;
0802:            }
0803:
0804:            /**
0805:             * Flatten this subquery into the outer query block.  
0806:             * At this point we are only flattening based on a uniqueness
0807:             * condition and only flattening non-aggregate subqueries.
0808:             * So, we promote the subquery's from list, as is, into 
0809:             * the outer from list.  For EXISTS subquerys, we return a 
0810:             * TRUE.  Otherwise we return a new comparison between
0811:             * the leftOperand and the expression in the subquery's
0812:             * SELECT list.
0813:             * RESOLVE - we will need to modify this logic to account
0814:             * for exists joins and aggregates as we support flattening
0815:             * for them.
0816:             *
0817:             * Anyway, here's what we do:
0818:             *	o We remove ourself from the outer subquery list.
0819:             *	o We decrement the nesting level for all tables
0820:             *	  in the subquery tree.
0821:             *	o We append the subquery's from list to the outer
0822:             *	  from list.
0823:             *	o We add the subquery's predicate list to the outer
0824:             *	  predicate list.  (The subquery has already been
0825:             *	  preprocessed.)
0826:             *  o We add the subquery's subquery list to the outer
0827:             *	  subquery list.
0828:             *	o For EXISTS, we return a true.
0829:             *	o Otherwise, we return a new comparison between the
0830:             *	  leftOperand and the expression in the inner select's
0831:             *	  RCL.
0832:             *
0833:             * @param	numTables			Number of tables in the DML Statement
0834:             * @param	outerFromList		FromList from outer query block
0835:             * @param	outerSubqueryList	SubqueryList from outer query block
0836:             * @param	outerPredicateList	PredicateList from outer query block
0837:             *
0838:             * @return	The modified expression
0839:             *
0840:             * @exception StandardException		Thrown on error
0841:             */
0842:            private ValueNode flattenToNormalJoin(int numTables,
0843:                    FromList outerFromList, SubqueryList outerSubqueryList,
0844:                    PredicateList outerPredicateList) throws StandardException {
0845:                SelectNode select = (SelectNode) resultSet;
0846:                FromList fl = select.getFromList();
0847:                int[] tableNumbers = fl.getTableNumbers();
0848:
0849:                // Remove ourselves from the outer subquery list
0850:                outerSubqueryList.removeElement(this );
0851:
0852:                /* Decrease the nesting level for all
0853:                 * tables in the subquey tree.
0854:                 */
0855:                select.decrementLevel(1);
0856:
0857:                /* Add the table(s) from the subquery into the outer from list */
0858:                outerFromList.destructiveAppend(fl);
0859:
0860:                /* Append the subquery's predicate list to the
0861:                 * outer predicate list.
0862:                 */
0863:                outerPredicateList.destructiveAppend(select
0864:                        .getWherePredicates());
0865:
0866:                /* Append the subquery's subquery list to the 
0867:                 * outer subquery list.
0868:                 * NOTE: We must propagate any subqueries from both the
0869:                 * SELECT list and WHERE clause of the subquery that's
0870:                 * getting flattened.
0871:                 */
0872:                outerSubqueryList.destructiveAppend(select.getWhereSubquerys());
0873:                outerSubqueryList
0874:                        .destructiveAppend(select.getSelectSubquerys());
0875:
0876:                /* return the new join condition 
0877:                 * If we are flattening an EXISTS then there is no new join
0878:                 * condition since there is no leftOperand.  Simply return
0879:                 * TRUE.
0880:                 *
0881:                 * NOTE: The outer where clause, etc. has already been normalized,
0882:                 * so we simply return the BinaryComparisonOperatorNode above
0883:                 * the new join condition.
0884:                 */
0885:                if (leftOperand == null) {
0886:                    return (ValueNode) getNodeFactory().getNode(
0887:                            C_NodeTypes.BOOLEAN_CONSTANT_NODE, Boolean.TRUE,
0888:                            getContextManager());
0889:                } else {
0890:                    ValueNode rightOperand;
0891:                    rightOperand = ((ResultColumn) select.getResultColumns()
0892:                            .elementAt(0)).getExpression();
0893:                    /* If the right operand is a CR, then we need to decrement
0894:                     * its source level as part of flattening so that
0895:                     * transitive closure will work correctly.
0896:                     */
0897:                    if (rightOperand instanceof  ColumnReference) {
0898:                        ColumnReference cr = (ColumnReference) rightOperand;
0899:                        int tableNumber = cr.getTableNumber();
0900:                        for (int index = 0; index < tableNumbers.length; index++) {
0901:                            if (tableNumber == tableNumbers[index]) {
0902:                                cr.setSourceLevel(cr.getSourceLevel() - 1);
0903:                                break;
0904:                            }
0905:                        }
0906:                    }
0907:                    return getNewJoinCondition(leftOperand, rightOperand);
0908:                }
0909:            }
0910:
0911:            /**
0912:             * Flatten this subquery into the outer query block
0913:             * as an exists join.  
0914:             * At this point we are only flattening non-aggregate subqueries
0915:             * with a single FBT in the from list.
0916:             * So, we transform all FBTs in the from list into ExistBaseTables,
0917:             * update the dependency lists for each of the tables and then
0918:             * flatten the subquery.
0919:             * RESOLVE - we will need to modify this logic to account
0920:             * for aggregates as we support flattening
0921:             * for them.
0922:             *
0923:             * @param	numTables			Number of tables in the DML Statement
0924:             * @param	outerFromList		FromList from outer query block
0925:             * @param	outerSubqueryList	SubqueryList from outer query block
0926:             * @param	outerPredicateList	PredicateList from outer query block
0927:             * @param	flattenableNotExists Is it a flattening into a NOT EXISTS join
0928:             *
0929:             * @return	The modified expression
0930:             *
0931:             * @exception StandardException		Thrown on error
0932:             */
0933:            private ValueNode flattenToExistsJoin(int numTables,
0934:                    FromList outerFromList, SubqueryList outerSubqueryList,
0935:                    PredicateList outerPredicateList,
0936:                    boolean flattenableNotExists) throws StandardException {
0937:                SelectNode select = (SelectNode) resultSet;
0938:
0939:                // Replace the FromBaseTables in the from list with ExistBaseTables
0940:                select.getFromList().genExistsBaseTables(
0941:                        resultSet.getReferencedTableMap(), outerFromList,
0942:                        flattenableNotExists);
0943:
0944:                /* NOTE: Because we are currently only flattening single table subqueries
0945:                 * whose predicates are all pushable, we simply follow the rest of the
0946:                 * flattening algorithm for unique subqueries.  Should we decide to 
0947:                 * loosen these restrictions then we need to do more work such as:
0948:                 *
0949:                 * Mark all of the predicates from the subquery as non-pullable. They must
0950:                 * not be pulled so that we can guarantee correctness.  Otherwise, we could
0951:                 * add or subtract rows from the result set.
0952:                 *
0953:                 * Remap all of the non-correlated CRs in the predicate list so that they
0954:                 * point to the correct source.  (We've chopped a level out of the RCL/VCN
0955:                 * chain.)  We then transfer those predicates to the PRN in the subquery's
0956:                 * from list.
0957:                 */
0958:
0959:                return flattenToNormalJoin(numTables, outerFromList,
0960:                        outerSubqueryList, outerPredicateList);
0961:            }
0962:
0963:            /**
0964:             * Check to see if we have a Variant value below us.
0965:             * If so, return true.  Caches the result so multiple
0966:             * calls are ok.
0967:             *  
0968:             * @return boolean whether we have 
0969:             *
0970:             * @exception StandardException		Thrown on error
0971:             */
0972:            private boolean isInvariant() throws StandardException {
0973:                if (doneInvariantCheck) {
0974:                    return !foundVariant;
0975:                }
0976:
0977:                doneInvariantCheck = true;
0978:                HasVariantValueNodeVisitor visitor = new HasVariantValueNodeVisitor();
0979:                resultSet.accept(visitor);
0980:                foundVariant = visitor.hasVariant();
0981:                return !foundVariant;
0982:            }
0983:
0984:            /**
0985:             * Check to see if this subquery has correlated
0986:             * column references.  Only useful results if
0987:             * called AFTER binding (after CRs have been bound).
0988:             *
0989:             * @return whether the subquery has correlated column
0990:             *	references.
0991:             * @exception StandardException		Thrown on error
0992:             */
0993:            public boolean hasCorrelatedCRs() throws StandardException {
0994:                if (doneCorrelationCheck) {
0995:                    return foundCorrelation;
0996:                }
0997:                doneCorrelationCheck = true;
0998:
0999:                ResultSetNode realSubquery = resultSet;
1000:                ResultColumnList oldRCL = null;
1001:
1002:                /* If we have pushed the new join predicate on top, we want to disregard it
1003:                 * to see if anything under the predicate is correlated.  If nothing correlated
1004:                 * under the new join predicate, we could then materialize the subquery.
1005:                 * See beetle 4373.
1006:                 */
1007:                if (pushedNewPredicate) {
1008:                    if (SanityManager.DEBUG) {
1009:                        SanityManager
1010:                                .ASSERT(
1011:                                        resultSet instanceof  ProjectRestrictNode,
1012:                                        "resultSet expected to be a ProjectRestrictNode!");
1013:                    }
1014:
1015:                    realSubquery = ((ProjectRestrictNode) resultSet)
1016:                            .getChildResult();
1017:                    oldRCL = realSubquery.getResultColumns();
1018:
1019:                    /* Only first column matters.
1020:                     */
1021:                    if (oldRCL.size() > 1) {
1022:                        ResultColumnList newRCL = new ResultColumnList();
1023:                        newRCL.addResultColumn(oldRCL.getResultColumn(1));
1024:                        realSubquery.setResultColumns(newRCL);
1025:                    }
1026:                }
1027:
1028:                HasCorrelatedCRsVisitor visitor = new HasCorrelatedCRsVisitor();
1029:                realSubquery.accept(visitor);
1030:                foundCorrelation = visitor.hasCorrelatedCRs();
1031:
1032:                if (pushedNewPredicate && (oldRCL.size() > 1)) {
1033:                    realSubquery.setResultColumns(oldRCL);
1034:                }
1035:
1036:                return foundCorrelation;
1037:            }
1038:
1039:            /**
1040:             * Transform:
1041:             *		expresion QuantifiedOperator (select x from ...)
1042:             * into
1043:             *		(select true from .. where expression <BinaryComparisonOperator> x ...)
1044:             *		IS [NOT] NULL
1045:             *
1046:             * or, if we have an aggregate:
1047:             *		(select true from 
1048:             *			(select AGG(x) from ...)
1049:             *		where expression <BinaryComparisonOperator> x ...)
1050:             *		IS [NOT] NULL
1051:             *
1052:             *
1053:             * For ANY and IN subqueries:
1054:             *		o  We generate an IS NULL above the SubqueryNode and return the top of
1055:             *		   the new tree to the caller.
1056:             *		o  The operator in the new predicate that is added to the subquery
1057:             *		   will correspond to the operator that modifies the ANY.
1058:             *		   (eg, = for = ANY, with = for IN.)
1059:             * For ALL and NOT IN subqueries:
1060:             *		o  We generate an IS NOT NULL above the SubqueryNode and return the top of
1061:             *		   the new tree to the caller.
1062:             *		o  The operator in the new predicate that is added to the subquery
1063:             *		   will be a BinaryAllOperatorNode whose bcoNodeType corresponds to 
1064:             *		   the negation of the operator that modifies the ALL.
1065:             *		   (eg, <> for = ALL, with <> for NOT IN.)
1066:             *
1067:             * NOTE: This method is called after the underlying subquery has been
1068:             * preprocessed, so we build a new Predicate, not just a new expression.
1069:             *
1070:             * @param numTables			Number of tables in DML Statement
1071:             *
1072:             * @return UnaryComparisonOperatorNode	An IS [NOT] NULL above the 
1073:             *										transformed subquery.
1074:             *
1075:             * @exception StandardException		Thrown on error
1076:             */
1077:            private UnaryComparisonOperatorNode pushNewPredicate(int numTables)
1078:                    throws StandardException {
1079:                AndNode andNode;
1080:                BinaryComparisonOperatorNode bcoNode = null;
1081:                JBitSet tableMap;
1082:                Predicate predicate;
1083:                ResultColumn firstRC;
1084:                ResultColumnList resultColumns;
1085:                UnaryComparisonOperatorNode ucoNode = null;
1086:                ValueNode oldWhereClause;
1087:                ValueNode rightOperand;
1088:
1089:                /* We have to ensure that the resultSet immediately under us has
1090:                 * a PredicateList, otherwise we can't push the predicate down.
1091:                 */
1092:                resultSet = resultSet.ensurePredicateList(numTables);
1093:
1094:                /* RESOLVE - once we understand how correlated columns will work, 
1095:                 * we probably want to mark leftOperand as a correlated column
1096:                 */
1097:                resultColumns = resultSet.getResultColumns();
1098:
1099:                /*
1100:                 ** Create a new PR node.  Put it over the original subquery.  resulSet
1101:                 ** is now the new PR.  We give the chance that things under the PR node
1102:                 ** can be materialized.  See beetle 4373.
1103:                 */
1104:                ResultColumnList newRCL = resultColumns.copyListAndObjects();
1105:                newRCL.genVirtualColumnNodes(resultSet, resultColumns);
1106:                resultSet = (ResultSetNode) getNodeFactory().getNode(
1107:                        C_NodeTypes.PROJECT_RESTRICT_NODE, resultSet, // child
1108:                        newRCL, // result columns
1109:                        null, // restriction
1110:                        null, // restriction list
1111:                        null, // project subqueries
1112:                        null, // restrict subqueries	
1113:                        null, getContextManager());
1114:                resultColumns = newRCL;
1115:
1116:                firstRC = (ResultColumn) resultColumns.elementAt(0);
1117:                rightOperand = firstRC.getExpression();
1118:
1119:                bcoNode = getNewJoinCondition(leftOperand, rightOperand);
1120:
1121:                ValueNode andLeft = bcoNode;
1122:
1123:                /* For NOT IN or ALL, and if either side of the comparison is nullable, and the
1124:                 * subquery can not be flattened (because of that), we need to add IS NULL node
1125:                 * on top of the nullables, such that the behavior is (beetle 5173):
1126:                 *
1127:                 *    (1) If we have nulls in right operand, no row is returned.
1128:                 *    (2) If subquery result is empty before applying join predicate, every
1129:                 *		  left row (including NULLs) is returned.
1130:                 *	  (3) Otherwise, return {all left row} - {NULLs}
1131:                 */
1132:                if (isNOT_IN() || isALL()) {
1133:                    boolean leftNullable = leftOperand.getTypeServices()
1134:                            .isNullable();
1135:                    boolean rightNullable = rightOperand.getTypeServices()
1136:                            .isNullable();
1137:                    if (leftNullable || rightNullable) {
1138:                        /* Create a normalized structure.
1139:                         */
1140:                        BooleanConstantNode falseNode = (BooleanConstantNode) getNodeFactory()
1141:                                .getNode(C_NodeTypes.BOOLEAN_CONSTANT_NODE,
1142:                                        Boolean.FALSE, getContextManager());
1143:                        OrNode newOr = (OrNode) getNodeFactory().getNode(
1144:                                C_NodeTypes.OR_NODE, bcoNode, falseNode,
1145:                                getContextManager());
1146:                        newOr.postBindFixup();
1147:                        andLeft = newOr;
1148:
1149:                        if (leftNullable) {
1150:                            UnaryComparisonOperatorNode leftIsNull = (UnaryComparisonOperatorNode) getNodeFactory()
1151:                                    .getNode(C_NodeTypes.IS_NULL_NODE,
1152:                                            leftOperand, getContextManager());
1153:                            leftIsNull.bindComparisonOperator();
1154:                            newOr = (OrNode) getNodeFactory().getNode(
1155:                                    C_NodeTypes.OR_NODE, leftIsNull, andLeft,
1156:                                    getContextManager());
1157:                            newOr.postBindFixup();
1158:                            andLeft = newOr;
1159:                        }
1160:                        if (rightNullable) {
1161:                            UnaryComparisonOperatorNode rightIsNull = (UnaryComparisonOperatorNode) getNodeFactory()
1162:                                    .getNode(C_NodeTypes.IS_NULL_NODE,
1163:                                            rightOperand, getContextManager());
1164:                            rightIsNull.bindComparisonOperator();
1165:                            newOr = (OrNode) getNodeFactory().getNode(
1166:                                    C_NodeTypes.OR_NODE, rightIsNull, andLeft,
1167:                                    getContextManager());
1168:                            newOr.postBindFixup();
1169:                            andLeft = newOr;
1170:                        }
1171:                    }
1172:                }
1173:
1174:                /* Place an AndNode above the <BinaryComparisonOperator> */
1175:                andNode = (AndNode) getNodeFactory().getNode(
1176:                        C_NodeTypes.AND_NODE, andLeft, getTrueNode(),
1177:                        getContextManager());
1178:
1179:                /* Build the referenced table map for the new predicate */
1180:                tableMap = new JBitSet(numTables);
1181:                andNode.postBindFixup();
1182:
1183:                /* Put the AndNode under a Predicate */
1184:                predicate = (Predicate) getNodeFactory().getNode(
1185:                        C_NodeTypes.PREDICATE, andNode, tableMap,
1186:                        getContextManager());
1187:                predicate.categorize();
1188:
1189:                /* Push the new Predicate to the subquery's list */
1190:                resultSet = resultSet.addNewPredicate(predicate);
1191:
1192:                /* Clean up the leftOperand and subquery ResultColumn */
1193:                leftOperand = null;
1194:                firstRC.setType(getTypeServices());
1195:                firstRC.setExpression(getTrueNode());
1196:
1197:                /* Add the IS [NOT] NULL above the SubqueryNode */
1198:                switch (subqueryType) {
1199:                case IN_SUBQUERY:
1200:                case EQ_ANY_SUBQUERY:
1201:                case NE_ANY_SUBQUERY:
1202:                case LE_ANY_SUBQUERY:
1203:                case LT_ANY_SUBQUERY:
1204:                case GE_ANY_SUBQUERY:
1205:                case GT_ANY_SUBQUERY:
1206:                    ucoNode = (UnaryComparisonOperatorNode) getNodeFactory()
1207:                            .getNode(C_NodeTypes.IS_NOT_NULL_NODE, this ,
1208:                                    getContextManager());
1209:                    break;
1210:
1211:                case NOT_IN_SUBQUERY:
1212:                case EQ_ALL_SUBQUERY:
1213:                case NE_ALL_SUBQUERY:
1214:                case LE_ALL_SUBQUERY:
1215:                case LT_ALL_SUBQUERY:
1216:                case GE_ALL_SUBQUERY:
1217:                case GT_ALL_SUBQUERY:
1218:                    ucoNode = (UnaryComparisonOperatorNode) getNodeFactory()
1219:                            .getNode(C_NodeTypes.IS_NULL_NODE, this ,
1220:                                    getContextManager());
1221:                    break;
1222:                }
1223:                ucoNode.bindComparisonOperator();
1224:                return ucoNode;
1225:            }
1226:
1227:            /**
1228:             * Build a new join condition between the leftOperand
1229:             * and the rightOperand.  The comparison operator
1230:             * is dependent on the subquery type.
1231:             *
1232:             * @param leftOperand	The left operand for the new condition.
1233:             * @param rightOperand	The right operand for the new condition.
1234:             *
1235:             * @exception StandardException		Thrown on error
1236:             */
1237:            private BinaryComparisonOperatorNode getNewJoinCondition(
1238:                    ValueNode leftOperand, ValueNode rightOperand)
1239:                    throws StandardException {
1240:                BinaryComparisonOperatorNode bcoNode = null;
1241:
1242:                /* NOTE: If we are an expression subquery that's getting
1243:                 * flattened then our subqueryType is EXPRESSION_SUBQUERY.
1244:                 * However, we can get the comparison type from the 
1245:                 * parentComparisonOperator.  In that case we dovetail on
1246:                 * the ANY subquery types.
1247:                 */
1248:                int operatorType = subqueryType;
1249:                if (subqueryType == EXPRESSION_SUBQUERY) {
1250:                    if (SanityManager.DEBUG) {
1251:                        SanityManager
1252:                                .ASSERT(parentComparisonOperator != null,
1253:                                        "parentComparisonOperator expected to be non-null");
1254:                    }
1255:
1256:                    int parentOperator = -1;
1257:
1258:                    if (parentComparisonOperator.isRelationalOperator()) {
1259:                        RelationalOperator ro = (RelationalOperator) parentComparisonOperator;
1260:                        parentOperator = ro.getOperator();
1261:                    }
1262:
1263:                    if (parentOperator == RelationalOperator.EQUALS_RELOP) {
1264:                        operatorType = EQ_ANY_SUBQUERY;
1265:                    } else if (parentOperator == RelationalOperator.NOT_EQUALS_RELOP) {
1266:                        operatorType = NE_ANY_SUBQUERY;
1267:                    } else if (parentOperator == RelationalOperator.LESS_EQUALS_RELOP) {
1268:                        operatorType = LE_ANY_SUBQUERY;
1269:                    } else if (parentOperator == RelationalOperator.LESS_THAN_RELOP) {
1270:                        operatorType = LT_ANY_SUBQUERY;
1271:                    } else if (parentOperator == RelationalOperator.GREATER_EQUALS_RELOP) {
1272:                        operatorType = GE_ANY_SUBQUERY;
1273:                    } else if (parentOperator == RelationalOperator.GREATER_THAN_RELOP) {
1274:                        operatorType = GT_ANY_SUBQUERY;
1275:                    }
1276:                }
1277:
1278:                int bcoType = 0;
1279:                int nodeType = 0;
1280:
1281:                /* Build the <BinaryComparisonOperator> */
1282:                switch (operatorType) {
1283:                case IN_SUBQUERY:
1284:                case EQ_ANY_SUBQUERY:
1285:                case NOT_IN_SUBQUERY:
1286:                case NE_ALL_SUBQUERY:
1287:                    nodeType = C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE;
1288:                    break;
1289:
1290:                case NE_ANY_SUBQUERY:
1291:                case EQ_ALL_SUBQUERY:
1292:                    nodeType = C_NodeTypes.BINARY_NOT_EQUALS_OPERATOR_NODE;
1293:                    break;
1294:
1295:                case LE_ANY_SUBQUERY:
1296:                case GT_ALL_SUBQUERY:
1297:                    nodeType = C_NodeTypes.BINARY_LESS_EQUALS_OPERATOR_NODE;
1298:                    break;
1299:
1300:                case LT_ANY_SUBQUERY:
1301:                case GE_ALL_SUBQUERY:
1302:                    nodeType = C_NodeTypes.BINARY_LESS_THAN_OPERATOR_NODE;
1303:                    break;
1304:
1305:                case GE_ANY_SUBQUERY:
1306:                case LT_ALL_SUBQUERY:
1307:                    nodeType = C_NodeTypes.BINARY_GREATER_EQUALS_OPERATOR_NODE;
1308:                    break;
1309:
1310:                case GT_ANY_SUBQUERY:
1311:                case LE_ALL_SUBQUERY:
1312:                    nodeType = C_NodeTypes.BINARY_GREATER_THAN_OPERATOR_NODE;
1313:                    break;
1314:
1315:                default:
1316:                    if (SanityManager.DEBUG)
1317:                        SanityManager.ASSERT(false, "subqueryType ("
1318:                                + subqueryType + ") is an unexpected type");
1319:                }
1320:
1321:                bcoNode = (BinaryComparisonOperatorNode) getNodeFactory()
1322:                        .getNode(nodeType, leftOperand, rightOperand,
1323:                                getContextManager());
1324:
1325:                bcoNode.bindComparisonOperator();
1326:                return bcoNode;
1327:            }
1328:
1329:            /**
1330:             * Eliminate NotNodes in the current query block.  We traverse the tree, 
1331:             * inverting ANDs and ORs and eliminating NOTs as we go.  We stop at 
1332:             * ComparisonOperators and boolean expressions.  We invert 
1333:             * ComparisonOperators and replace boolean expressions with 
1334:             * boolean expression = false.
1335:             * NOTE: Since we do not recurse under ComparisonOperators, there
1336:             * still could be NotNodes left in the tree.
1337:             *
1338:             * @param	underNotNode		Whether or not we are under a NotNode.
1339:             *							
1340:             *
1341:             * @return		The modified expression
1342:             *
1343:             * @exception StandardException		Thrown on error
1344:             */
1345:            ValueNode eliminateNots(boolean underNotNode)
1346:                    throws StandardException {
1347:                ValueNode result = this ;
1348:
1349:                if (underNotNode) {
1350:                    /* Negate the subqueryType. For expression subqueries
1351:                     * we simply return subquery = false
1352:                     */
1353:                    /* RESOLVE - This code needs to get cleaned up once there are
1354:                     * more subquery types.  (Consider using arrays.)
1355:                     */
1356:                    switch (subqueryType) {
1357:                    case EXPRESSION_SUBQUERY:
1358:                        result = genEqualsFalseTree();
1359:                        break;
1360:
1361:                    case EXISTS_SUBQUERY:
1362:                        subqueryType = NOT_EXISTS_SUBQUERY;
1363:                        break;
1364:
1365:                    /* ANY subqueries */
1366:                    case IN_SUBQUERY:
1367:                    case EQ_ANY_SUBQUERY:
1368:                        subqueryType = NOT_IN_SUBQUERY;
1369:                        break;
1370:
1371:                    case NE_ANY_SUBQUERY:
1372:                        subqueryType = EQ_ALL_SUBQUERY;
1373:                        break;
1374:
1375:                    case GE_ANY_SUBQUERY:
1376:                        subqueryType = LT_ALL_SUBQUERY;
1377:                        break;
1378:
1379:                    case GT_ANY_SUBQUERY:
1380:                        subqueryType = LE_ALL_SUBQUERY;
1381:                        break;
1382:
1383:                    case LE_ANY_SUBQUERY:
1384:                        subqueryType = GT_ALL_SUBQUERY;
1385:                        break;
1386:
1387:                    case LT_ANY_SUBQUERY:
1388:                        subqueryType = GE_ALL_SUBQUERY;
1389:                        break;
1390:
1391:                    /* ALL subqueries - no need for NOT NOT_IN_SUBQUERY, since
1392:                     * NOT IN only comes into existence here.
1393:                     */
1394:                    case EQ_ALL_SUBQUERY:
1395:                        subqueryType = NE_ANY_SUBQUERY;
1396:                        break;
1397:
1398:                    case NE_ALL_SUBQUERY:
1399:                        subqueryType = EQ_ANY_SUBQUERY;
1400:                        break;
1401:
1402:                    case GE_ALL_SUBQUERY:
1403:                        subqueryType = LT_ANY_SUBQUERY;
1404:                        break;
1405:
1406:                    case GT_ALL_SUBQUERY:
1407:                        subqueryType = LE_ANY_SUBQUERY;
1408:                        break;
1409:
1410:                    case LE_ALL_SUBQUERY:
1411:                        subqueryType = GT_ANY_SUBQUERY;
1412:                        break;
1413:
1414:                    case LT_ALL_SUBQUERY:
1415:                        subqueryType = GE_ANY_SUBQUERY;
1416:                        break;
1417:
1418:                    default:
1419:                        if (SanityManager.DEBUG)
1420:                            SanityManager
1421:                                    .ASSERT(false,
1422:                                            "NOT is not supported for this time of subquery");
1423:                    }
1424:                }
1425:
1426:                /* Halt recursion here, as each query block is preprocessed separately */
1427:                return result;
1428:            }
1429:
1430:            /**
1431:             * Finish putting an expression into conjunctive normal
1432:             * form.  An expression tree in conjunctive normal form meets
1433:             * the following criteria:
1434:             *		o  If the expression tree is not null,
1435:             *		   the top level will be a chain of AndNodes terminating
1436:             *		   in a true BooleanConstantNode.
1437:             *		o  The left child of an AndNode will never be an AndNode.
1438:             *		o  Any right-linked chain that includes an AndNode will
1439:             *		   be entirely composed of AndNodes terminated by a true BooleanConstantNode.
1440:             *		o  The left child of an OrNode will never be an OrNode.
1441:             *		o  Any right-linked chain that includes an OrNode will
1442:             *		   be entirely composed of OrNodes terminated by a false BooleanConstantNode.
1443:             *		o  ValueNodes other than AndNodes and OrNodes are considered
1444:             *		   leaf nodes for purposes of expression normalization.
1445:             *		   In other words, we won't do any normalization under
1446:             *		   those nodes.
1447:             *
1448:             * In addition, we track whether or not we are under a top level AndNode.  
1449:             * SubqueryNodes need to know this for subquery flattening.
1450:             *
1451:             * @param	underTopAndNode		Whether or not we are under a top level AndNode.
1452:             *							
1453:             *
1454:             * @return		The modified expression
1455:             *
1456:             * @exception StandardException		Thrown on error
1457:             */
1458:            public ValueNode changeToCNF(boolean underTopAndNode)
1459:                    throws StandardException {
1460:                /* Remember whether or not we are immediately under a top leve
1461:                 * AndNode.  This is important for subquery flattening.
1462:                 * (We can only flatten subqueries under a top level AndNode.)
1463:                 */
1464:                this .underTopAndNode = underTopAndNode;
1465:
1466:                /* Halt recursion here, as each query block is preprocessed separately */
1467:                return this ;
1468:            }
1469:
1470:            /**
1471:             * Categorize this predicate.  Initially, this means
1472:             * building a bit map of the referenced tables for each predicate.
1473:             * If the source of this ColumnReference (at the next underlying level) 
1474:             * is not a ColumnReference or a VirtualColumnNode then this predicate
1475:             * will not be pushed down.
1476:             *
1477:             * For example, in:
1478:             *		select * from (select 1 from s) a (x) where x = 1
1479:             * we will not push down x = 1.
1480:             * NOTE: It would be easy to handle the case of a constant, but if the
1481:             * inner SELECT returns an arbitrary expression, then we would have to copy
1482:             * that tree into the pushed predicate, and that tree could contain
1483:             * subqueries and method calls.
1484:             * RESOLVE - revisit this issue once we have views.
1485:             *
1486:             * @param referencedTabs	JBitSet with bit map of referenced FromTables
1487:             * @return boolean		Whether or not source.expression is a ColumnReference
1488:             *						or a VirtualColumnNode.
1489:             *
1490:             * @exception StandardException		Thrown on error
1491:             */
1492:            public boolean categorize(JBitSet referencedTabs,
1493:                    boolean simplePredsOnly) throws StandardException {
1494:                /* We stop here when only considering simple predicates
1495:                 *  as we don't consider method calls when looking
1496:                 * for null invariant predicates.
1497:                 */
1498:                if (simplePredsOnly) {
1499:                    return false;
1500:                }
1501:
1502:                /* RESOLVE - We need to or in a bit map when there are correlation columns */
1503:
1504:                /* We categorize a query block at a time, so stop the recursion here */
1505:
1506:                /* Predicates with subqueries are not pushable for now */
1507:
1508:                /*
1509:                 ** If we can materialize the subquery, then it is 
1510:                 ** both invariant and non-correlated.  And so it
1511:                 ** is pushable.
1512:                 */
1513:                return isMaterializable();
1514:
1515:            }
1516:
1517:            /*
1518:             ** Subquery is materializable if
1519:             ** it is an expression subquery that
1520:             ** has no correlations and is invariant.
1521:             */
1522:            boolean isMaterializable() throws StandardException {
1523:                boolean retval = (subqueryType == EXPRESSION_SUBQUERY)
1524:                        && !hasCorrelatedCRs() && isInvariant();
1525:                /* If we can materialize the subquery, then we set
1526:                 * the level of all of the tables to 0 so that we can
1527:                 * consider bulk fetch for them.
1528:                 */
1529:                if (retval) {
1530:                    if (resultSet instanceof  SelectNode) {
1531:                        SelectNode select = (SelectNode) resultSet;
1532:                        FromList fromList = select.getFromList();
1533:                        fromList.setLevel(0);
1534:                    }
1535:                }
1536:
1537:                return retval;
1538:            }
1539:
1540:            /**
1541:             * Optimize this SubqueryNode.  
1542:             *
1543:             * @param dataDictionary	The DataDictionary to use for optimization
1544:             * @param outerRows			The optimizer's estimate of the number of
1545:             *							times this subquery will be executed.
1546:             *
1547:             * @exception StandardException		Thrown on error
1548:             */
1549:
1550:            public void optimize(DataDictionary dataDictionary, double outerRows)
1551:                    throws StandardException {
1552:                /* RESOLVE - is there anything else that we need to do for this
1553:                 * node.
1554:                 */
1555:
1556:                /* Optimize the underlying result set */
1557:                resultSet = resultSet.optimize(dataDictionary, null, outerRows);
1558:            }
1559:
1560:            /**
1561:             * Make any changes to the access paths, as decided by the optimizer.
1562:             *
1563:             * @exception StandardException		Thrown on error
1564:             */
1565:            public void modifyAccessPaths() throws StandardException {
1566:                resultSet = resultSet.modifyAccessPaths();
1567:            }
1568:
1569:            /**
1570:             * Return the variant type for the underlying expression.
1571:             * The variant type can be:
1572:             *		VARIANT				- variant within a scan
1573:             *							  (method calls and non-static field access)
1574:             *		SCAN_INVARIANT		- invariant within a scan
1575:             *							  (column references from outer tables)
1576:             *		QUERY_INVARIANT		- invariant within the life of a query
1577:             *							  (constant expressions)
1578:             *
1579:             * @return	The variant type for the underlying expression.
1580:             *
1581:             * @exception StandardException		Thrown on error
1582:             */
1583:            protected int getOrderableVariantType() throws StandardException {
1584:                /* 
1585:                 * If the subquery is variant, than return
1586:                 * VARIANT.  Otherwise, if we have an expression
1587:                 * subquery and no correlated CRs we are going
1588:                 * to materialize it, so it is QUERY_INVARIANT.
1589:                 * Otherwise, SCAN_INVARIANT.
1590:                 */
1591:                if (isInvariant()) {
1592:                    if (!hasCorrelatedCRs()
1593:                            && (subqueryType == EXPRESSION_SUBQUERY)) {
1594:                        return Qualifier.QUERY_INVARIANT;
1595:                    } else {
1596:                        return Qualifier.SCAN_INVARIANT;
1597:                    }
1598:                } else {
1599:                    return Qualifier.VARIANT;
1600:                }
1601:            }
1602:
1603:            /**
1604:             * Do code generation for this subquery.
1605:             *
1606:             * @param expressionBuilder	The ExpressionClassBuilder for the class being built
1607:             * @param mbex	The method the expression will go into
1608:             *
1609:             *
1610:             * @exception StandardException		Thrown on error
1611:             */
1612:
1613:            public void generateExpression(
1614:                    ExpressionClassBuilder expressionBuilder, MethodBuilder mbex)
1615:                    throws StandardException {
1616:                CompilerContext cc = getCompilerContext();
1617:                String resultSetString;
1618:
1619:                ///////////////////////////////////////////////////////////////////////////
1620:                //
1621:                //	Subqueries should not appear in Filter expressions. We should get here
1622:                //	only if we're compiling a query. That means that our class builder
1623:                //	is an activation builder. If we ever allow subqueries in filters, we'll
1624:                //	have to revisit this code.
1625:                //
1626:                ///////////////////////////////////////////////////////////////////////////
1627:
1628:                if (SanityManager.DEBUG) {
1629:                    SanityManager
1630:                            .ASSERT(
1631:                                    expressionBuilder instanceof  ActivationClassBuilder,
1632:                                    "Expecting an ActivationClassBuilder");
1633:                }
1634:
1635:                ActivationClassBuilder acb = (ActivationClassBuilder) expressionBuilder;
1636:                /* Reuse generated code, where possible */
1637:
1638:                /* Generate the appropriate (Any or Once) ResultSet */
1639:                if (subqueryType == EXPRESSION_SUBQUERY) {
1640:                    resultSetString = "getOnceResultSet";
1641:                } else {
1642:                    resultSetString = "getAnyResultSet";
1643:                }
1644:
1645:                // Get cost estimate for underlying subquery
1646:                CostEstimate costEstimate = resultSet.getFinalCostEstimate();
1647:
1648:                /* Generate a new method.  It's only used within the other
1649:                 * exprFuns, so it could be private. but since we don't
1650:                 * generate the right bytecodes to invoke private methods,
1651:                 * we just make it protected.  This generated class won't
1652:                 * have any subclasses, certainly! (nat 12/97)
1653:                 */
1654:                String subqueryTypeString = getTypeCompiler().interfaceName();
1655:                MethodBuilder mb = acb.newGeneratedFun(subqueryTypeString,
1656:                        Modifier.PROTECTED);
1657:
1658:                /* Declare the field to hold the suquery's ResultSet tree */
1659:                LocalField rsFieldLF = acb.newFieldDeclaration(
1660:                        Modifier.PRIVATE, ClassName.NoPutResultSet);
1661:
1662:                ResultSetNode subNode = null;
1663:
1664:                if (!isMaterializable()) {
1665:                    MethodBuilder executeMB = acb.getExecuteMethod();
1666:                    if (pushedNewPredicate && (!hasCorrelatedCRs())) {
1667:                        /* We try to materialize the subquery if it can fit in the memory.  We
1668:                         * evaluate the subquery first.  If the result set fits in the memory,
1669:                         * we replace the resultset with in-memory unions of row result sets.
1670:                         * We do this trick by replacing the child result with a new node --
1671:                         * MaterializeSubqueryNode, which essentially generates the suitable
1672:                         * code to materialize the subquery if possible.  This may have big
1673:                         * performance improvement.  See beetle 4373.
1674:                         */
1675:                        if (SanityManager.DEBUG) {
1676:                            SanityManager
1677:                                    .ASSERT(
1678:                                            resultSet instanceof  ProjectRestrictNode,
1679:                                            "resultSet expected to be a ProjectRestrictNode!");
1680:                        }
1681:                        subNode = ((ProjectRestrictNode) resultSet)
1682:                                .getChildResult();
1683:                        LocalField subRS = acb.newFieldDeclaration(
1684:                                Modifier.PRIVATE, ClassName.NoPutResultSet);
1685:                        mb.getField(subRS);
1686:                        mb.conditionalIfNull();
1687:
1688:                        ResultSetNode materialSubNode = new MaterializeSubqueryNode(
1689:                                subRS);
1690:
1691:                        // Propagate the resultSet's cost estimate to the new node.
1692:                        materialSubNode.costEstimate = resultSet
1693:                                .getFinalCostEstimate();
1694:
1695:                        ((ProjectRestrictNode) resultSet)
1696:                                .setChildResult(materialSubNode);
1697:
1698:                        /* Evaluate subquery resultset here first.  Next time when we come to
1699:                         * this subquery it may be replaced by a bunch of unions of rows.
1700:                         */
1701:                        subNode.generate(acb, mb);
1702:                        mb.startElseCode();
1703:                        mb.getField(subRS);
1704:                        mb.completeConditional();
1705:
1706:                        mb.setField(subRS);
1707:
1708:                        executeMB.pushNull(ClassName.NoPutResultSet);
1709:                        executeMB.setField(subRS);
1710:                    }
1711:
1712:                    executeMB.pushNull(ClassName.NoPutResultSet);
1713:                    executeMB.setField(rsFieldLF);
1714:
1715:                    // now we fill in the body of the conditional
1716:                    mb.getField(rsFieldLF);
1717:                    mb.conditionalIfNull();
1718:                }
1719:
1720:                acb.pushGetResultSetFactoryExpression(mb);
1721:
1722:                // start of args
1723:                int nargs;
1724:
1725:                /* Inside here is where subquery could already have been materialized. 4373
1726:                 */
1727:                resultSet.generate(acb, mb);
1728:
1729:                /* Get the next ResultSet #, so that we can number the subquery's 
1730:                 * empty row ResultColumnList and Once/Any ResultSet.
1731:                 */
1732:                int subqResultSetNumber = cc.getNextResultSetNumber();
1733:
1734:                /* We will be reusing the RCL from the subquery's ResultSet for the 
1735:                 * empty row function.  We need to reset the resultSetNumber in the
1736:                 * RCL, before we generate that function.  Now that we've called
1737:                 * generate() on the subquery's ResultSet, we can reset that
1738:                 * resultSetNumber.
1739:                 */
1740:                resultSet.getResultColumns().setResultSetNumber(
1741:                        subqResultSetNumber);
1742:
1743:                /* Generate code for empty row */
1744:                resultSet.getResultColumns().generateNulls(acb, mb);
1745:
1746:                /*
1747:                 *	arg1: suqueryExpress - Expression for subquery's
1748:                 *		  ResultSet
1749:                 *  arg2: Activation
1750:                 *  arg3: Method to generate Row with null(s) if subquery
1751:                 *		  Result Set is empty
1752:                 */
1753:                if (subqueryType == EXPRESSION_SUBQUERY) {
1754:                    int cardinalityCheck;
1755:
1756:                    /* No need to do sort if subquery began life as a distinct expression subquery.
1757:                     * (We simply check for a single unique value at execution time.)
1758:                     * No need for cardinality check if we know that underlying
1759:                     * ResultSet can contain at most 1 row.
1760:                     * RESOLVE - Not necessary if we know we
1761:                     * are getting a single row because of a unique index.
1762:                     */
1763:                    if (distinctExpression) {
1764:                        cardinalityCheck = OnceResultSet.UNIQUE_CARDINALITY_CHECK;
1765:                    } else if (resultSet.returnsAtMostOneRow()) {
1766:                        cardinalityCheck = OnceResultSet.NO_CARDINALITY_CHECK;
1767:                    } else {
1768:                        cardinalityCheck = OnceResultSet.DO_CARDINALITY_CHECK;
1769:                    }
1770:
1771:                    /*  arg4: int - whether or not cardinality check is required
1772:                     *				DO_CARDINALITY_CHECK - required
1773:                     *				NO_CARDINALITY_CHECK - not required
1774:                     *				UNIQUE_CARDINALITY_CHECK - verify single
1775:                     *											unique value
1776:                     */
1777:                    mb.push(cardinalityCheck);
1778:                    nargs = 8;
1779:
1780:                } else {
1781:                    nargs = 7;
1782:                }
1783:
1784:                mb.push(subqResultSetNumber);
1785:                mb.push(subqueryNumber);
1786:                mb.push(pointOfAttachment);
1787:                mb.push(costEstimate.rowCount());
1788:                mb.push(costEstimate.getEstimatedCost());
1789:
1790:                mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null,
1791:                        resultSetString, ClassName.NoPutResultSet, nargs);
1792:
1793:                /* Fill in the body of the method
1794:                 * generates the following.
1795:                 * (NOTE: the close() method only generated for
1796:                 * materialized subqueries.  All other subqueries
1797:                 * closed by top result set in the query.):
1798:                 * 
1799:                 *	NoPutResultSet	rsFieldX;
1800:                 *	{
1801:                 *		<Datatype interface> col;
1802:                 *		ExecRow r;
1803:                 *		rsFieldX = (rsFieldX == null) ? outerRSCall() : rsFieldX; // <== NONmaterialized specific
1804:                 *		rsFieldX.openCore();
1805:                 *		r = rsFieldX.getNextRowCore();
1806:                 *		col = (<Datatype interface>) r.getColumn(1);
1807:                 *		return col;
1808:                 *	}
1809:                 *
1810:                 * MATERIALIZED:
1811:                 *	NoPutResultSet	rsFieldX;
1812:                 *	{
1813:                 *		<Datatype interface> col;
1814:                 *		ExecRow r;
1815:                 *		rsFieldX = outerRSCall();
1816:                 *		rsFieldX.openCore();
1817:                 *		r = rsFieldX.getNextRowCore();
1818:                 *		col = (<Datatype interface>) r.getColumn(1);
1819:                 *		rsFieldX.close();								// <== materialized specific
1820:                 *		return col;
1821:                 *	}
1822:                 * and adds it to exprFun
1823:                 */
1824:
1825:                /* Generate the declarations */// PUSHCOMPILE
1826:                //VariableDeclaration colVar = mb.addVariableDeclaration(subqueryTypeString);
1827:                //VariableDeclaration rVar   = mb.addVariableDeclaration(ClassName.ExecRow);
1828:                if (!isMaterializable()) {
1829:                    /* put it back
1830:                     */
1831:                    if (pushedNewPredicate && (!hasCorrelatedCRs()))
1832:                        ((ProjectRestrictNode) resultSet)
1833:                                .setChildResult(subNode);
1834:
1835:                    // now we fill in the body of the conditional
1836:                    mb.startElseCode();
1837:                    mb.getField(rsFieldLF);
1838:                    mb.completeConditional();
1839:                }
1840:
1841:                mb.setField(rsFieldLF);
1842:
1843:                /* rs.openCore() */
1844:                mb.getField(rsFieldLF);
1845:                mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null,
1846:                        "openCore", "void", 0);
1847:
1848:                /* r = rs.next() */
1849:                mb.getField(rsFieldLF);
1850:                mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null,
1851:                        "getNextRowCore", ClassName.ExecRow, 0);
1852:                //mb.putVariable(rVar);
1853:                //mb.endStatement();
1854:
1855:                /* col = (<Datatype interface>) r.getColumn(1) */
1856:                //mb.getVariable(rVar);
1857:                mb.push(1); // both the Row interface and columnId are 1-based
1858:                mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row,
1859:                        "getColumn", ClassName.DataValueDescriptor, 1);
1860:                mb.cast(subqueryTypeString);
1861:                //mb.putVariable(colVar);
1862:                //mb.endStatement();
1863:
1864:                /* Only generate the close() method for materialized
1865:                 * subqueries.  All others will be closed when the
1866:                 * close() method is called on the top ResultSet.
1867:                 */
1868:                if (isMaterializable()) {
1869:                    /* rs.close() */
1870:                    mb.getField(rsFieldLF);
1871:                    mb.callMethod(VMOpcode.INVOKEINTERFACE,
1872:                            ClassName.ResultSet, "close", "void", 0);
1873:                }
1874:
1875:                /* return col */
1876:                //mb.getVariable(colVar);
1877:                mb.methodReturn();
1878:                mb.complete();
1879:
1880:                /*
1881:                 ** If we have an expression subquery, then we
1882:                 ** can materialize it if it has no correlated
1883:                 ** column references and is invariant.
1884:                 */
1885:                if (isMaterializable()) {
1886:                    LocalField lf = generateMaterialization(acb, mb,
1887:                            subqueryTypeString);
1888:                    mbex.getField(lf);
1889:
1890:                } else {
1891:                    /* Generate the call to the new method */
1892:                    mbex.pushThis();
1893:                    mbex.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, mb
1894:                            .getName(), subqueryTypeString, 0);
1895:                }
1896:            }
1897:
1898:            /*
1899:             ** Materialize the subquery in question.  Given the expression
1900:             ** that represents the subquery, this returns fieldX where
1901:             ** fieldX is set up as follows:
1902:             **
1903:             ** private ... fieldX
1904:             **
1905:             ** execute()
1906:             ** {
1907:             **	fieldX = <subqueryExpression>
1908:             **	...
1909:             ** }
1910:             **
1911:             ** So we wind up evaluating the subquery when we start
1912:             ** execution.  Obviously, it is absolutely necessary that
1913:             ** the subquery is invariant and has no correlations
1914:             ** for this to work.
1915:             **
1916:             ** Ideally we wouldn't evaluate the expression subquery
1917:             ** until we know we need to, but because we are marking
1918:             ** this expression subquery as pushable, we must evaluate
1919:             ** it up front because it might wind up as a qualification,
1920:             ** and we cannot execute a subquery in the store as a
1921:             ** qualification because the store executes qualifications
1922:             ** while holding a latch.  
1923:             **
1924:             ** @param acb
1925:             ** @param type 
1926:             ** @param subqueryExpression
1927:             */
1928:            private LocalField generateMaterialization(
1929:                    ActivationClassBuilder acb, MethodBuilder mbsq, String type) {
1930:                MethodBuilder mb = acb.executeMethod;
1931:
1932:                // declare field
1933:                LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE,
1934:                        type);
1935:
1936:                /* Generate the call to the new method */
1937:                mb.pushThis();
1938:                mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, mbsq
1939:                        .getName(), type, 0);
1940:
1941:                // generate: field = value (value is on stack)
1942:                mb.setField(field);
1943:
1944:                return field;
1945:            }
1946:
1947:            /* Private methods on private variables */
1948:            private BooleanConstantNode getTrueNode() throws StandardException {
1949:                if (trueNode == null) {
1950:                    trueNode = (BooleanConstantNode) getNodeFactory().getNode(
1951:                            C_NodeTypes.BOOLEAN_CONSTANT_NODE, Boolean.TRUE,
1952:                            getContextManager());
1953:                }
1954:                return trueNode;
1955:            }
1956:
1957:            /**
1958:             * Accept a visitor, and call v.visit()
1959:             * on child nodes as necessary.  
1960:             * 
1961:             * @param v the visitor
1962:             *
1963:             * @exception StandardException on error
1964:             */
1965:            public Visitable accept(Visitor v) throws StandardException {
1966:                Visitable returnNode = v.visit(this );
1967:
1968:                /* shortcut if we've already done it
1969:                 */
1970:                if ((v instanceof  HasCorrelatedCRsVisitor)
1971:                        && doneCorrelationCheck) {
1972:                    ((HasCorrelatedCRsVisitor) v)
1973:                            .setHasCorrelatedCRs(foundCorrelation);
1974:                    return returnNode;
1975:                }
1976:
1977:                if (v.skipChildren(this )) {
1978:                    return returnNode;
1979:                }
1980:
1981:                if (resultSet != null && !v.stopTraversal()) {
1982:                    resultSet = (ResultSetNode) resultSet.accept(v);
1983:                }
1984:
1985:                if (leftOperand != null && !v.stopTraversal()) {
1986:                    leftOperand = (ValueNode) leftOperand.accept(v);
1987:                }
1988:                return returnNode;
1989:            }
1990:
1991:            private boolean isIN() {
1992:                return subqueryType == IN_SUBQUERY;
1993:            }
1994:
1995:            private boolean isNOT_IN() {
1996:                return subqueryType == NOT_IN_SUBQUERY;
1997:            }
1998:
1999:            private boolean isANY() {
2000:                switch (subqueryType) {
2001:                case EQ_ANY_SUBQUERY:
2002:                case NE_ANY_SUBQUERY:
2003:                case LE_ANY_SUBQUERY:
2004:                case LT_ANY_SUBQUERY:
2005:                case GE_ANY_SUBQUERY:
2006:                case GT_ANY_SUBQUERY:
2007:                    return true;
2008:
2009:                default:
2010:                    return false;
2011:                }
2012:            }
2013:
2014:            private boolean isALL() {
2015:                switch (subqueryType) {
2016:                case EQ_ALL_SUBQUERY:
2017:                case NE_ALL_SUBQUERY:
2018:                case LE_ALL_SUBQUERY:
2019:                case LT_ALL_SUBQUERY:
2020:                case GE_ALL_SUBQUERY:
2021:                case GT_ALL_SUBQUERY:
2022:                    return true;
2023:
2024:                default:
2025:                    return false;
2026:                }
2027:            }
2028:
2029:            private boolean isEXISTS() {
2030:                return subqueryType == EXISTS_SUBQUERY;
2031:            }
2032:
2033:            private boolean isNOT_EXISTS() {
2034:                return subqueryType == NOT_EXISTS_SUBQUERY;
2035:            }
2036:
2037:            /**
2038:             * Convert this IN/ANY subquery, which is known to return at most 1 row,
2039:             * to an equivalent expression subquery.
2040:             *
2041:             * @exception StandardException		Thrown on error
2042:             */
2043:            private void changeToCorrespondingExpressionType()
2044:                    throws StandardException {
2045:                BinaryOperatorNode bcon = null;
2046:
2047:                switch (subqueryType) {
2048:                case EQ_ANY_SUBQUERY:
2049:                case IN_SUBQUERY:
2050:                    bcon = (BinaryOperatorNode) getNodeFactory().getNode(
2051:                            C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE,
2052:                            leftOperand, this , getContextManager());
2053:                    break;
2054:
2055:                case NE_ANY_SUBQUERY:
2056:                    bcon = (BinaryOperatorNode) getNodeFactory().getNode(
2057:                            C_NodeTypes.BINARY_NOT_EQUALS_OPERATOR_NODE,
2058:                            leftOperand, this , getContextManager());
2059:                    break;
2060:
2061:                case LE_ANY_SUBQUERY:
2062:                    bcon = (BinaryOperatorNode) getNodeFactory().getNode(
2063:                            C_NodeTypes.BINARY_LESS_EQUALS_OPERATOR_NODE,
2064:                            leftOperand, this , getContextManager());
2065:                    break;
2066:
2067:                case LT_ANY_SUBQUERY:
2068:                    bcon = (BinaryOperatorNode) getNodeFactory().getNode(
2069:                            C_NodeTypes.BINARY_LESS_THAN_OPERATOR_NODE,
2070:                            leftOperand, this , getContextManager());
2071:                    break;
2072:
2073:                case GE_ANY_SUBQUERY:
2074:                    bcon = (BinaryOperatorNode) getNodeFactory().getNode(
2075:                            C_NodeTypes.BINARY_GREATER_EQUALS_OPERATOR_NODE,
2076:                            leftOperand, this , getContextManager());
2077:                    break;
2078:
2079:                case GT_ANY_SUBQUERY:
2080:                    bcon = (BinaryOperatorNode) getNodeFactory().getNode(
2081:                            C_NodeTypes.BINARY_GREATER_THAN_OPERATOR_NODE,
2082:                            leftOperand, this , getContextManager());
2083:                    break;
2084:                }
2085:
2086:                // clean up the state of the tree to reflect a bound expression subquery
2087:                subqueryType = EXPRESSION_SUBQUERY;
2088:                setDataTypeServices(resultSet.getResultColumns());
2089:
2090:                parentComparisonOperator = (BinaryComparisonOperatorNode) bcon;
2091:                /* Set type info for the operator node */
2092:                parentComparisonOperator.bindComparisonOperator();
2093:                leftOperand = null;
2094:            }
2095:
2096:            private void setDataTypeServices(ResultColumnList resultColumns)
2097:                    throws StandardException {
2098:                DataTypeDescriptor dts;
2099:
2100:                /* Set the result type for this subquery (must be nullable).
2101:                 * Quantified predicates will return boolean.
2102:                 * However, the return type of the subquery's result list will 
2103:                 * probably not be boolean at this point, because we do not
2104:                 * transform the subquery (other than EXISTS) into 
2105:                 * (select true/false ...) until preprocess().  So, we force 
2106:                 * the return type to boolean.
2107:                 */
2108:                if (subqueryType == EXPRESSION_SUBQUERY) {
2109:                    dts = ((ResultColumn) resultColumns.elementAt(0))
2110:                            .getTypeServices();
2111:                } else {
2112:                    dts = getTrueNode().getTypeServices();
2113:                }
2114:
2115:                /* If datatype of underlying resultSet is nullable, reuse it, otherwise
2116:                 * we need to generate a new one.
2117:                 */
2118:                if (!dts.isNullable()) {
2119:                    dts = new DataTypeDescriptor(dts, true);
2120:                }
2121:                setType(dts);
2122:            }
2123:
2124:            /**
2125:             * {@inheritDoc}
2126:             */
2127:            protected boolean isEquivalent(ValueNode o) {
2128:                return false;
2129:            }
2130:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.