📄 subquerynode.java
字号:
/* Derby - Class org.apache.derby.impl.sql.compile.SubqueryNode Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */package org.apache.derby.impl.sql.compile;import org.apache.derby.iapi.services.context.ContextManager;import org.apache.derby.iapi.error.StandardException;import org.apache.derby.iapi.sql.compile.CompilerContext;import org.apache.derby.iapi.sql.compile.CostEstimate;import org.apache.derby.iapi.sql.compile.Visitable;import org.apache.derby.iapi.sql.compile.Visitor;import org.apache.derby.iapi.sql.compile.C_NodeTypes;import org.apache.derby.iapi.sql.dictionary.DataDictionary;import org.apache.derby.iapi.reference.SQLState;import org.apache.derby.iapi.reference.ClassName;import org.apache.derby.iapi.types.DataTypeDescriptor;import org.apache.derby.iapi.sql.execute.ExecRow;import org.apache.derby.iapi.sql.Activation;import org.apache.derby.iapi.types.DataValueDescriptor;import org.apache.derby.iapi.sql.Row;import org.apache.derby.iapi.types.DataTypeDescriptor;import org.apache.derby.iapi.sql.ResultSet;import org.apache.derby.iapi.types.TypeId;import org.apache.derby.iapi.services.loader.GeneratedMethod;import org.apache.derby.iapi.services.compiler.MethodBuilder;import org.apache.derby.iapi.services.compiler.LocalField;import org.apache.derby.iapi.services.sanity.SanityManager;import org.apache.derby.iapi.store.access.Qualifier;import java.lang.reflect.Modifier;import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;import org.apache.derby.impl.sql.compile.ActivationClassBuilder;import org.apache.derby.impl.sql.execute.OnceResultSet;import org.apache.derby.iapi.util.JBitSet;import org.apache.derby.iapi.util.ReuseFactory;import org.apache.derby.iapi.services.classfile.VMOpcode;import java.util.Properties;import java.util.Vector;/** * A SubqueryNode represents a subquery. Subqueries return values to their * outer queries. An quantified subquery is one that appears under a quantified * operator (like IN or EXISTS) - quantified subqueries can return more than * one value per invocation. An expression subquery is one that is not directly * under a quantified operator - expression subqueries are allowed to return * at most one value per invocation (returning no value is considered to be * equivalent to returning NULL). * * There are a large number of subquery types. Because of the large number of * types, and the large amount of shared code, we have decided to have 1 SubqueryNode * without any subclasses. The subquery type (and operator) is encoded in the * subqueryType field. * * The query optimizer is responsible for optimizing subqueries, and also for * transforming them so that code can be generated for them. The optimizer may * eliminate some subqueries by transforming them into joins, or it may * change the internal form of a subquery (for example, transforming * 'where x in (select y from z where ...)' into * 'where (select true from z where x = y and ...)'). * * Note that aggregates present some additional issues. A transformation * such as: * <UL> where x in (SELECT <I>expression</I> FROM z) </UL> * has to be treated specially if <I>expression</I> has an aggregate. * We change it to: * <UL> where x = (SELECT true FROM (SELECT MAX(x) FROM z) WHERE SQLCOL1 = y) </UL> * * @author Jeff Lichtman */public class SubqueryNode extends ValueNode{ /* ** This must be a single-column result set. If the subquery is ** not quantified, it must also be a single-row result set - that is, ** expression subqueries are allowed to return only a single value ** per invocation. ** NOTE: SubqueryNodes are used as an intermediate step within the parser ** for building a derived table. Derived tables can be multi-column and ** multi-table. */ ResultSetNode resultSet; /* Type of this subquery */ int subqueryType; /* Whether or not this subquery is immediately under a top level AndNode. * (Important for subquery flattening.) */ boolean underTopAndNode; /* Whether or not we've been preprocessed. (Only do the work once.) */ boolean preprocessed; /* Whether or not this subquery began life as a distinct expression subquery */ boolean distinctExpression; /* Since we do not have separate subquery operator nodes, the * type of the subquery is stored in the subqueryType field. Most subquery * types take a left operand (except for expression and exists). We could * either add a leftOperand field here or subclass SubqueryNode for those * types that take a left operand. We have decided to add the left operand * here for now. */ ValueNode leftOperand; boolean pushedNewPredicate; /* Expression subqueries on the right side of a BinaryComparisonOperatorNode * will get passed a pointer to that node prior to preprocess(). This * allows us to replace the entire comparison, if we want to, when * flattening. */ BinaryComparisonOperatorNode parentComparisonOperator; /* Private fields (all references via private methods) - * We reuse true BooleanConstantNodes within * this class, creating them on the first reference. */ private BooleanConstantNode trueNode; /* Reuse generated code where possible */ //private Expression genResult; /* Subquery # for this subquery */ private int subqueryNumber = -1; /* ResultSet # for the point of attachment for this subquery */ private int pointOfAttachment = -1; /* ** Indicate whether we found a correlation or not. ** And track whether we have checked yet. */ private boolean foundCorrelation; private boolean doneCorrelationCheck; /* ** Indicate whether we found an invariant node ** below us or not. And track whether we have ** checked yet. */ private boolean foundVariant; private boolean doneInvariantCheck; /* Subquery types. * NOTE: FROM_SUBQUERY only exists for a brief second in the parser. It * should never appear in a query tree. * NOTE: NOT EXISTS and NOT IN subquery types do not exist prior to NOT * elimination during preprocessing. Prior to that, there is a separate * NotNode above the SubqueryNode in the tree. * */ public final static int NOTIMPLEMENTED_SUBQUERY = -1; public final static int FROM_SUBQUERY = 0; public final static int IN_SUBQUERY = 1; public final static int NOT_IN_SUBQUERY = 2; public final static int EQ_ANY_SUBQUERY = 3; public final static int EQ_ALL_SUBQUERY = 4; public final static int NE_ANY_SUBQUERY = 5; public final static int NE_ALL_SUBQUERY = 6; public final static int GT_ANY_SUBQUERY = 7; public final static int GT_ALL_SUBQUERY = 8; public final static int GE_ANY_SUBQUERY = 9; public final static int GE_ALL_SUBQUERY = 10; public final static int LT_ANY_SUBQUERY = 11; public final static int LT_ALL_SUBQUERY = 12; public final static int LE_ANY_SUBQUERY = 13; public final static int LE_ALL_SUBQUERY = 14; public final static int EXISTS_SUBQUERY = 15; public final static int NOT_EXISTS_SUBQUERY = 16; public final static int EXPRESSION_SUBQUERY = 17; /** * Initializer. * * @param resultSet The ResultSetNode for the subquery * @param subqueryType The type of the subquery * @param leftOperand The left operand, if any, of the subquery */ public void init( Object resultSet, Object subqueryType, Object leftOperand) { this.resultSet = (ResultSetNode) resultSet; this.subqueryType = ((Integer) subqueryType).intValue(); /* Subqueries are presumed not to be under a top level AndNode by * default. This is because expression normalization only recurses * under Ands and Ors, not under comparison operators, method calls, * built-in functions, etc. */ underTopAndNode = false; this.leftOperand = (ValueNode) leftOperand; } /** * Convert this object to a String. See comments in QueryTreeNode.java * for how this should be done for tree printing. * * @return This object as a String */ public String toString() { if (SanityManager.DEBUG) { return "subqueryType: " + subqueryType + "\n" + "underTopAndNode: " + underTopAndNode + "\n" + "subqueryNumber: " + subqueryNumber + "\n" + "pointOfAttachment: " + pointOfAttachment + "\n" + "preprocessed: " + preprocessed + "\n" + "distinctExpression: " + distinctExpression + "\n" + super.toString(); } else { return ""; } } /** * Prints the sub-nodes of this object. See QueryTreeNode.java for * how tree printing is supposed to work. * * @param depth The depth of this node in the tree * * @return Nothing */ public void printSubNodes(int depth) { if (SanityManager.DEBUG) { super.printSubNodes(depth); if (resultSet != null) { printLabel(depth, "resultSet: "); resultSet.treePrint(depth + 1); } if (leftOperand != null) { printLabel(depth, "leftOperand: "); leftOperand.treePrint(depth + 1); } } } /** * Return the resultSet for this SubqueryNode. * * @return ResultSetNode underlying this SubqueryNode. */ public ResultSetNode getResultSet() { return resultSet; } /** * Return the type of this subquery. * * @return int Type of this subquery. */ public int getSubqueryType() { return subqueryType; } /** * Set the type of this subquery. * * @param Type of this subquery. * * @return None. */ public void setSubqueryType(int subqueryType) { this.subqueryType = subqueryType; } /** * Set the point of attachment of this subquery. * * @param pointOfAttachment The point of attachment of this subquery. * * @return None. * * @exception StandardException Thrown on error */ public void setPointOfAttachment(int pointOfAttachment) throws StandardException { /* Materialized subqueries always keep their point of * attachment as -1. */ if (! isMaterializable()) { this.pointOfAttachment = pointOfAttachment; } } /** * Return whether or not this subquery is immediately under a top level * AndNode. * * @return boolean Whether or not this subquery is immediately under a * top level AndNode. */ public boolean getUnderTopAndNode() { return underTopAndNode; } /** * Get the ResultSet # for the point of attachment for this SubqueryNode. * * @return int The ResultSet # for the point of attachment */ public int getPointOfAttachment() { if (SanityManager.DEBUG) { SanityManager.ASSERT(pointOfAttachment >= 0, "pointOfAttachment expected to be >= 0"); } return pointOfAttachment; } /** * Get whether or not this SubqueryNode has already been * preprocessed. * * @return Whether or not this SubqueryNode has already been * preprocessed. */ boolean getPreprocessed() { return preprocessed; } /** * Set the parent BCON. Useful when considering flattening * expression subqueries. * * @param parent The parent BCON. * * @return Nothing. */ void setParentComparisonOperator(BinaryComparisonOperatorNode parent) { parentComparisonOperator = parent; } /** * Remap all ColumnReferences in this tree to be clones of the * underlying expression. * * @return ValueNode The remapped expression tree. * * @exception StandardException Thrown on error */ public ValueNode remapColumnReferencesToExpressions() throws StandardException { /* We need to remap both the SELECT and Predicate lists * since there may be correlated columns in either of them. */ if (resultSet instanceof SelectNode) { ResultColumnList selectRCL = resultSet.getResultColumns(); SelectNode select = (SelectNode) resultSet; PredicateList selectPL = select.getWherePredicates(); if (SanityManager.DEBUG) { SanityManager.ASSERT(selectPL != null, "selectPL expected to be non-null"); } selectRCL.remapColumnReferencesToExpressions(); selectPL.remapColumnReferencesToExpressions(); } return this; } /**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -