--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.compile.UnaryArithmeticOperatorNode\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.StringDataValue;\r
+import org.apache.derby.iapi.types.TypeId;\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;\r
+import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;\r
+\r
+import java.sql.Types;\r
+import java.util.Vector;\r
+\r
+/**\r
+ * This node represents a unary arithmetic operator\r
+ *\r
+ */\r
+\r
+public class UnaryArithmeticOperatorNode extends UnaryOperatorNode\r
+{\r
+ private final static int UNARY_PLUS = 0;\r
+ private final static int UNARY_MINUS = 1;\r
+ private final static int SQRT = 2;\r
+ private final static int ABSOLUTE = 3;\r
+ private final static String[] UNARY_OPERATORS = {"+","-","SQRT", "ABS/ABSVAL"};\r
+ private final static String[] UNARY_METHODS = {"plus","minus","sqrt", "absolute"};\r
+\r
+ private int operatorType;\r
+ \r
+ /**\r
+ * Initializer for a UnaryArithmeticOperatorNode\r
+ *\r
+ * @param operand The operand of the node\r
+ */\r
+ public void init(Object operand)\r
+ {\r
+ switch(getNodeType())\r
+ {\r
+ case C_NodeTypes.UNARY_PLUS_OPERATOR_NODE:\r
+ operatorType = UNARY_PLUS;\r
+ break;\r
+ case C_NodeTypes.UNARY_MINUS_OPERATOR_NODE:\r
+ operatorType = UNARY_MINUS;\r
+ break;\r
+ case C_NodeTypes.SQRT_OPERATOR_NODE:\r
+ operatorType = SQRT;\r
+ break;\r
+ case C_NodeTypes.ABSOLUTE_OPERATOR_NODE:\r
+ operatorType = ABSOLUTE;\r
+ break;\r
+ default:\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.THROWASSERT("init for UnaryArithmeticOperator called with wrong nodeType = " + getNodeType());\r
+ }\r
+ break;\r
+ }\r
+ init(operand, UNARY_OPERATORS[this.operatorType], \r
+ UNARY_METHODS[this.operatorType]);\r
+ }\r
+ \r
+ /**\r
+ * Unary + and - require their type to be set if\r
+ * they wrap another node (e.g. a parameter) that\r
+ * requires type from its context.\r
+ * @see ValueNode#requiresTypeFromContext\r
+ */\r
+ public boolean requiresTypeFromContext()\r
+ {\r
+ if (operatorType == UNARY_PLUS || operatorType == UNARY_MINUS)\r
+ return operand.requiresTypeFromContext(); \r
+ return false;\r
+ }\r
+ \r
+ /**\r
+ * A +? or a -? is considered a parameter.\r
+ */\r
+ public boolean isParameterNode()\r
+ {\r
+ if (operatorType == UNARY_PLUS || operatorType == UNARY_MINUS)\r
+ return operand.isParameterNode(); \r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * For SQRT and ABS the parameter becomes a DOUBLE.\r
+ * For unary + and - no change is made to the\r
+ * underlying node. Once this node's type is set\r
+ * using setType, then the underlying node will have\r
+ * its type set.\r
+ *\r
+ * @exception StandardException Thrown if ? parameter doesn't\r
+ * have a type bound to it yet.\r
+ * ? parameter where it isn't allowed.\r
+ */\r
+\r
+ void bindParameter() throws StandardException\r
+ {\r
+ if (operatorType == SQRT || operatorType == ABSOLUTE)\r
+ {\r
+ operand.setType(\r
+ new DataTypeDescriptor(TypeId.getBuiltInTypeId(Types.DOUBLE), true));\r
+ return;\r
+ }\r
+ \r
+ //Derby-582 add support for dynamic parameter for unary plus and minus\r
+ if (operatorType == UNARY_MINUS || operatorType == UNARY_PLUS) \r
+ return;\r
+ \r
+ // Not expected to get here since only the above types are supported\r
+ // but the super-class method will throw an exception\r
+ super.bindParameter();\r
+ \r
+ }\r
+ \r
+ /**\r
+ * Bind this operator\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
+ //Return with no binding, if the type of unary minus/plus parameter is not set yet.\r
+ if (operand.requiresTypeFromContext() && ((operatorType == UNARY_PLUS || operatorType == UNARY_MINUS))\r
+ && operand.getTypeServices() == null)\r
+ return this;\r
+\r
+ bindOperand(fromList, subqueryList,\r
+ aggregateVector);\r
+\r
+ if (operatorType == SQRT || operatorType == ABSOLUTE)\r
+ {\r
+ bindSQRTABS();\r
+ }\r
+ else if (operatorType == UNARY_PLUS || operatorType == UNARY_MINUS)\r
+ {\r
+ checkOperandIsNumeric(operand.getTypeId());\r
+ }\r
+ /*\r
+ ** The result type of a +, -, SQRT, ABS is the same as its operand.\r
+ */\r
+ super.setType(operand.getTypeServices());\r
+ return this;\r
+ }\r
+ \r
+ /**\r
+ * Only called for Unary +/-.\r
+ *\r
+ */\r
+ private void checkOperandIsNumeric(TypeId operandType) throws StandardException\r
+ {\r
+ if (!operandType.isNumericTypeId())\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.LANG_UNARY_ARITHMETIC_BAD_TYPE, \r
+ (operatorType == UNARY_PLUS) ? "+" : "-", \r
+ operandType.getSQLTypeName());\r
+ }\r
+ \r
+ }\r
+\r
+ /**\r
+ * Do code generation for this unary plus operator\r
+ *\r
+ * @param acb The ExpressionClassBuilder for the class we're generating\r
+ * @param mb The method the expression will go into\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ public void generateExpression(ExpressionClassBuilder acb,\r
+ MethodBuilder mb)\r
+ throws StandardException\r
+ {\r
+ /* Unary + doesn't do anything. Just return the operand */\r
+ if (operatorType == UNARY_PLUS)\r
+ operand.generateExpression(acb, mb);\r
+ else\r
+ super.generateExpression(acb, mb);\r
+ }\r
+ /**\r
+ * Bind SQRT or ABS\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ private void bindSQRTABS()\r
+ throws StandardException\r
+ {\r
+ TypeId operandType;\r
+ int jdbcType;\r
+\r
+ /*\r
+ ** Check the type of the operand \r
+ */\r
+ operandType = operand.getTypeId();\r
+\r
+ /*\r
+ * If the operand is not a build-in type, generate a bound conversion\r
+ * tree to build-in types.\r
+ */\r
+ if (operandType.userType() )\r
+ {\r
+ operand = operand.genSQLJavaSQLTree();\r
+ }\r
+ /* DB2 doesn't cast string types to numeric types for numeric functions */\r
+\r
+ jdbcType = operandType.getJDBCTypeId();\r
+\r
+ /* Both SQRT and ABS are only allowed on numeric types */\r
+ if (!operandType.isNumericTypeId())\r
+ throw StandardException.newException(\r
+ SQLState.LANG_UNARY_FUNCTION_BAD_TYPE, \r
+ getOperatorString(), operandType.getSQLTypeName());\r
+\r
+ /* For SQRT, if operand is not a DOUBLE, convert it to DOUBLE */\r
+ if (operatorType == SQRT && jdbcType != Types.DOUBLE)\r
+ {\r
+ operand = (ValueNode) getNodeFactory().getNode(\r
+ C_NodeTypes.CAST_NODE,\r
+ operand,\r
+ new DataTypeDescriptor(TypeId.getBuiltInTypeId(Types.DOUBLE), true),\r
+ getContextManager());\r
+ ((CastNode) operand).bindCastNodeOnly();\r
+ }\r
+ }\r
+\r
+ /** We are overwriting this method here because for -?/+?, we now know\r
+ the type of these dynamic parameters and hence we can do the parameter\r
+ binding. The setType method will call the binding code after setting\r
+ the type of the parameter*/\r
+ public void setType(DataTypeDescriptor descriptor) throws StandardException\r
+ {\r
+ if (operand.requiresTypeFromContext() && operand.getTypeServices() == null)\r
+ {\r
+ checkOperandIsNumeric(descriptor.getTypeId());\r
+ operand.setType(descriptor);\r
+ }\r
+ super.setType(descriptor);\r
+ }\r
+}\r