--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.compile.BetweenOperatorNode\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.sql.compile;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+\r
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;\r
+\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;\r
+import org.apache.derby.impl.sql.compile.ActivationClassBuilder;\r
+import org.apache.derby.iapi.sql.compile.NodeFactory;\r
+import org.apache.derby.iapi.services.context.ContextManager;\r
+\r
+/**\r
+ * A BetweenOperatorNode represents a BETWEEN clause. The between values are\r
+ * represented as a 2 element list in order to take advantage of code reuse.\r
+ *\r
+ */\r
+\r
+public class BetweenOperatorNode extends BinaryListOperatorNode\r
+{\r
+ /**\r
+ * Initializer for a BetweenOperatorNode\r
+ *\r
+ * @param leftOperand The left operand of the node\r
+ * @param betweenValues The between values in list form\r
+ */\r
+\r
+ public void init(Object leftOperand, Object betweenValues)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ ValueNodeList betweenVals = (ValueNodeList) betweenValues;\r
+\r
+ SanityManager.ASSERT(betweenVals.size() == 2,\r
+ "betweenValues.size() (" +\r
+ betweenVals.size() +\r
+ ") is expected to be 2");\r
+ }\r
+\r
+ super.init(leftOperand, betweenValues, "BETWEEN", null);\r
+ }\r
+\r
+ /**\r
+ * Eliminate NotNodes in the current query block. We traverse the tree, \r
+ * inverting ANDs and ORs and eliminating NOTs as we go. We stop at \r
+ * ComparisonOperators and boolean expressions. We invert \r
+ * ComparisonOperators and replace boolean expressions with \r
+ * boolean expression = false.\r
+ * NOTE: Since we do not recurse under ComparisonOperators, there\r
+ * still could be NotNodes left in the tree.\r
+ *\r
+ * @param underNotNode Whether or not we are under a NotNode.\r
+ * \r
+ *\r
+ * @return The modified expression\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ ValueNode eliminateNots(boolean underNotNode) \r
+ throws StandardException\r
+ {\r
+ BinaryComparisonOperatorNode leftBCO;\r
+ BinaryComparisonOperatorNode rightBCO;\r
+ OrNode newOr;\r
+\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(rightOperandList.size() == 2,\r
+ "rightOperandList.size() (" +\r
+ rightOperandList.size() +\r
+ ") is expected to be 2");\r
+\r
+ if (! underNotNode)\r
+ {\r
+ return this;\r
+ }\r
+\r
+ /* we want to convert the BETWEEN * into < OR > \r
+ as described below.\r
+ */ \r
+\r
+ /* Convert:\r
+ * leftO between rightOList.elementAt(0) and rightOList.elementAt(1)\r
+ * to:\r
+ * leftO < rightOList.elementAt(0) or leftO > rightOList.elementAt(1)\r
+ * NOTE - We do the conversion here since ORs will eventually be\r
+ * optimizable and there's no benefit for the optimizer to see NOT BETWEEN\r
+ */\r
+\r
+ NodeFactory nodeFactory = getNodeFactory();\r
+ ContextManager cm = getContextManager();\r
+\r
+ /* leftO < rightOList.elementAt(0) */\r
+ leftBCO = (BinaryComparisonOperatorNode) \r
+ nodeFactory.getNode(\r
+ C_NodeTypes.BINARY_LESS_THAN_OPERATOR_NODE,\r
+ leftOperand, \r
+ rightOperandList.elementAt(0),\r
+ cm);\r
+ /* Set type info for the operator node */\r
+ leftBCO.bindComparisonOperator();\r
+\r
+ /* leftO > rightOList.elementAt(1) */\r
+ rightBCO = (BinaryComparisonOperatorNode) \r
+ nodeFactory.getNode(\r
+ C_NodeTypes.BINARY_GREATER_THAN_OPERATOR_NODE,\r
+ leftOperand, \r
+ rightOperandList.elementAt(1),\r
+ cm);\r
+ /* Set type info for the operator node */\r
+ rightBCO.bindComparisonOperator();\r
+\r
+ /* Create and return the OR */\r
+ newOr = (OrNode) nodeFactory.getNode(\r
+ C_NodeTypes.OR_NODE,\r
+ leftBCO,\r
+ rightBCO,\r
+ cm);\r
+ newOr.postBindFixup();\r
+\r
+ /* Tell optimizer to use the between selectivity instead of >= * <= selectivities */\r
+ leftBCO.setBetweenSelectivity();\r
+ rightBCO.setBetweenSelectivity();\r
+\r
+ return newOr;\r
+ }\r
+\r
+ /**\r
+ * Preprocess an expression tree. We do a number of transformations\r
+ * here (including subqueries, IN lists, LIKE and BETWEEN) plus\r
+ * subquery flattening.\r
+ * NOTE: This is done before the outer ResultSetNode is preprocessed.\r
+ *\r
+ * @param numTables Number of tables in the DML Statement\r
+ * @param outerFromList FromList from outer query block\r
+ * @param outerSubqueryList SubqueryList from outer query block\r
+ * @param outerPredicateList PredicateList from outer query block\r
+ *\r
+ * @return The modified expression\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public ValueNode preprocess(int numTables,\r
+ FromList outerFromList,\r
+ SubqueryList outerSubqueryList,\r
+ PredicateList outerPredicateList) \r
+ throws StandardException\r
+ {\r
+ ValueNode leftClone1;\r
+ ValueNode rightOperand;\r
+\r
+ /* We must 1st preprocess the component parts */\r
+ super.preprocess(numTables,\r
+ outerFromList, outerSubqueryList,\r
+ outerPredicateList);\r
+\r
+ /* This is where we do the transformation for BETWEEN to make it optimizable.\r
+ * c1 BETWEEN value1 AND value2 -> c1 >= value1 AND c1 <= value2\r
+ * This transformation is only done if the leftOperand is a ColumnReference.\r
+ */\r
+ if (!(leftOperand instanceof ColumnReference))\r
+ {\r
+ return this;\r
+ }\r
+\r
+ /* For some unknown reason we need to clone the leftOperand if it is\r
+ * a ColumnReference because reusing them in Qualifiers for a scan\r
+ * does not work. \r
+ */\r
+ leftClone1 = leftOperand.getClone();\r
+\r
+ /* The transformed tree has to be normalized:\r
+ * AND\r
+ * / \\r
+ * >= AND\r
+ * / \\r
+ * <= TRUE\r
+ */\r
+\r
+ NodeFactory nodeFactory = getNodeFactory();\r
+ ContextManager cm = getContextManager();\r
+\r
+ QueryTreeNode trueNode = nodeFactory.getNode(\r
+ C_NodeTypes.BOOLEAN_CONSTANT_NODE,\r
+ Boolean.TRUE,\r
+ cm);\r
+\r
+ /* Create the AND <= */\r
+ BinaryComparisonOperatorNode lessEqual = \r
+ (BinaryComparisonOperatorNode) nodeFactory.getNode(\r
+ C_NodeTypes.BINARY_LESS_EQUALS_OPERATOR_NODE,\r
+ leftClone1, \r
+ rightOperandList.elementAt(1),\r
+ cm);\r
+\r
+ /* Set type info for the operator node */\r
+ lessEqual.bindComparisonOperator();\r
+\r
+ /* Create the AND */\r
+ AndNode newAnd = (AndNode) nodeFactory.getNode(\r
+ C_NodeTypes.AND_NODE,\r
+ lessEqual,\r
+ trueNode,\r
+ cm);\r
+ newAnd.postBindFixup();\r
+\r
+ /* Create the AND >= */\r
+ BinaryComparisonOperatorNode greaterEqual = \r
+ (BinaryComparisonOperatorNode) nodeFactory.getNode(\r
+ C_NodeTypes.BINARY_GREATER_EQUALS_OPERATOR_NODE,\r
+ leftOperand, \r
+ rightOperandList.elementAt(0),\r
+ cm);\r
+\r
+ /* Set type info for the operator node */\r
+ greaterEqual.bindComparisonOperator();\r
+\r
+ /* Create the AND */\r
+ newAnd = (AndNode) nodeFactory.getNode(\r
+ C_NodeTypes.AND_NODE,\r
+ greaterEqual,\r
+ newAnd,\r
+ cm);\r
+ newAnd.postBindFixup();\r
+\r
+ /* Tell optimizer to use the between selectivity instead of >= * <= selectivities */\r
+ lessEqual.setBetweenSelectivity();\r
+ greaterEqual.setBetweenSelectivity();\r
+\r
+ return newAnd;\r
+ }\r
+ \r
+ /**\r
+ * Do code generation for this BETWEEN operator.\r
+ *\r
+ * @param acb The ExpressionClassBuilder for the class we're generating\r
+ * @param mb The method the code to place the code\r
+ *\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ public void generateExpression(ExpressionClassBuilder acb,\r
+ MethodBuilder mb)\r
+ throws StandardException\r
+ {\r
+ AndNode newAnd;\r
+ BinaryComparisonOperatorNode leftBCO;\r
+ BinaryComparisonOperatorNode rightBCO;\r
+\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(rightOperandList.size() == 2,\r
+ "rightOperandList.size() (" +\r
+ rightOperandList.size() +\r
+ ") is expected to be 2");\r
+\r
+ /* Convert:\r
+ * leftO between rightOList.elementAt(0) and rightOList.elementAt(1)\r
+ * to:\r
+ * leftO >= rightOList.elementAt(0) and leftO <= rightOList.elementAt(1) \r
+ */\r
+\r
+ NodeFactory nodeFactory = getNodeFactory();\r
+ ContextManager cm = getContextManager();\r
+\r
+ /* leftO >= rightOList.elementAt(0) */\r
+ leftBCO = (BinaryComparisonOperatorNode) \r
+ nodeFactory.getNode(\r
+ C_NodeTypes.BINARY_GREATER_EQUALS_OPERATOR_NODE,\r
+ leftOperand, \r
+ rightOperandList.elementAt(0),\r
+ cm);\r
+ /* Set type info for the operator node */\r
+ leftBCO.bindComparisonOperator();\r
+\r
+ /* leftO <= rightOList.elementAt(1) */\r
+ rightBCO = (BinaryComparisonOperatorNode) \r
+ nodeFactory.getNode(\r
+ C_NodeTypes.BINARY_LESS_EQUALS_OPERATOR_NODE,\r
+ leftOperand, \r
+ rightOperandList.elementAt(1),\r
+ cm);\r
+ /* Set type info for the operator node */\r
+ rightBCO.bindComparisonOperator();\r
+\r
+ /* Create and return the AND */\r
+ newAnd = (AndNode) nodeFactory.getNode(\r
+ C_NodeTypes.AND_NODE,\r
+ leftBCO,\r
+ rightBCO,\r
+ cm);\r
+ newAnd.postBindFixup();\r
+ newAnd.generateExpression(acb, mb);\r
+ }\r
+}\r