001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.BetweenOperatorNode
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.conn.LanguageConnectionContext;
027:
028: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
029:
030: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
031:
032: import org.apache.derby.iapi.services.compiler.MethodBuilder;
033:
034: import org.apache.derby.iapi.services.sanity.SanityManager;
035:
036: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
037: import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
038: import org.apache.derby.iapi.sql.compile.NodeFactory;
039: import org.apache.derby.iapi.services.context.ContextManager;
040:
041: /**
042: * A BetweenOperatorNode represents a BETWEEN clause. The between values are
043: * represented as a 2 element list in order to take advantage of code reuse.
044: *
045: * @author Jerry Brenner
046: */
047:
048: public class BetweenOperatorNode extends BinaryListOperatorNode {
049: /**
050: * Initializer for a BetweenOperatorNode
051: *
052: * @param leftOperand The left operand of the node
053: * @param betweenValues The between values in list form
054: */
055:
056: public void init(Object leftOperand, Object betweenValues) {
057: if (SanityManager.DEBUG) {
058: ValueNodeList betweenVals = (ValueNodeList) betweenValues;
059:
060: SanityManager.ASSERT(betweenVals.size() == 2,
061: "betweenValues.size() (" + betweenVals.size()
062: + ") is expected to be 2");
063: }
064:
065: super .init(leftOperand, betweenValues, "BETWEEN", null);
066: }
067:
068: /**
069: * Eliminate NotNodes in the current query block. We traverse the tree,
070: * inverting ANDs and ORs and eliminating NOTs as we go. We stop at
071: * ComparisonOperators and boolean expressions. We invert
072: * ComparisonOperators and replace boolean expressions with
073: * boolean expression = false.
074: * NOTE: Since we do not recurse under ComparisonOperators, there
075: * still could be NotNodes left in the tree.
076: *
077: * @param underNotNode Whether or not we are under a NotNode.
078: *
079: *
080: * @return The modified expression
081: *
082: * @exception StandardException Thrown on error
083: */
084: ValueNode eliminateNots(boolean underNotNode)
085: throws StandardException {
086: BinaryComparisonOperatorNode leftBCO;
087: BinaryComparisonOperatorNode rightBCO;
088: OrNode newOr;
089:
090: if (SanityManager.DEBUG)
091: SanityManager.ASSERT(rightOperandList.size() == 2,
092: "rightOperandList.size() ("
093: + rightOperandList.size()
094: + ") is expected to be 2");
095:
096: if (!underNotNode) {
097: return this ;
098: }
099:
100: /* we want to convert the BETWEEN * into < OR >
101: as described below.
102: */
103:
104: /* Convert:
105: * leftO between rightOList.elementAt(0) and rightOList.elementAt(1)
106: * to:
107: * leftO < rightOList.elementAt(0) or leftO > rightOList.elementAt(1)
108: * NOTE - We do the conversion here since ORs will eventually be
109: * optimizable and there's no benefit for the optimizer to see NOT BETWEEN
110: */
111:
112: NodeFactory nodeFactory = getNodeFactory();
113: ContextManager cm = getContextManager();
114:
115: /* leftO < rightOList.elementAt(0) */
116: leftBCO = (BinaryComparisonOperatorNode) nodeFactory.getNode(
117: C_NodeTypes.BINARY_LESS_THAN_OPERATOR_NODE,
118: leftOperand, rightOperandList.elementAt(0), cm);
119: /* Set type info for the operator node */
120: leftBCO.bindComparisonOperator();
121:
122: /* leftO > rightOList.elementAt(1) */
123: rightBCO = (BinaryComparisonOperatorNode) nodeFactory.getNode(
124: C_NodeTypes.BINARY_GREATER_THAN_OPERATOR_NODE,
125: leftOperand, rightOperandList.elementAt(1), cm);
126: /* Set type info for the operator node */
127: rightBCO.bindComparisonOperator();
128:
129: /* Create and return the OR */
130: newOr = (OrNode) nodeFactory.getNode(C_NodeTypes.OR_NODE,
131: leftBCO, rightBCO, cm);
132: newOr.postBindFixup();
133:
134: /* Tell optimizer to use the between selectivity instead of >= * <= selectivities */
135: leftBCO.setBetweenSelectivity();
136: rightBCO.setBetweenSelectivity();
137:
138: return newOr;
139: }
140:
141: /**
142: * Preprocess an expression tree. We do a number of transformations
143: * here (including subqueries, IN lists, LIKE and BETWEEN) plus
144: * subquery flattening.
145: * NOTE: This is done before the outer ResultSetNode is preprocessed.
146: *
147: * @param numTables Number of tables in the DML Statement
148: * @param outerFromList FromList from outer query block
149: * @param outerSubqueryList SubqueryList from outer query block
150: * @param outerPredicateList PredicateList from outer query block
151: *
152: * @return The modified expression
153: *
154: * @exception StandardException Thrown on error
155: */
156: public ValueNode preprocess(int numTables, FromList outerFromList,
157: SubqueryList outerSubqueryList,
158: PredicateList outerPredicateList) throws StandardException {
159: ValueNode leftClone1;
160: ValueNode rightOperand;
161:
162: /* We must 1st preprocess the component parts */
163: super .preprocess(numTables, outerFromList, outerSubqueryList,
164: outerPredicateList);
165:
166: /* This is where we do the transformation for BETWEEN to make it optimizable.
167: * c1 BETWEEN value1 AND value2 -> c1 >= value1 AND c1 <= value2
168: * This transformation is only done if the leftOperand is a ColumnReference.
169: */
170: if (!(leftOperand instanceof ColumnReference)) {
171: return this ;
172: }
173:
174: /* For some unknown reason we need to clone the leftOperand if it is
175: * a ColumnReference because reusing them in Qualifiers for a scan
176: * does not work.
177: */
178: leftClone1 = leftOperand.getClone();
179:
180: /* The transformed tree has to be normalized:
181: * AND
182: * / \
183: * >= AND
184: * / \
185: * <= TRUE
186: */
187:
188: NodeFactory nodeFactory = getNodeFactory();
189: ContextManager cm = getContextManager();
190:
191: QueryTreeNode trueNode = nodeFactory.getNode(
192: C_NodeTypes.BOOLEAN_CONSTANT_NODE, Boolean.TRUE, cm);
193:
194: /* Create the AND <= */
195: BinaryComparisonOperatorNode lessEqual = (BinaryComparisonOperatorNode) nodeFactory
196: .getNode(C_NodeTypes.BINARY_LESS_EQUALS_OPERATOR_NODE,
197: leftClone1, rightOperandList.elementAt(1), cm);
198:
199: /* Set type info for the operator node */
200: lessEqual.bindComparisonOperator();
201:
202: /* Create the AND */
203: AndNode newAnd = (AndNode) nodeFactory.getNode(
204: C_NodeTypes.AND_NODE, lessEqual, trueNode, cm);
205: newAnd.postBindFixup();
206:
207: /* Create the AND >= */
208: BinaryComparisonOperatorNode greaterEqual = (BinaryComparisonOperatorNode) nodeFactory
209: .getNode(
210: C_NodeTypes.BINARY_GREATER_EQUALS_OPERATOR_NODE,
211: leftOperand, rightOperandList.elementAt(0), cm);
212:
213: /* Set type info for the operator node */
214: greaterEqual.bindComparisonOperator();
215:
216: /* Create the AND */
217: newAnd = (AndNode) nodeFactory.getNode(C_NodeTypes.AND_NODE,
218: greaterEqual, newAnd, cm);
219: newAnd.postBindFixup();
220:
221: /* Tell optimizer to use the between selectivity instead of >= * <= selectivities */
222: lessEqual.setBetweenSelectivity();
223: greaterEqual.setBetweenSelectivity();
224:
225: return newAnd;
226: }
227:
228: /**
229: * Do code generation for this BETWEEN operator.
230: *
231: * @param acb The ExpressionClassBuilder for the class we're generating
232: * @param mb The method the code to place the code
233: *
234: *
235: * @exception StandardException Thrown on error
236: */
237:
238: public void generateExpression(ExpressionClassBuilder acb,
239: MethodBuilder mb) throws StandardException {
240: AndNode newAnd;
241: BinaryComparisonOperatorNode leftBCO;
242: BinaryComparisonOperatorNode rightBCO;
243:
244: if (SanityManager.DEBUG)
245: SanityManager.ASSERT(rightOperandList.size() == 2,
246: "rightOperandList.size() ("
247: + rightOperandList.size()
248: + ") is expected to be 2");
249:
250: /* Convert:
251: * leftO between rightOList.elementAt(0) and rightOList.elementAt(1)
252: * to:
253: * leftO >= rightOList.elementAt(0) and leftO <= rightOList.elementAt(1)
254: */
255:
256: NodeFactory nodeFactory = getNodeFactory();
257: ContextManager cm = getContextManager();
258:
259: /* leftO >= rightOList.elementAt(0) */
260: leftBCO = (BinaryComparisonOperatorNode) nodeFactory.getNode(
261: C_NodeTypes.BINARY_GREATER_EQUALS_OPERATOR_NODE,
262: leftOperand, rightOperandList.elementAt(0), cm);
263: /* Set type info for the operator node */
264: leftBCO.bindComparisonOperator();
265:
266: /* leftO <= rightOList.elementAt(1) */
267: rightBCO = (BinaryComparisonOperatorNode) nodeFactory.getNode(
268: C_NodeTypes.BINARY_LESS_EQUALS_OPERATOR_NODE,
269: leftOperand, rightOperandList.elementAt(1), cm);
270: /* Set type info for the operator node */
271: rightBCO.bindComparisonOperator();
272:
273: /* Create and return the AND */
274: newAnd = (AndNode) nodeFactory.getNode(C_NodeTypes.AND_NODE,
275: leftBCO, rightBCO, cm);
276: newAnd.postBindFixup();
277: newAnd.generateExpression(acb, mb);
278: }
279: }
|