001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.UnaryArithmeticOperatorNode
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.sql.dictionary.DataDictionary;
025:
026: import org.apache.derby.iapi.types.TypeId;
027: import org.apache.derby.iapi.types.DataTypeDescriptor;
028: import org.apache.derby.iapi.reference.SQLState;
029: import org.apache.derby.iapi.error.StandardException;
030:
031: import org.apache.derby.iapi.services.compiler.MethodBuilder;
032: import org.apache.derby.iapi.services.sanity.SanityManager;
033: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
034: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
035:
036: import java.sql.Types;
037: import java.util.Vector;
038:
039: /**
040: * This node represents a unary arithmetic operator
041: *
042: * @author Manish Khettry
043: */
044:
045: public class UnaryArithmeticOperatorNode extends UnaryOperatorNode {
046: private final static int UNARY_PLUS = 0;
047: private final static int UNARY_MINUS = 1;
048: private final static int SQRT = 2;
049: private final static int ABSOLUTE = 3;
050: private final static String[] UNARY_OPERATORS = { "+", "-", "SQRT",
051: "ABS/ABSVAL" };
052: private final static String[] UNARY_METHODS = { "plus", "minus",
053: "sqrt", "absolute" };
054:
055: private int operatorType;
056:
057: //when the bindExpression method is called during the normal binding phase,
058: //unary minus and unary plus dynamic parameters are not ready for
059: //binding because the type of these dynamic parameters is not yet set.
060: //For eg, consider sql select * from t1 where c1 = -?
061: //bindExpression on -? gets called from BinaryComparisonOperatorNode's
062: //bindExpression but the parameter type has not been set yet for -?
063: //Later on, in BinaryComparisonOperatorNode's bindExpression, the type
064: //of the -? gets set to the type of c1 by the setType call.
065: //Now, at this point, we are ready to finish binding phase for -?
066: //(This class's setType method calls the bindExpression to finish binding)
067: //In order to accomplish binding later on, we need to save the following
068: //3 objects during first call to bindExpression and then later this
069: //gets used in setType method when it calls the bindExpression method.
070: FromList localCopyFromList;
071: SubqueryList localCopySubqueryList;
072: Vector localAggregateVector;
073:
074: /**
075: * Initializer for a UnaryArithmeticOperatorNode
076: *
077: * @param operand The operand of the node
078: */
079: public void init(Object operand) {
080: switch (getNodeType()) {
081: case C_NodeTypes.UNARY_PLUS_OPERATOR_NODE:
082: operatorType = UNARY_PLUS;
083: break;
084: case C_NodeTypes.UNARY_MINUS_OPERATOR_NODE:
085: operatorType = UNARY_MINUS;
086: break;
087: case C_NodeTypes.SQRT_OPERATOR_NODE:
088: operatorType = SQRT;
089: break;
090: case C_NodeTypes.ABSOLUTE_OPERATOR_NODE:
091: operatorType = ABSOLUTE;
092: break;
093: default:
094: if (SanityManager.DEBUG) {
095: SanityManager
096: .THROWASSERT("init for UnaryArithmeticOperator called with wrong nodeType = "
097: + getNodeType());
098: }
099: break;
100: }
101: init(operand, UNARY_OPERATORS[this .operatorType],
102: UNARY_METHODS[this .operatorType]);
103: }
104:
105: /**
106: * By default unary operators don't accept ? parameters as operands.
107: * This can be over-ridden for particular unary operators.
108: *
109: * We throw an exception if the parameter doesn't have a datatype
110: * assigned to it yet.
111: *
112: * @exception StandardException Thrown if ? parameter doesn't
113: * have a type bound to it yet.
114: * ? parameter where it isn't allowed.
115: */
116:
117: void bindParameter() throws StandardException {
118: if (operatorType == SQRT || operatorType == ABSOLUTE) {
119: operand.setType(new DataTypeDescriptor(TypeId
120: .getBuiltInTypeId(Types.DOUBLE), true));
121: }
122: //Derby-582 add support for dynamic parameter for unary plus and minus
123: else if (operatorType == UNARY_MINUS
124: || operatorType == UNARY_PLUS)
125: return;
126: else if (operand.getTypeServices() == null) {
127: throw StandardException.newException(
128: SQLState.LANG_UNARY_OPERAND_PARM, operator);
129: }
130: }
131:
132: /**
133: * Bind this operator
134: *
135: * @param fromList The query's FROM list
136: * @param subqueryList The subquery list being built as we find SubqueryNodes
137: * @param aggregateVector The aggregate vector being built as we find AggregateNodes
138: *
139: * @return The new top of the expression tree.
140: *
141: * @exception StandardException Thrown on error
142: */
143:
144: public ValueNode bindExpression(FromList fromList,
145: SubqueryList subqueryList, Vector aggregateVector)
146: throws StandardException {
147: localCopyFromList = fromList;
148: localCopySubqueryList = subqueryList;
149: localAggregateVector = aggregateVector;
150: //Return with no binding, if the type of unary minus/plus parameter is not set yet.
151: if (operand.requiresTypeFromContext()
152: && ((operatorType == UNARY_PLUS || operatorType == UNARY_MINUS))
153: && operand.getTypeServices() == null)
154: return this ;
155:
156: super .bindExpression(fromList, subqueryList, aggregateVector);
157:
158: if (operatorType == SQRT || operatorType == ABSOLUTE) {
159: bindSQRTABS();
160: } else if (operatorType == UNARY_PLUS
161: || operatorType == UNARY_MINUS) {
162: TypeId operandType = operand.getTypeId();
163:
164: if (!operandType.isNumericTypeId()) {
165:
166: throw StandardException.newException(
167: SQLState.LANG_UNARY_ARITHMETIC_BAD_TYPE,
168: (operatorType == UNARY_PLUS) ? "+" : "-",
169: operandType.getSQLTypeName());
170: }
171: }
172: /*
173: ** The result type of a +, -, SQRT, ABS is the same as its operand.
174: */
175: super .setType(operand.getTypeServices());
176: return this ;
177: }
178:
179: /**
180: * Do code generation for this unary plus operator
181: *
182: * @param acb The ExpressionClassBuilder for the class we're generating
183: * @param mb The method the expression will go into
184: *
185: * @exception StandardException Thrown on error
186: */
187:
188: public void generateExpression(ExpressionClassBuilder acb,
189: MethodBuilder mb) throws StandardException {
190: /* Unary + doesn't do anything. Just return the operand */
191: if (operatorType == UNARY_PLUS)
192: operand.generateExpression(acb, mb);
193: else
194: super .generateExpression(acb, mb);
195: }
196:
197: /**
198: * Bind SQRT or ABS
199: *
200: * @exception StandardException Thrown on error
201: */
202: private void bindSQRTABS() throws StandardException {
203: TypeId operandType;
204: int jdbcType;
205:
206: /*
207: ** Check the type of the operand
208: */
209: operandType = operand.getTypeId();
210:
211: /*
212: * If the operand is not a build-in type, generate a bound conversion
213: * tree to build-in types.
214: */
215: if (operandType.userType()) {
216: operand = operand.genSQLJavaSQLTree();
217: }
218: /* DB2 doesn't cast string types to numeric types for numeric functions */
219:
220: jdbcType = operandType.getJDBCTypeId();
221:
222: /* Both SQRT and ABS are only allowed on numeric types */
223: if (!operandType.isNumericTypeId())
224: throw StandardException.newException(
225: SQLState.LANG_UNARY_FUNCTION_BAD_TYPE,
226: getOperatorString(), operandType.getSQLTypeName());
227:
228: /* For SQRT, if operand is not a DOUBLE, convert it to DOUBLE */
229: if (operatorType == SQRT && jdbcType != Types.DOUBLE) {
230: operand = (ValueNode) getNodeFactory().getNode(
231: C_NodeTypes.CAST_NODE,
232: operand,
233: new DataTypeDescriptor(TypeId
234: .getBuiltInTypeId(Types.DOUBLE), true),
235: getContextManager());
236: ((CastNode) operand).bindCastNodeOnly();
237: }
238: }
239:
240: /** @see ValueNode#setType */
241: /* We are overwriting this method here because for -?/+?, we now know
242: the type of these dynamic parameters and hence we can do the parameter
243: binding. The setType method will call the binding code after setting
244: the type of the parameter*/
245: public void setType(DataTypeDescriptor descriptor)
246: throws StandardException {
247: operand.setType(descriptor);
248: super .setType(descriptor);
249: //Derby-582 add support for dynamic parameters for unary plus and minus
250: //Now that we know the type of this parameter node, we can do the
251: //binding.
252: bindExpression(localCopyFromList, localCopySubqueryList,
253: localAggregateVector);
254: }
255: }
|