0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.sql.compile.ValueNode
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.types.DataTypeDescriptor;
0025: import org.apache.derby.iapi.types.TypeId;
0026: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
0027: import org.apache.derby.iapi.error.StandardException;
0028:
0029: import org.apache.derby.iapi.sql.compile.TypeCompiler;
0030: import org.apache.derby.iapi.types.DataValueFactory;
0031:
0032: import org.apache.derby.iapi.types.SQLChar;
0033:
0034: import org.apache.derby.iapi.services.sanity.SanityManager;
0035:
0036: import org.apache.derby.iapi.sql.compile.CompilerContext;
0037: import org.apache.derby.iapi.sql.compile.Optimizable;
0038: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
0039: import org.apache.derby.iapi.sql.compile.NodeFactory;
0040:
0041: import org.apache.derby.iapi.reference.SQLState;
0042:
0043: import org.apache.derby.iapi.store.access.Qualifier;
0044:
0045: import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
0046: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
0047:
0048: import org.apache.derby.iapi.services.compiler.MethodBuilder;
0049:
0050: import org.apache.derby.iapi.util.JBitSet;
0051: import org.apache.derby.iapi.services.i18n.MessageService;
0052:
0053: import java.lang.reflect.Modifier;
0054:
0055: import java.sql.Date;
0056: import java.sql.Time;
0057: import java.sql.Timestamp;
0058:
0059: import java.util.Vector;
0060:
0061: /**
0062: * A ValueNode is an abstract class for all nodes that can represent data
0063: * values, that is, constants, columns, and expressions.
0064: *
0065: * @author Jeff Lichtman
0066: */
0067:
0068: public abstract class ValueNode extends QueryTreeNode {
0069: public static final int IN_UNKNOWN_CLAUSE = 0;
0070: public static final int IN_SELECT_LIST = 1;
0071: public static final int IN_WHERE_CLAUSE = 2;
0072: public static final int IN_HAVING_CLAUSE = 3;
0073:
0074: protected DataTypeDescriptor dataTypeServices;
0075: private TypeId typeId;
0076: private TypeCompiler typeCompiler;
0077: protected int clause = IN_UNKNOWN_CLAUSE;
0078:
0079: // Whether or not additional predicates have been created from this one.
0080: boolean transformed;
0081:
0082: /*
0083: ** Constructor for untyped ValueNodes, for example, untyped NULLs
0084: ** and parameter nodes.
0085: **
0086: ** Binding will replace all untyped ValueNodes with typed ValueNodes
0087: ** when it figures out what their types should be.
0088: */
0089: public ValueNode() {
0090: }
0091:
0092: /**
0093: * Initializer for numeric types.
0094: *
0095: *
0096: * @param typeId The TypeID of this new node
0097: * @param precision The precision of this new node
0098: * @param scale The scale of this new node
0099: * @param isNullable The nullability of this new node
0100: * @param maximumWidth The maximum width of this new node
0101: *
0102: * @exception StandardException
0103: */
0104:
0105: public void init(Object typeId, Object precision, Object scale,
0106: Object isNullable, Object maximumWidth)
0107: throws StandardException {
0108: setType(new DataTypeDescriptor((TypeId) typeId,
0109: ((Integer) precision).intValue(), ((Integer) scale)
0110: .intValue(), ((Boolean) isNullable)
0111: .booleanValue(), ((Integer) maximumWidth)
0112: .intValue()));
0113: }
0114:
0115: /**
0116: * Initializer for non-numeric types.
0117: *
0118: *
0119: * @param tcf The factory to get the
0120: * DataTypeServicesFactory from
0121: * @param typeId The TypeID of this new node
0122: * @param isNullable The nullability of this new node
0123: * @param maximumWidth The maximum width of this new node
0124: *
0125: * @exception StandardException
0126: */
0127:
0128: ValueNode(Object tcf, Object typeId, Object isNullable,
0129: Object maximumWidth) throws StandardException {
0130: setType(new DataTypeDescriptor((TypeId) typeId,
0131: ((Boolean) isNullable).booleanValue(),
0132: ((Integer) maximumWidth).intValue()));
0133: }
0134:
0135: /**
0136: * Convert this object to a String. See comments in QueryTreeNode.java
0137: * for how this should be done for tree printing.
0138: *
0139: * @return This object as a String
0140: */
0141:
0142: public String toString() {
0143: if (SanityManager.DEBUG) {
0144: return "dataTypeServices: "
0145: + ((dataTypeServices != null) ? dataTypeServices
0146: .toString() : "null") + "\n" + "clause: "
0147: + clause + "\n" + super .toString();
0148: } else {
0149: return "";
0150: }
0151: }
0152:
0153: /**
0154: * Get the DataTypeServices from this ValueNode.
0155: *
0156: * @return The DataTypeServices from this ValueNode. This
0157: * may be null if the node isn't bound yet.
0158: */
0159: public DataTypeDescriptor getTypeServices()
0160: throws StandardException {
0161: return dataTypeServices;
0162: }
0163:
0164: /**
0165: * Get the TypeId from this ValueNode.
0166: *
0167: * @return The TypeId from this ValueNode. This
0168: * may be null if the node isn't bound yet.
0169: */
0170: public TypeId getTypeId() throws StandardException {
0171: return typeId;
0172: }
0173:
0174: /**
0175: Return the DataValueFactory
0176: */
0177: protected final DataValueFactory getDataValueFactory() {
0178: return getLanguageConnectionContext().getDataValueFactory();
0179: }
0180:
0181: /**
0182: * Get the TypeCompiler from this ValueNode, based on its TypeId.
0183: *
0184: * @return This ValueNode's TypeCompiler
0185: *
0186: */
0187: public TypeCompiler getTypeCompiler() throws StandardException {
0188: if (typeCompiler == null) {
0189: /*
0190: ** getTypeId() is overriddend by parameter node so
0191: ** don't get smart and remove the extra method call.
0192: */
0193: typeCompiler = getTypeCompiler(getTypeId());
0194: }
0195:
0196: return typeCompiler;
0197: }
0198:
0199: /**
0200: * Set the DataTypeServices for this ValueNode. This method is
0201: * overridden in ParameterNode.
0202: *
0203: * @param dataTypeServices The DataTypeServices to set in this
0204: * ValueNode
0205: */
0206:
0207: public void setType(DataTypeDescriptor dataTypeServices)
0208: throws StandardException {
0209: this .dataTypeServices = dataTypeServices;
0210:
0211: /* Get this now so we only have to cast it once */
0212: if (dataTypeServices == null)
0213: typeId = null;
0214: else
0215: typeId = dataTypeServices.getTypeId();
0216:
0217: // Clear the typeCompiler, just in case type has changed
0218: typeCompiler = null;
0219: }
0220:
0221: /**
0222: * Get the source for this ValueNode.
0223: *
0224: * @return The source of this ValueNode.
0225: */
0226:
0227: public ResultColumn getSourceResultColumn() {
0228: if (SanityManager.DEBUG)
0229: SanityManager.ASSERT(false,
0230: "getSourceResultColumn() not expected to be called for this node - "
0231: + getClass().toString());
0232: return null;
0233: }
0234:
0235: /**
0236: * Get the clause that this node appears in.
0237: *
0238: * @return int The clause that this node appears in.
0239: */
0240: public int getClause() {
0241: return clause;
0242: }
0243:
0244: /**
0245: * Set the clause that this node appears in.
0246: *
0247: * @param clause The clause that this node appears in.
0248: */
0249: public void setClause(int clause) {
0250: this .clause = clause;
0251: }
0252:
0253: /**
0254: * Mark this predicate has having been transformed (other predicates
0255: * were generated from it). This will help us with ensure that the
0256: * predicate does not get calculated into the selectivity multiple
0257: * times.
0258: */
0259: void setTransformed() {
0260: transformed = true;
0261: }
0262:
0263: /**
0264: * Return whether or not this predicate has been transformed.
0265: *
0266: * @return Whether or not this predicate has been transformed.
0267: */
0268: boolean getTransformed() {
0269: return transformed;
0270: }
0271:
0272: public ValueNode bindExpression(FromList fromList,
0273: SubqueryList subqueryList, Vector aggregateVector)
0274: throws StandardException {
0275: return bindExpression(fromList, subqueryList, aggregateVector,
0276: false);
0277: }
0278:
0279: /**
0280: * Bind this expression. This is a place-holder method - it should never
0281: * be called.
0282: *
0283: * @param fromList The FROM list to use for binding
0284: * @param subqueryList The SubqueryList we are building as we hit
0285: * SubqueryNodes.
0286: * @param aggregateVector The aggregate vector being built as we find AggregateNodes
0287: *
0288: * @return The new top of the expression tree.
0289: *
0290: * @exception StandardException Thrown on error
0291: */
0292:
0293: public ValueNode bindExpression(FromList fromList,
0294: SubqueryList subqueryList, Vector aggregateVector,
0295: boolean forQueryRewrite) throws StandardException {
0296: /* There are a bizillion classes which extend ValueNode. Here is info
0297: * on some of the classes that bindExpression() should not be called on
0298: * and why:
0299: * o BaseColumnNodes should only appear under the ResultColumnList
0300: * in the FromBaseTable. They are created/bound when binding the
0301: * FromBaseTable.
0302: */
0303: if (SanityManager.DEBUG) {
0304: SanityManager.ASSERT(false,
0305: "bindExpression() not expected to be called on a "
0306: + this .getClass().toString());
0307: }
0308:
0309: return this ;
0310: }
0311:
0312: /**
0313: * Generate a SQL->Java->SQL conversion tree above the current node
0314: * and bind the new nodes individually.
0315: * This is useful when doing comparisons, built-in functions, etc. on
0316: * java types which have a direct mapping to system built-in types.
0317: *
0318: * @return ValueNode The new tree.
0319: *
0320: * @exception StandardException Thrown on error
0321: */
0322: public ValueNode genSQLJavaSQLTree() throws StandardException {
0323: if (SanityManager.DEBUG) {
0324: SanityManager
0325: .ASSERT(typeId != null,
0326: "genSQLJavaSQLTree() only expected to be called on a bound node");
0327: SanityManager
0328: .ASSERT(typeId.userType(),
0329: "genSQLJavaSQLTree() only expected to be called on user types");
0330: }
0331:
0332: JavaValueNode stjvn = (JavaValueNode) getNodeFactory().getNode(
0333: C_NodeTypes.SQL_TO_JAVA_VALUE_NODE, this ,
0334: getContextManager());
0335:
0336: ValueNode jtsvn = (ValueNode) getNodeFactory().getNode(
0337: C_NodeTypes.JAVA_TO_SQL_VALUE_NODE, stjvn,
0338: getContextManager());
0339: jtsvn.setType(DataTypeDescriptor.getSQLDataTypeDescriptor(stjvn
0340: .getJavaTypeName()));
0341: return jtsvn;
0342: }
0343:
0344: /**
0345: * Preprocess an expression tree. We do a number of transformations
0346: * here (including subqueries, IN lists, LIKE and BETWEEN) plus
0347: * subquery flattening.
0348: * NOTE: This is done before the outer ResultSetNode is preprocessed.
0349: *
0350: * @param numTables Number of tables in the DML Statement
0351: * @param outerFromList FromList from outer query block
0352: * @param outerSubqueryList SubqueryList from outer query block
0353: * @param outerPredicateList PredicateList from outer query block
0354: *
0355: * @return The modified expression
0356: *
0357: * @exception StandardException Thrown on error
0358: */
0359: public ValueNode preprocess(int numTables, FromList outerFromList,
0360: SubqueryList outerSubqueryList,
0361: PredicateList outerPredicateList) throws StandardException {
0362: return this ;
0363: }
0364:
0365: /**
0366: * Eliminate NotNodes in the current query block. We traverse the tree,
0367: * inverting ANDs and ORs and eliminating NOTs as we go. We stop at
0368: * ComparisonOperators and boolean expressions. We invert
0369: * ComparisonOperators and replace boolean expressions with
0370: * boolean expression = false.
0371: * NOTE: Since we do not recurse under ComparisonOperators, there
0372: * still could be NotNodes left in the tree.
0373: *
0374: * @param underNotNode Whether or not we are under a NotNode.
0375: *
0376: *
0377: * @return The modified expression
0378: *
0379: * @exception StandardException Thrown on error
0380: */
0381: ValueNode eliminateNots(boolean underNotNode)
0382: throws StandardException {
0383: if (!underNotNode) {
0384: return this ;
0385: }
0386:
0387: /* bind() has ensured that this node's type is SQLBoolean */
0388: if (SanityManager.DEBUG)
0389: SanityManager.ASSERT(dataTypeServices.getTypeId().equals(
0390: TypeId.BOOLEAN_ID), "Node's type ("
0391: + dataTypeServices.getTypeId().getSQLTypeName()
0392: + ") is expected to be boolean");
0393:
0394: /* Return ValueNode = false */
0395: return genEqualsFalseTree();
0396: }
0397:
0398: /**
0399: * Transform this into this = false. Useful for NOT elimination.
0400: *
0401: *
0402: * @return The modified expression
0403: *
0404: * @exception StandardException Thrown on error
0405: */
0406: public ValueNode genEqualsFalseTree() throws StandardException {
0407: BinaryRelationalOperatorNode equalsNode;
0408: BooleanConstantNode falseNode;
0409: boolean nullableResult;
0410: NodeFactory nodeFactory = getNodeFactory();
0411:
0412: falseNode = (BooleanConstantNode) nodeFactory.getNode(
0413: C_NodeTypes.BOOLEAN_CONSTANT_NODE, Boolean.FALSE,
0414: getContextManager());
0415: equalsNode = (BinaryRelationalOperatorNode) nodeFactory
0416: .getNode(C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE, this ,
0417: falseNode, getContextManager());
0418: nullableResult = dataTypeServices.isNullable();
0419: equalsNode.setType(new DataTypeDescriptor(TypeId.BOOLEAN_ID,
0420: nullableResult));
0421: return equalsNode;
0422: }
0423:
0424: /**
0425: * Transform this into this is null. Useful for NOT elimination.
0426: *
0427: * @return The modified expression
0428: *
0429: * @exception StandardException Thrown on error
0430: */
0431: public ValueNode genIsNullTree() throws StandardException {
0432: IsNullNode isNullNode;
0433:
0434: isNullNode = (IsNullNode) getNodeFactory().getNode(
0435: C_NodeTypes.IS_NULL_NODE, this , getContextManager());
0436: isNullNode.setType(new DataTypeDescriptor(TypeId.BOOLEAN_ID,
0437: false));
0438: return isNullNode;
0439: }
0440:
0441: /**
0442: * Verify that eliminateNots() did its job correctly. Verify that
0443: * there are no NotNodes above the top level comparison operators
0444: * and boolean expressions.
0445: *
0446: * @return Boolean which reflects validity of the tree.
0447: */
0448: boolean verifyEliminateNots() {
0449: if (SanityManager.ASSERT) {
0450: return (!(this instanceof NotNode));
0451: } else {
0452: return true;
0453: }
0454: }
0455:
0456: /**
0457: * Do the 1st step in putting an expression into conjunctive normal
0458: * form. This step ensures that the top level of the expression is
0459: * a chain of AndNodes.
0460: *
0461: * @return The modified expression
0462: *
0463: * @exception StandardException Thrown on error
0464: */
0465: public ValueNode putAndsOnTop() throws StandardException {
0466: NodeFactory nodeFactory = getNodeFactory();
0467:
0468: QueryTreeNode trueNode = nodeFactory.getNode(
0469: C_NodeTypes.BOOLEAN_CONSTANT_NODE, Boolean.TRUE,
0470: getContextManager());
0471: AndNode andNode = (AndNode) nodeFactory.getNode(
0472: C_NodeTypes.AND_NODE, this , trueNode,
0473: getContextManager());
0474: andNode.postBindFixup();
0475: return andNode;
0476: }
0477:
0478: /**
0479: * Verify that putAndsOnTop() did its job correctly. Verify that the top level
0480: * of the expression is a chain of AndNodes.
0481: *
0482: * @return Boolean which reflects validity of the tree.
0483: */
0484: public boolean verifyPutAndsOnTop() {
0485: return true;
0486: }
0487:
0488: /**
0489: * Finish putting an expression into conjunctive normal
0490: * form. An expression tree in conjunctive normal form meets
0491: * the following criteria:
0492: * o If the expression tree is not null,
0493: * the top level will be a chain of AndNodes terminating
0494: * in a true BooleanConstantNode.
0495: * o The left child of an AndNode will never be an AndNode.
0496: * o Any right-linked chain that includes an AndNode will
0497: * be entirely composed of AndNodes terminated by a true BooleanConstantNode.
0498: * o The left child of an OrNode will never be an OrNode.
0499: * o Any right-linked chain that includes an OrNode will
0500: * be entirely composed of OrNodes terminated by a false BooleanConstantNode.
0501: * o ValueNodes other than AndNodes and OrNodes are considered
0502: * leaf nodes for purposes of expression normalization.
0503: * In other words, we won't do any normalization under
0504: * those nodes.
0505: *
0506: * In addition, we track whether or not we are under a top level AndNode.
0507: * SubqueryNodes need to know this for subquery flattening.
0508: *
0509: * @param underTopAndNode Whether or not we are under a top level AndNode.
0510: *
0511: *
0512: * @return The modified expression
0513: *
0514: * @exception StandardException Thrown on error
0515: */
0516: public ValueNode changeToCNF(boolean underTopAndNode)
0517: throws StandardException {
0518: return this ;
0519: }
0520:
0521: /**
0522: * Verify that changeToCNF() did its job correctly. Verify that:
0523: * o AndNode - rightOperand is not instanceof OrNode
0524: * leftOperand is not instanceof AndNode
0525: * o OrNode - rightOperand is not instanceof AndNode
0526: * leftOperand is not instanceof OrNode
0527: *
0528: * @return Boolean which reflects validity of the tree.
0529: */
0530: public boolean verifyChangeToCNF() {
0531: return true;
0532: }
0533:
0534: /**
0535: * Categorize this predicate. Initially, this means
0536: * building a bit map of the referenced tables for each predicate.
0537: * If the source of this ColumnReference (at the next underlying level)
0538: * is not a ColumnReference or a VirtualColumnNode then this predicate
0539: * will not be pushed down.
0540: *
0541: * For example, in:
0542: * select * from (select 1 from s) a (x) where x = 1
0543: * we will not push down x = 1.
0544: * NOTE: It would be easy to handle the case of a constant, but if the
0545: * inner SELECT returns an arbitrary expression, then we would have to copy
0546: * that tree into the pushed predicate, and that tree could contain
0547: * subqueries and method calls.
0548: * RESOLVE - revisit this issue once we have views.
0549: *
0550: * @param referencedTabs JBitSet with bit map of referenced FromTables
0551: * @param simplePredsOnly Whether or not to consider method
0552: * calls, field references and conditional nodes
0553: * when building bit map
0554: *
0555: * @return boolean Whether or not source.expression is a ColumnReference
0556: * or a VirtualColumnNode.
0557: *
0558: * @exception StandardException Thrown on error
0559: */
0560: public boolean categorize(JBitSet referencedTabs,
0561: boolean simplePredsOnly) throws StandardException {
0562: return true;
0563: }
0564:
0565: /**
0566: * This returns the user-supplied schema name of the column.
0567: * At this class level, it simply returns null. But, the subclasses
0568: * of ValueNode will overwrite this method to return the
0569: * user-supplied schema name.
0570: *
0571: * When the value node is in a result column of a select list,
0572: * the user can request metadata information. The result column
0573: * won't have a column descriptor, so we return some default
0574: * information through the expression. This lets expressions that
0575: * are simply columns return all of the info, and others use
0576: * this supertype's default values.
0577: *
0578: * @return the default schema name for an expression -- null
0579: */
0580: public String getSchemaName() throws StandardException {
0581: return null;
0582: }
0583:
0584: /**
0585: * This returns the user-supplied table name of the column.
0586: * At this class level, it simply returns null. But, the subclasses
0587: * of ValueNode will overwrite this method to return the
0588: * user-supplied table name.
0589: *
0590: * When the value node is in a result column of a select list,
0591: * the user can request metadata information. The result column
0592: * won't have a column descriptor, so we return some default
0593: * information through the expression. This lets expressions that
0594: * are simply columns return all of the info, and others use
0595: * this supertype's default values.
0596: *
0597: * @return the default table name for an expression -- null
0598: */
0599: public String getTableName() {
0600: return null;
0601: }
0602:
0603: /**
0604: * @return the default updatability for an expression - false
0605: */
0606: public boolean updatableByCursor() {
0607: return false;
0608: }
0609:
0610: /**
0611: * This is null so that the caller will substitute in the resultset generated
0612: * name as needed.
0613: *
0614: * @return the default column name for an expression -- null.
0615: */
0616: public String getColumnName() {
0617: return null;
0618: }
0619:
0620: /**
0621: * Get a bit map of table references in this expression
0622: *
0623: * @return A bit map of table numbers referred to in this expression
0624: *
0625: * @exception StandardException Thrown on error
0626: */
0627: JBitSet getTablesReferenced() throws StandardException {
0628: ReferencedTablesVisitor rtv = new ReferencedTablesVisitor(
0629: new JBitSet(0));
0630: accept(rtv);
0631: return rtv.getTableMap();
0632: }
0633:
0634: /**
0635: * Return whether or not this expression tree is cloneable.
0636: *
0637: * @return boolean Whether or not this expression tree is cloneable.
0638: */
0639: public boolean isCloneable() {
0640: return false;
0641: }
0642:
0643: /**
0644: * Return a clone of this node.
0645: *
0646: * @return ValueNode A clone of this node.
0647: *
0648: * @exception StandardException Thrown on error
0649: */
0650: public ValueNode getClone() throws StandardException {
0651: if (SanityManager.DEBUG) {
0652: SanityManager.ASSERT(false,
0653: "getClone() not expected to be called for "
0654: + getClass().getName());
0655: }
0656: return null;
0657: }
0658:
0659: /**
0660: * Copy all of the "appropriate fields" for a shallow copy.
0661: *
0662: * @param oldVN The ValueNode to copy from.
0663: *
0664: */
0665: public void copyFields(ValueNode oldVN) throws StandardException {
0666: dataTypeServices = oldVN.getTypeServices();
0667: typeId = oldVN.getTypeId();
0668: }
0669:
0670: /**
0671: * Remap all ColumnReferences in this tree to be clones of the
0672: * underlying expression.
0673: *
0674: * @return ValueNode The remapped expression tree.
0675: *
0676: * @exception StandardException Thrown on error
0677: */
0678: public ValueNode remapColumnReferencesToExpressions()
0679: throws StandardException {
0680: return this ;
0681: }
0682:
0683: /**
0684: * Return whether or not this expression tree represents a constant expression.
0685: *
0686: * @return Whether or not this expression tree represents a constant expression.
0687: */
0688: public boolean isConstantExpression() {
0689: return false;
0690: }
0691:
0692: /**
0693: * Return whether or not this expression tree represents a constant value.
0694: * In this case, "constant" means that it will always evaluate to the
0695: * same thing, even if it includes columns. A column is constant if it
0696: * is compared to a constant expression.
0697: *
0698: * @return True means this expression tree represents a constant value.
0699: */
0700: public boolean constantExpression(PredicateList whereClause) {
0701: return false;
0702: }
0703:
0704: /**
0705: * Bind time logic. Raises an error if this ValueNode, once compiled, returns
0706: * unstable results AND if we're in a context where unstable results are
0707: * forbidden.
0708: *
0709: * Called by children who may NOT appear in the WHERE subclauses of ADD TABLE clauses.
0710: *
0711: * @param fragmentType Type of fragment as a String, for inclusion in error messages.
0712: * @param fragmentBitMask Type of fragment as a bitmask of possible fragment types
0713: *
0714: * @exception StandardException Thrown on error
0715: */
0716: public void checkReliability(String fragmentType,
0717: int fragmentBitMask) throws StandardException {
0718: // if we're in a context that forbids unreliable fragments, raise an error
0719: if ((getCompilerContext().getReliability() & fragmentBitMask) != 0) {
0720: throwReliabilityException(fragmentType);
0721: }
0722: }
0723:
0724: /**
0725: * Bind time logic. Raises an error if this ValueNode, once compiled, returns
0726: * unstable results AND if we're in a context where unstable results are
0727: * forbidden.
0728: *
0729: * Called by children who may NOT appear in the WHERE subclauses of ADD TABLE clauses.
0730: *
0731: * @param fragmentBitMask Type of fragment as a bitmask of possible fragment types
0732: * @param fragmentType Type of fragment as a String, to be fetch for the error message.
0733: *
0734: * @exception StandardException Thrown on error
0735: */
0736: public void checkReliability(int fragmentBitMask,
0737: String fragmentType) throws StandardException {
0738: // if we're in a context that forbids unreliable fragments, raise an error
0739: if ((getCompilerContext().getReliability() & fragmentBitMask) != 0) {
0740: String fragmentTypeTxt = MessageService
0741: .getTextMessage(fragmentType);
0742: throwReliabilityException(fragmentTypeTxt);
0743: }
0744: }
0745:
0746: /**
0747: * Common code for the 2 checkReliability functions. Always throws StandardException.
0748: *
0749: * @param fragmentType Type of fragment as a string, for inclusion in error messages.
0750: * @exception StandardException Throws an error, always.
0751: */
0752: private void throwReliabilityException(String fragmentType)
0753: throws StandardException {
0754: String sqlState;
0755: /* Error string somewhat dependent on operation due to different
0756: * nodes being allowed for different operations.
0757: */
0758: if (getCompilerContext().getReliability() == CompilerContext.DEFAULT_RESTRICTION) {
0759: sqlState = SQLState.LANG_INVALID_DEFAULT_DEFINITION;
0760: } else {
0761: sqlState = SQLState.LANG_UNRELIABLE_QUERY_FRAGMENT;
0762: }
0763: throw StandardException.newException(sqlState, fragmentType);
0764: }
0765:
0766: /**
0767: * Return the variant type for the underlying expression.
0768: * The variant type can be:
0769: * VARIANT - variant within a scan
0770: * (method calls and non-static field access)
0771: * SCAN_INVARIANT - invariant within a scan
0772: * (column references from outer tables)
0773: * QUERY_INVARIANT - invariant within the life of a query
0774: * (constant expressions)
0775: *
0776: * @return The variant type for the underlying expression.
0777: * @exception StandardException Thrown on error
0778: */
0779: protected int getOrderableVariantType() throws StandardException {
0780: // The default is VARIANT
0781: return Qualifier.VARIANT;
0782: }
0783:
0784: /**
0785: * Bind time logic. Raises an error if this ValueNode does not resolve to
0786: * a boolean value. This method is called by WHERE clauses.
0787: *
0788: * @return bound coercion of this node to a builtin type as necessary
0789: *
0790: * @exception StandardException Thrown on error
0791: */
0792: public ValueNode checkIsBoolean() throws StandardException {
0793: ValueNode whereClause = this ;
0794:
0795: /*
0796: ** Is the datatype of the WHERE clause BOOLEAN?
0797: **
0798: ** NOTE: This test is not necessary in SQL92 entry level, because
0799: ** it is syntactically impossible to have a non-Boolean WHERE clause
0800: ** in that level of the standard. But we intend to extend the
0801: ** language to allow Boolean user functions in the WHERE clause,
0802: ** so we need to test for the error condition.
0803: */
0804: TypeId whereTypeId = whereClause.getTypeId();
0805:
0806: /* If the where clause is not a built-in type, then generate a bound
0807: * conversion tree to a built-in type.
0808: */
0809: if (whereTypeId.userType()) {
0810: whereClause = whereClause.genSQLJavaSQLTree();
0811: whereTypeId = whereClause.getTypeId();
0812: }
0813:
0814: if (!whereTypeId.equals(TypeId.BOOLEAN_ID)) {
0815: throw StandardException.newException(
0816: SQLState.LANG_NON_BOOLEAN_WHERE_CLAUSE, whereTypeId
0817: .getSQLTypeName());
0818: }
0819:
0820: return whereClause;
0821: }
0822:
0823: /**
0824: * Return an Object representing the bind time value of this
0825: * expression tree. If the expression tree does not evaluate to
0826: * a constant at bind time then we return null.
0827: * This is useful for bind time resolution of VTIs.
0828: * RESOLVE: What do we do for primitives?
0829: *
0830: * @return An Object representing the bind time value of this expression tree.
0831: * (null if not a bind time constant.)
0832: *
0833: * @exception StandardException Thrown on error
0834: */
0835: Object getConstantValueAsObject() throws StandardException {
0836: return null;
0837: }
0838:
0839: /////////////////////////////////////////////////////////////////////////
0840: //
0841: // The ValueNode defers its generate() work to a method that works on
0842: // ExpressionClassBuilders rather than ActivationClassBuilders. This
0843: // is so that expression generation can be shared by the Core compiler
0844: // AND the Replication Filter compiler.
0845: //
0846: /////////////////////////////////////////////////////////////////////////
0847:
0848: /**
0849: * Do the code generation for this node. Call the more general
0850: * routine that generates expressions.
0851: *
0852: * @param acb The ActivationClassBuilder for the class being built
0853: * @param mb The method the expression will go into
0854: *
0855: *
0856: * @exception StandardException Thrown on error
0857: */
0858:
0859: protected final void generate(ActivationClassBuilder acb,
0860: MethodBuilder mb) throws StandardException {
0861: generateExpression(acb, mb);
0862: }
0863:
0864: /**
0865: * The only reason this routine exists is so that I don't have to change
0866: * the protection on generateExpression() and rototill all of QueryTree.
0867: *
0868: * @param ecb The ExpressionClassBuilder for the class being built
0869: * @param mb The method the expression will go into
0870: *
0871: *
0872: * @exception StandardException Thrown on error
0873: */
0874: public void generateFilter(ExpressionClassBuilder ecb,
0875: MethodBuilder mb) throws StandardException {
0876: generateExpression(ecb, mb);
0877: }
0878:
0879: /**
0880: * The default selectivity for value nodes is 50%. This is overridden
0881: * in specific cases, such as the RelationalOperators.
0882: */
0883: public double selectivity(Optimizable optTable)
0884: throws StandardException {
0885: // Return 1 if additional predicates have been generated from this one.
0886: if (transformed) {
0887: return 1.0;
0888: } else {
0889: return 0.5d;
0890: }
0891: }
0892:
0893: /**
0894: * Update the array of columns in = conditions with expressions without
0895: * column references from the same table. This is useful when doing
0896: * subquery flattening on the basis of an equality condition.
0897: * eqOuterCols or tableColMap may be null if the calling routine
0898: * doesn't need the information provided
0899: *
0900: * @param tableNumber The tableNumber of the table from which
0901: * the columns of interest come from.
0902: * @param eqOuterCols Array of booleans for noting which columns
0903: * are in = predicates without columns from the
0904: * subquery block. May be null.
0905: * @param tableNumbers Array of table numbers in this query block.
0906: * @param tableColMap Array of bits for noting which columns
0907: * are in = predicates for each table in the
0908: * query block. May be null.
0909: * @param resultColTable True if tableNumber is the table containing result
0910: * columns
0911: *
0912: * @exception StandardException Thrown on error
0913: *
0914: */
0915: void checkTopPredicatesForEqualsConditions(int tableNumber,
0916: boolean[] eqOuterCols, int[] tableNumbers,
0917: JBitSet[] tableColMap, boolean resultColTable)
0918: throws StandardException {
0919: for (ValueNode whereWalker = this ; whereWalker instanceof AndNode; whereWalker = ((AndNode) whereWalker)
0920: .getRightOperand()) {
0921: // See if this is a candidate =
0922: AndNode and = (AndNode) whereWalker;
0923:
0924: if (!and.getLeftOperand().isRelationalOperator()
0925: || !(((RelationalOperator) (and.getLeftOperand()))
0926: .getOperator() == RelationalOperator.EQUALS_RELOP)) {
0927: continue;
0928: }
0929:
0930: BinaryRelationalOperatorNode beon = (BinaryRelationalOperatorNode) and
0931: .getLeftOperand();
0932: ValueNode left = beon.getLeftOperand();
0933: ValueNode right = beon.getRightOperand();
0934: int resultTable = 0;
0935: if (resultColTable) {
0936: for (; resultTable < tableNumbers.length; resultTable++) {
0937: if (tableNumbers[resultTable] == tableNumber)
0938: break;
0939: }
0940: } else
0941: resultTable = -1;
0942:
0943: /* Is this = of the right form? */
0944: if ((left instanceof ColumnReference)
0945: && ((ColumnReference) left).getTableNumber() == tableNumber) {
0946: updateMaps(tableColMap, eqOuterCols, tableNumbers,
0947: tableNumber, resultTable, right, left);
0948: } else if ((right instanceof ColumnReference)
0949: && ((ColumnReference) right).getTableNumber() == tableNumber) {
0950: updateMaps(tableColMap, eqOuterCols, tableNumbers,
0951: tableNumber, resultTable, left, right);
0952: }
0953: }
0954: }
0955:
0956: /**
0957: * Does this represent a true constant.
0958: *
0959: * @return Whether or not this node represents a true constant.
0960: */
0961: boolean isBooleanTrue() {
0962: return false;
0963: }
0964:
0965: /**
0966: * Does this represent a false constant.
0967: *
0968: * @return Whether or not this node represents a false constant.
0969: */
0970: boolean isBooleanFalse() {
0971: return false;
0972: }
0973:
0974: /**
0975: * Generate code for this calculation. This is a place-holder method -
0976: * it should not be called.
0977: *
0978: * @param acb The ExpressionClassBuilder for the class being built
0979: * @param mb The method the expression will go into
0980: *
0981: *
0982: * @exception StandardException Thrown on error
0983: */
0984:
0985: public void generateExpression(ExpressionClassBuilder acb,
0986: MethodBuilder mb) throws StandardException {
0987: if (SanityManager.DEBUG)
0988: SanityManager
0989: .ASSERT(false,
0990: "Code generation for this type of ValueNode is unimplemented");
0991: }
0992:
0993: /**
0994: * Set the correct bits in tableColMap and set the boolean value in eqOuterCols
0995: * given two arguments to an = predicate
0996: * tableColMap[t] - bit is set if the column is in an = predicate with a column
0997: * in table t, or a bit is set if the column is in an
0998: * = predicate with a constant,parameter or correlation variable
0999: * (for all table t, if this tableColMap is not for the
1000: * table with the result columns)
1001: * eqOuterCols[c] - is true if the column is in an = predicate with a constant,
1002: * parameter or correlation variable
1003: *
1004: *
1005: * @param tableColMap Array of bitmaps for noting which columns are in =
1006: * predicates with columns from each table
1007: * @param eqOuterCols Array of booleans for noting which columns
1008: * are in = predicates without columns from the
1009: * subquery block.
1010: * @param tableNumber table number for which we are setting up the Maps
1011: * @param resultTable -1 if this table is not the result table; otherwise
1012: * the index into tableNumbers for the result table
1013: * @param arg1 one side of the = predicate
1014: * @param arg2 other side of the = predicate
1015: *
1016: *
1017: * @exception StandardException Thrown on error
1018: */
1019: private void updateMaps(JBitSet[] tableColMap,
1020: boolean[] eqOuterCols, int[] tableNumbers, int tableNumber,
1021: int resultTable, ValueNode arg1, ValueNode arg2)
1022: throws StandardException {
1023: /* arg2 is a column from our table. This
1024: * is a good = for both All tables and Outer arrays
1025: * if the right side is a constant or a parameter
1026: * or a column from an outer table.
1027: * It is a good = for only the All array if
1028: * the right side is a column from this query block.
1029: */
1030: if ((arg1 instanceof ConstantNode)
1031: || (arg1.requiresTypeFromContext())) {
1032: setValueCols(tableColMap, eqOuterCols,
1033: ((ColumnReference) arg2).getColumnNumber(),
1034: resultTable);
1035: } else if ((arg1 instanceof ColumnReference && ((ColumnReference) arg1)
1036: .getTableNumber() != tableNumber)) {
1037: /* See if other columns is a correlation column */
1038: int otherTN = ((ColumnReference) arg1).getTableNumber();
1039: int index = 0;
1040: int colNumber = ((ColumnReference) arg2).getColumnNumber();
1041:
1042: for (; index < tableNumbers.length; index++) {
1043: if (otherTN == tableNumbers[index]) {
1044: break;
1045: }
1046: }
1047: /* Correlation column, so we can treat it as a constant */
1048: if (index == tableNumbers.length) {
1049: setValueCols(tableColMap, eqOuterCols, colNumber,
1050: resultTable);
1051: } else if (tableColMap != null) {
1052: tableColMap[index].set(colNumber);
1053: }
1054:
1055: } else {
1056: /* See if other side contains a column reference from the same table */
1057: JBitSet referencedTables = arg1.getTablesReferenced();
1058: /* See if other columns are all correlation columns */
1059: int index = 0;
1060: int colNumber = ((ColumnReference) arg2).getColumnNumber();
1061: for (; index < tableNumbers.length; index++) {
1062: if (referencedTables.get(tableNumbers[index])) {
1063: break;
1064: }
1065: }
1066: /* Correlation column, so we can treat it as a constant */
1067: if (index == tableNumbers.length) {
1068: setValueCols(tableColMap, eqOuterCols, colNumber,
1069: resultTable);
1070: } else if (tableColMap != null
1071: && !referencedTables.get(tableNumber)) {
1072: tableColMap[index].set(colNumber);
1073: }
1074: }
1075: }
1076:
1077: /**
1078: * Set eqOuterCols and the column in all the tables for constants,
1079: * parmeters and correlation columns
1080: * The column in the tableColMap is set only for the current table
1081: * if the table is the result column table. For other tables in the
1082: * query we set the column for all the tables since the constant will
1083: * reduced the number of columns required in a unique multicolumn index for
1084: * distinctness.
1085: * For example, given an unique index on t1(a,b), setting b=1 means that
1086: * t1(a) is unique since there can be no duplicates for a where b=1 without
1087: * destroying the uniqueness of t1(a,b). However, for the result columns
1088: * setting b=1, does not mean that a select list of t1.a is distinct if
1089: * t1.a is the only column used in joining with another table
1090: * e.g. select t1.a from t1, t2 where t1.a = t2.a and t1.b = 1;
1091: *
1092: * t1 t2 result
1093: * a b a a
1094: * 1 1 1 1
1095: * 1 2 2 1
1096: * 2 1
1097: *
1098: *
1099: * @param tableColMap Array of bitmaps for noting which columns are in =
1100: * predicates with columns from each table
1101: * @param eqOuterCols Array of booleans for noting which columns
1102: * are in = predicates without columns from the
1103: * subquery block.
1104: * @param colReference The column to set
1105: * @param resultTable If -1 set all the bit for all the tables for that
1106: * column; otherwise set the bit for the specified table
1107: *
1108: *
1109: */
1110: private void setValueCols(JBitSet[] tableColMap,
1111: boolean[] eqOuterCols, int colReference, int resultTable) {
1112: if (eqOuterCols != null)
1113: eqOuterCols[colReference] = true;
1114:
1115: if (tableColMap != null) {
1116: if (resultTable == -1) {
1117: for (int i = 0; i < tableColMap.length; i++)
1118: tableColMap[i].set(colReference);
1119: } else
1120: tableColMap[resultTable].set(colReference);
1121: }
1122: }
1123:
1124: /**
1125: * Returns true if this ValueNode is a relational operator. Relational
1126: * Operators are <, <=, =, >, >=, <> as well as IS NULL and IS NOT
1127: * NULL. This is the preferred way of figuring out if a ValueNode is
1128: * relational or not.
1129: * @see RelationalOperator
1130: * @see BinaryRelationalOperatorNode
1131: * @see IsNullNode
1132: */
1133: public boolean isRelationalOperator() {
1134: return false;
1135: }
1136:
1137: /**
1138: * Returns true if this value node is a <em>equals</em> operator.
1139: *
1140: * @see ValueNode#isRelationalOperator
1141: */
1142: public boolean isBinaryEqualsOperatorNode() {
1143: return false;
1144: }
1145:
1146: /** Return true if the predicate represents an optimizable equality node.
1147: * an expression is considered to be an optimizable equality node if all the
1148: * following conditions are met:
1149: * <ol>
1150: * <li> the operator is an <em>=</em> or <em>IS NULL</em> operator </li>
1151: * <li> one of the operands is a column specified by optTable/columnNumber</li>
1152: * <li> Both operands are not the same column; i.e tab.col = tab.col </li>
1153: * <li> There are no implicit varchar comparisons of the operands; i.e
1154: * either both operands are string like (varchar, char, longvarchar) or
1155: * neither operand is string like </li>
1156: * </ol>
1157: *
1158: * @param optTable the table being optimized. Column reference must be from
1159: * this table.
1160: * @param columnNumber the column number. One of the operands of this
1161: * predicate must be the column number specified by optTable/columnNumber
1162: * @param isNullOkay if set to true we also consider IS NULL predicates;
1163: * otherwise consider only = predicates.
1164: */
1165: public boolean optimizableEqualityNode(Optimizable optTable,
1166: int columnNumber, boolean isNullOkay)
1167: throws StandardException {
1168: return false;
1169: }
1170:
1171: /**
1172: * Returns TRUE if the type of this node will be determined from the
1173: * context in which it is getting used.
1174: *
1175: * @return Whether this node's type will be determined from the context
1176: */
1177: public boolean requiresTypeFromContext() {
1178: return false;
1179: }
1180:
1181: /**
1182: * Returns TRUE if this is a parameter node. We do lots of special things
1183: * with Parameter Nodes.
1184: *
1185: */
1186: public boolean isParameterNode() {
1187: return false;
1188: }
1189:
1190: /**
1191: * Tests if this node is equivalent to the specified ValueNode. Two
1192: * ValueNodes are considered equivalent if they will evaluate to the same
1193: * value during query execution.
1194: * <p>
1195: * This method provides basic expression matching facility for the derived
1196: * class of ValueNode and it is used by the language layer to compare the
1197: * node structural form of the two expressions for equivalence at bind
1198: * phase.
1199: * <p>
1200: * Note that it is not comparing the actual row values at runtime to produce
1201: * a result; hence, when comparing SQL NULLs, they are considered to be
1202: * equivalent and not unknown.
1203: * <p>
1204: * One usage case of this method in this context is to compare the select
1205: * column expression against the group by expression to check if they are
1206: * equivalent. e.g.:
1207: * <p>
1208: * SELECT c1+c2 FROM t1 GROUP BY c1+c2
1209: * <p>
1210: * In general, node equivalence is determined by the derived class of
1211: * ValueNode. But they generally abide to the rules below:
1212: * <ul>
1213: * <li>The two ValueNodes must be of the same node type to be considered
1214: * equivalent. e.g.: CastNode vs. CastNode - equivalent (if their args
1215: * also match), ColumnReference vs CastNode - not equivalent.
1216: *
1217: * <li>If node P contains other ValueNode(s) and so on, those node(s) must
1218: * also be of the same node type to be considered equivalent.
1219: *
1220: * <li>If node P takes a parameter list, then the number of arguments and its
1221: * arguments for the two nodes must also match to be considered
1222: * equivalent. e.g.: CAST(c1 as INTEGER) vs CAST(c1 as SMALLINT), they
1223: * are not equivalent.
1224: *
1225: * <li>When comparing SQL NULLs in this context, they are considered to be
1226: * equivalent.
1227: *
1228: * <li>If this does not apply or it is determined that the two nodes are not
1229: * equivalent then the derived class of this method should return false;
1230: * otherwise, return true.
1231: * </ul>
1232: *
1233: * @param other the node to compare this ValueNode against.
1234: * @return <code>true</code> if the two nodes are equivalent,
1235: * <code>false</code> otherwise.
1236: *
1237: * @throws StandardException
1238: */
1239: protected abstract boolean isEquivalent(ValueNode other)
1240: throws StandardException;
1241:
1242: /**
1243: * Tests if this node is of the same type as the specified node as
1244: * reported by {@link QueryTreeNode#getNodeType()}.
1245: *
1246: * @param other the node to compare this value node against.
1247: *
1248: * @return <code>true</code> if the two nodes are of the same type.
1249: */
1250: protected final boolean isSameNodeType(ValueNode other) {
1251: if (other != null) {
1252: return other.getNodeType() == getNodeType();
1253: }
1254: return false;
1255: }
1256:
1257: }
|