--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.compile.BinaryLogicalOperatorNode\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.sql.dictionary.DataDictionary;\r
+\r
+import org.apache.derby.iapi.types.BooleanDataValue;\r
+import org.apache.derby.iapi.types.TypeId;\r
+\r
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+import org.apache.derby.iapi.services.compiler.LocalField;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.reference.ClassName;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+\r
+import java.lang.reflect.Modifier;\r
+import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;\r
+import org.apache.derby.impl.sql.compile.ActivationClassBuilder;\r
+import org.apache.derby.iapi.services.classfile.VMOpcode;\r
+\r
+import java.util.Vector;\r
+\r
+abstract class BinaryLogicalOperatorNode extends BinaryOperatorNode\r
+{\r
+ boolean shortCircuitValue;\r
+\r
+ /**\r
+ * Initializer for a BinaryLogicalOperatorNode\r
+ *\r
+ * @param leftOperand The left operand of the comparison\r
+ * @param rightOperand The right operand of the comparison\r
+ * @param methodName The name of the method to call in the generated\r
+ * class. In this case, it's actually an operator\r
+ * name.\r
+ */\r
+\r
+ public void init(\r
+ Object leftOperand,\r
+ Object rightOperand,\r
+ Object methodName)\r
+ {\r
+ /* For logical operators, the operator and method names are the same */\r
+ super.init(leftOperand, rightOperand, methodName, methodName,\r
+ ClassName.BooleanDataValue, ClassName.BooleanDataValue);\r
+ }\r
+\r
+ /**\r
+ * Bind this logical operator. All that has to be done for binding\r
+ * a logical operator is to bind the operands, check that both operands\r
+ * are BooleanDataValue, and set the result type to BooleanDataValue.\r
+ *\r
+ * @param fromList The query's FROM list\r
+ * @param subqueryList The subquery list being built as we find SubqueryNodes\r
+ * @param aggregateVector The aggregate vector being built as we find AggregateNodes\r
+ *\r
+ * @return The new top of the expression tree.\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ public ValueNode bindExpression(\r
+ FromList fromList, SubqueryList subqueryList,\r
+ Vector aggregateVector)\r
+ throws StandardException\r
+ {\r
+ //following is to check if we have something like "? AND 1=1" or "2>1 OR ?" \r
+ if (leftOperand.isParameterNode() || rightOperand.isParameterNode())\r
+ throw StandardException.newException(SQLState.LANG_NON_BOOLEAN_WHERE_CLAUSE, "PARAMETER" );\r
+\r
+ super.bindExpression(fromList, subqueryList, aggregateVector);\r
+\r
+ return this;\r
+ }\r
+\r
+ /**\r
+ * Verify that eliminateNots() did its job correctly. Verify that\r
+ * there are no NotNodes above the top level comparison operators\r
+ * and boolean expressions.\r
+ *\r
+ * @return Boolean which reflects validity of the tree.\r
+ */\r
+ boolean verifyEliminateNots()\r
+ {\r
+ if (SanityManager.ASSERT)\r
+ {\r
+ return (leftOperand.verifyEliminateNots() &&\r
+ rightOperand.verifyEliminateNots());\r
+ }\r
+ else\r
+ {\r
+ return true;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Do code generation for this logical binary operator.\r
+ * This is used for AND and OR. the IsNode extends this class but\r
+ * overrides generateExpression.\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
+ /*\r
+ ** This generates the following code:\r
+ **\r
+ ** (<leftOperand>.equals(shortCircuitValue) ?\r
+ ** <leftOperand> :\r
+ ** <leftOperand>.<and/or>(<rightOperand>)\r
+ **\r
+ ** The ?: operator accomplishes the short-circuiting. We save the\r
+ ** value of the left operand on the stack so we don't have to evaluate\r
+ ** it twice.\r
+ **\r
+ ** The BooleanDataValue.{and,or} methods return an immutable BooleanDataValue\r
+ ** and an immutable BooleanDataValue is returned by this generated code in\r
+ ** the short circuit case.\r
+ */\r
+\r
+ /*\r
+ ** See whether the left operand equals the short-circuit value.\r
+ ** Generated code is:\r
+ ** .equals(shortCircuitValue)\r
+ */\r
+\r
+ leftOperand.generateExpression(acb, mb);\r
+ // stack - left\r
+\r
+ // put an extra left of the stack for potential\r
+ // use in the else clause.\r
+ mb.dup();\r
+ // stack - left, left\r
+ mb.push(shortCircuitValue);\r
+ // stack - left, left, shortcircuit\r
+ mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "equals", "boolean", 1);\r
+ // stack left, result\r
+\r
+ /*\r
+ ** Generate the if expression. This is what accomplishes\r
+ ** short-circuiting.\r
+ **\r
+ ** Generated code is:\r
+ **\r
+ ** <test for short circuiting> ?\r
+ ** <call to BooleanDataValue.getImmutable> : <call to operator method>\r
+ **\r
+ ** For AND short circuiting shortcircuit value will be false, so that\r
+ ** if left is false, no need to evaluate the right and the result will be false.\r
+ **\r
+ ** For OR short circuiting shortcircuit value will be true, so that\r
+ ** if left is true, no need to to evaluate the right and the result will be true.\r
+ **\r
+ ** In both cases the result is the same as the left operand.\r
+ **\r
+ ** TODO: Could short circuit when the left value is NULL as well. Then\r
+ ** the result would be NULL in either case and still equal to the left value.\r
+ ** This would require a different check on the conditional.\r
+ */\r
+\r
+ mb.conditionalIf();\r
+ \r
+ // stack: left\r
+ mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getImmutable",\r
+ ClassName.BooleanDataValue, 0);\r
+ \r
+ // stack: result (matching left)\r
+\r
+ mb.startElseCode();\r
+\r
+ /*\r
+ ** Generate the return value if the left operand does not equal the\r
+ ** short-circuit value. This is the call to "and" or "or".\r
+ **\r
+ ** Generated code is:\r
+ **\r
+ ** <fieldx>.<methodName>(<rightOperand>)\r
+ */\r
+\r
+ // stack: left\r
+\r
+ rightOperand.generateExpression(acb, mb);\r
+\r
+ // stack: left, right\r
+ mb.upCast(ClassName.BooleanDataValue);\r
+\r
+ mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, methodName, ClassName.BooleanDataValue, 1);\r
+ // stack: result(left op right)\r
+\r
+ mb.completeConditional();\r
+ // stack: result\r
+\r
+ }\r
+\r
+ DataTypeDescriptor resolveLogicalBinaryOperator(\r
+ DataTypeDescriptor leftType,\r
+ DataTypeDescriptor rightType)\r
+ throws StandardException\r
+ {\r
+ if ( ( ! (leftType.getTypeId().isBooleanTypeId()) ) ||\r
+ ( ! (rightType.getTypeId().isBooleanTypeId()) ) )\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_BINARY_LOGICAL_NON_BOOLEAN);\r
+ }\r
+\r
+ return leftType.getNullabilityType(\r
+ leftType.isNullable() || rightType.isNullable());\r
+ }\r
+}\r