001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.BinaryListOperatorNode
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.compile;
023:
024: import org.apache.derby.iapi.error.StandardException;
025:
026: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
027:
028: import org.apache.derby.iapi.reference.SQLState;
029:
030: import org.apache.derby.iapi.types.DataTypeDescriptor;
031: import org.apache.derby.iapi.types.TypeId;
032: import org.apache.derby.iapi.sql.compile.Visitor;
033: import org.apache.derby.iapi.sql.compile.Visitable;
034:
035: import org.apache.derby.iapi.services.sanity.SanityManager;
036:
037: import org.apache.derby.iapi.store.access.Qualifier;
038:
039: import org.apache.derby.iapi.util.JBitSet;
040:
041: import java.util.Vector;
042:
043: /**
044: * A BinaryListOperatorNode represents a built-in "binary" operator with a single
045: * operand on the left of the operator and a list of operands on the right.
046: * This covers operators such as IN and BETWEEN.
047: *
048: * @author Jerry Brenner
049: */
050:
051: public abstract class BinaryListOperatorNode extends ValueNode {
052: String methodName;
053: /* operator used for error messages */
054: String operator;
055:
056: String leftInterfaceType;
057: String rightInterfaceType;
058:
059: ValueNode receiver; // used in generation
060: ValueNode leftOperand;
061: ValueNodeList rightOperandList;
062:
063: /**
064: * Initializer for a BinaryListOperatorNode
065: *
066: * @param leftOperand The left operand of the node
067: * @param rightOperandList The right operand list of the node
068: * @param operator String representation of operator
069: */
070:
071: public void init(Object leftOperand, Object rightOperandList,
072: Object operator, Object methodName) {
073: this .leftOperand = (ValueNode) leftOperand;
074: this .rightOperandList = (ValueNodeList) rightOperandList;
075: this .operator = (String) operator;
076: this .methodName = (String) methodName;
077: }
078:
079: /**
080: * Convert this object to a String. See comments in QueryTreeNode.java
081: * for how this should be done for tree printing.
082: *
083: * @return This object as a String
084: */
085:
086: public String toString() {
087: if (SanityManager.DEBUG) {
088: return "operator: " + operator + "\n" + "methodName: "
089: + methodName + "\n" + super .toString();
090: } else {
091: return "";
092: }
093: }
094:
095: /**
096: * Prints the sub-nodes of this object. See QueryTreeNode.java for
097: * how tree printing is supposed to work.
098: *
099: * @param depth The depth of this node in the tree
100: */
101:
102: public void printSubNodes(int depth) {
103: if (SanityManager.DEBUG) {
104: super .printSubNodes(depth);
105:
106: if (leftOperand != null) {
107: printLabel(depth, "leftOperand: ");
108: leftOperand.treePrint(depth + 1);
109: }
110:
111: if (rightOperandList != null) {
112: printLabel(depth, "rightOperandList: ");
113: rightOperandList.treePrint(depth + 1);
114: }
115: }
116: }
117:
118: /**
119: * Set the clause that this node appears in.
120: *
121: * @param clause The clause that this node appears in.
122: */
123: public void setClause(int clause) {
124: super .setClause(clause);
125: leftOperand.setClause(clause);
126: rightOperandList.setClause(clause);
127: }
128:
129: /**
130: * Bind this expression. This means binding the sub-expressions,
131: * as well as figuring out what the return type is for this expression.
132: *
133: * @param fromList The FROM list for the query this
134: * expression is in, for binding columns.
135: * @param subqueryList The subquery list being built as we find SubqueryNodes
136: * @param aggregateVector The aggregate vector being built as we find AggregateNodes
137: *
138: * @return The new top of the expression tree.
139: *
140: * @exception StandardException Thrown on error
141: */
142:
143: public ValueNode bindExpression(FromList fromList,
144: SubqueryList subqueryList, Vector aggregateVector)
145: throws StandardException {
146: leftOperand = leftOperand.bindExpression(fromList,
147: subqueryList, aggregateVector);
148: rightOperandList.bindExpression(fromList, subqueryList,
149: aggregateVector);
150:
151: /* Is there a ? parameter on the left? */
152: if (leftOperand.requiresTypeFromContext()) {
153: ValueNode rightOperand = (ValueNode) rightOperandList
154: .elementAt(0);
155:
156: /*
157: ** It's an error if both operands are all ? parameters.
158: */
159: if (rightOperandList.containsAllParameterNodes()) {
160: throw StandardException.newException(
161: SQLState.LANG_BINARY_OPERANDS_BOTH_PARMS,
162: operator);
163: }
164:
165: /* Set the left operand to the type of right parameter. */
166: leftOperand.setType(rightOperandList.getTypeServices());
167: }
168:
169: /* Is there a ? parameter on the right? */
170: if (rightOperandList.containsParameterNode()) {
171: /* Set the right operand to the type of the left parameter. */
172: rightOperandList.setParameterDescriptor(leftOperand
173: .getTypeServices());
174: }
175:
176: /* If the left operand is not a built-in type, then generate a conversion
177: * tree to a built-in type.
178: */
179: if (leftOperand.getTypeId().userType()) {
180: leftOperand = leftOperand.genSQLJavaSQLTree();
181: }
182:
183: /* Generate bound conversion trees for those elements in the rightOperandList
184: * that are not built-in types.
185: */
186: rightOperandList.genSQLJavaSQLTrees();
187:
188: /* Test type compatability and set type info for this node */
189: bindComparisonOperator();
190:
191: return this ;
192: }
193:
194: /**
195: * Test the type compatability of the operands and set the type info
196: * for this node. This method is useful both during binding and
197: * when we generate nodes within the language module outside of the parser.
198: *
199: * @exception StandardException Thrown on error
200: */
201: public void bindComparisonOperator() throws StandardException {
202: boolean nullableResult;
203:
204: /* Can the types be compared to each other? */
205: rightOperandList.comparable(leftOperand);
206:
207: /*
208: ** Set the result type of this comparison operator based on the
209: ** operands. The result type is always SQLBoolean - the only question
210: ** is whether it is nullable or not. If either the leftOperand or
211: ** any of the elements in the rightOperandList is
212: ** nullable, the result of the comparison must be nullable, too, so
213: ** we can represent the unknown truth value.
214: */
215: nullableResult = leftOperand.getTypeServices().isNullable()
216: || rightOperandList.isNullable();
217: setType(new DataTypeDescriptor(TypeId.BOOLEAN_ID,
218: nullableResult));
219: }
220:
221: /**
222: * Preprocess an expression tree. We do a number of transformations
223: * here (including subqueries, IN lists, LIKE and BETWEEN) plus
224: * subquery flattening.
225: * NOTE: This is done before the outer ResultSetNode is preprocessed.
226: *
227: * @param numTables Number of tables in the DML Statement
228: * @param outerFromList FromList from outer query block
229: * @param outerSubqueryList SubqueryList from outer query block
230: * @param outerPredicateList PredicateList from outer query block
231: *
232: * @return The modified expression
233: *
234: * @exception StandardException Thrown on error
235: */
236: public ValueNode preprocess(int numTables, FromList outerFromList,
237: SubqueryList outerSubqueryList,
238: PredicateList outerPredicateList) throws StandardException {
239: leftOperand = leftOperand.preprocess(numTables, outerFromList,
240: outerSubqueryList, outerPredicateList);
241: rightOperandList.preprocess(numTables, outerFromList,
242: outerSubqueryList, outerPredicateList);
243: return this ;
244: }
245:
246: /**
247: * Set the leftOperand to the specified ValueNode
248: *
249: * @param newLeftOperand The new leftOperand
250: */
251: public void setLeftOperand(ValueNode newLeftOperand) {
252: leftOperand = newLeftOperand;
253: }
254:
255: /**
256: * Get the leftOperand
257: *
258: * @return The current leftOperand.
259: */
260: public ValueNode getLeftOperand() {
261: return leftOperand;
262: }
263:
264: /**
265: * Set the rightOperandList to the specified ValueNodeList
266: *
267: * @param newRightOperandList The new rightOperandList
268: *
269: */
270: public void setRightOperandList(ValueNodeList newRightOperandList) {
271: rightOperandList = newRightOperandList;
272: }
273:
274: /**
275: * Get the rightOperandList
276: *
277: * @return The current rightOperandList.
278: */
279: public ValueNodeList getRightOperandList() {
280: return rightOperandList;
281: }
282:
283: /**
284: * Categorize this predicate. Initially, this means
285: * building a bit map of the referenced tables for each predicate.
286: * If the source of this ColumnReference (at the next underlying level)
287: * is not a ColumnReference or a VirtualColumnNode then this predicate
288: * will not be pushed down.
289: *
290: * For example, in:
291: * select * from (select 1 from s) a (x) where x = 1
292: * we will not push down x = 1.
293: * NOTE: It would be easy to handle the case of a constant, but if the
294: * inner SELECT returns an arbitrary expression, then we would have to copy
295: * that tree into the pushed predicate, and that tree could contain
296: * subqueries and method calls.
297: * RESOLVE - revisit this issue once we have views.
298: *
299: * @param referencedTabs JBitSet with bit map of referenced FromTables
300: * @param simplePredsOnly Whether or not to consider method
301: * calls, field references and conditional nodes
302: * when building bit map
303: *
304: * @return boolean Whether or not source.expression is a ColumnReference
305: * or a VirtualColumnNode.
306: * @exception StandardException Thrown on error
307: */
308: public boolean categorize(JBitSet referencedTabs,
309: boolean simplePredsOnly) throws StandardException {
310: boolean pushable;
311: pushable = leftOperand.categorize(referencedTabs,
312: simplePredsOnly);
313: pushable = (rightOperandList.categorize(referencedTabs,
314: simplePredsOnly) && pushable);
315: return pushable;
316: }
317:
318: /**
319: * Remap all ColumnReferences in this tree to be clones of the
320: * underlying expression.
321: *
322: * @return ValueNode The remapped expression tree.
323: *
324: * @exception StandardException Thrown on error
325: */
326: public ValueNode remapColumnReferencesToExpressions()
327: throws StandardException {
328: // we need to assign back because a new object may be returned, beetle 4983
329: leftOperand = leftOperand.remapColumnReferencesToExpressions();
330: rightOperandList.remapColumnReferencesToExpressions();
331: return this ;
332: }
333:
334: /**
335: * Return whether or not this expression tree represents a constant expression.
336: *
337: * @return Whether or not this expression tree represents a constant expression.
338: */
339: public boolean isConstantExpression() {
340: return (leftOperand.isConstantExpression() && rightOperandList
341: .isConstantExpression());
342: }
343:
344: /** @see ValueNode#constantExpression */
345: public boolean constantExpression(PredicateList whereClause) {
346: return (leftOperand.constantExpression(whereClause) && rightOperandList
347: .constantExpression(whereClause));
348: }
349:
350: /**
351: * Return the variant type for the underlying expression.
352: * The variant type can be:
353: * VARIANT - variant within a scan
354: * (method calls and non-static field access)
355: * SCAN_INVARIANT - invariant within a scan
356: * (column references from outer tables)
357: * QUERY_INVARIANT - invariant within the life of a query
358: * CONSTANT - immutable
359: *
360: * @return The variant type for the underlying expression.
361: * @exception StandardException thrown on error
362: */
363: protected int getOrderableVariantType() throws StandardException {
364: int leftType = leftOperand.getOrderableVariantType();
365: int rightType = rightOperandList.getOrderableVariantType();
366:
367: return Math.min(leftType, rightType);
368: }
369:
370: /**
371: * Accept a visitor, and call v.visit()
372: * on child nodes as necessary.
373: *
374: * @param v the visitor
375: *
376: * @exception StandardException on error
377: */
378: public Visitable accept(Visitor v) throws StandardException {
379: Visitable returnNode = v.visit(this );
380:
381: if (v.skipChildren(this )) {
382: return returnNode;
383: }
384:
385: if (leftOperand != null && !v.stopTraversal()) {
386: leftOperand = (ValueNode) leftOperand.accept(v);
387: }
388:
389: if (rightOperandList != null && !v.stopTraversal()) {
390: rightOperandList = (ValueNodeList) rightOperandList
391: .accept(v);
392: }
393:
394: return returnNode;
395: }
396:
397: /**
398: * @inheritDoc
399: */
400: protected boolean isEquivalent(ValueNode o)
401: throws StandardException {
402: if (!isSameNodeType(o)) {
403: return false;
404: }
405: BinaryListOperatorNode other = (BinaryListOperatorNode) o;
406: if (!operator.equals(other.operator)
407: || !leftOperand.isEquivalent(other.getLeftOperand())) {
408: return false;
409: }
410:
411: int sz = getRightOperandList().size();
412: if (sz != other.rightOperandList.size()) {
413: return false;
414: }
415: for (int i = 0; i < sz; i++) {
416: ValueNode e = (ValueNode) rightOperandList.elementAt(i);
417: if (!e.isEquivalent((ValueNode) other.rightOperandList
418: .elementAt(i))) {
419: return false;
420: }
421: }
422: return true;
423: }
424: }
|