001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.BinaryArithmeticOperatorNode
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.services.sanity.SanityManager;
025:
026: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
027:
028: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
029:
030: import org.apache.derby.iapi.types.TypeId;
031:
032: import org.apache.derby.iapi.types.DataTypeDescriptor;
033: import org.apache.derby.iapi.types.NumberDataValue;
034:
035: import org.apache.derby.iapi.sql.compile.TypeCompiler;
036:
037: import org.apache.derby.iapi.error.StandardException;
038:
039: import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
040: import org.apache.derby.iapi.reference.ClassName;
041:
042: import java.sql.Types;
043:
044: import java.util.Vector;
045:
046: /**
047: * This node represents a binary arithmetic operator, like + or *.
048: *
049: * @author Jeff Lichtman
050: */
051:
052: public final class BinaryArithmeticOperatorNode extends
053: BinaryOperatorNode {
054: /**
055: * Initializer for a BinaryArithmeticOperatorNode
056: *
057: * @param leftOperand The left operand
058: * @param rightOperand The right operand
059: */
060:
061: public void init(Object leftOperand, Object rightOperand) {
062: super .init(leftOperand, rightOperand,
063: ClassName.NumberDataValue, ClassName.NumberDataValue);
064: }
065:
066: public void setNodeType(int nodeType) {
067: String operator = null;
068: String methodName = null;
069:
070: switch (nodeType) {
071: case C_NodeTypes.BINARY_DIVIDE_OPERATOR_NODE:
072: operator = TypeCompiler.DIVIDE_OP;
073: methodName = "divide";
074: break;
075:
076: case C_NodeTypes.BINARY_MINUS_OPERATOR_NODE:
077: operator = TypeCompiler.MINUS_OP;
078: methodName = "minus";
079: break;
080:
081: case C_NodeTypes.BINARY_PLUS_OPERATOR_NODE:
082: operator = TypeCompiler.PLUS_OP;
083: methodName = "plus";
084: break;
085:
086: case C_NodeTypes.BINARY_TIMES_OPERATOR_NODE:
087: operator = TypeCompiler.TIMES_OP;
088: methodName = "times";
089: break;
090:
091: case C_NodeTypes.MOD_OPERATOR_NODE:
092: operator = TypeCompiler.MOD_OP;
093: methodName = "mod";
094: break;
095:
096: default:
097: if (SanityManager.DEBUG) {
098: SanityManager.THROWASSERT("Unexpected nodeType = "
099: + nodeType);
100: }
101: }
102: setOperator(operator);
103: setMethodName(methodName);
104: super .setNodeType(nodeType);
105: }
106:
107: /**
108: * Bind this operator
109: *
110: * @param fromList The query's FROM list
111: * @param subqueryList The subquery list being built as we find SubqueryNodes
112: * @param aggregateVector The aggregate vector being built as we find AggregateNodes
113: *
114: * @return The new top of the expression tree.
115: *
116: * @exception StandardException Thrown on error
117: */
118:
119: public ValueNode bindExpression(FromList fromList,
120: SubqueryList subqueryList, Vector aggregateVector)
121: throws StandardException {
122: super .bindExpression(fromList, subqueryList, aggregateVector);
123:
124: TypeId leftType = leftOperand.getTypeId();
125: TypeId rightType = rightOperand.getTypeId();
126: DataTypeDescriptor leftDTS = leftOperand.getTypeServices();
127: DataTypeDescriptor rightDTS = rightOperand.getTypeServices();
128:
129: /* Do any implicit conversions from (long) (var)char. */
130: if (leftType.isStringTypeId() && rightType.isNumericTypeId()) {
131: boolean nullableResult;
132: nullableResult = leftDTS.isNullable()
133: || rightDTS.isNullable();
134: /* If other side is decimal/numeric, then we need to diddle
135: * with the precision, scale and max width in order to handle
136: * computations like: 1.1 + '0.111'
137: */
138: int precision = rightDTS.getPrecision();
139: int scale = rightDTS.getScale();
140: int maxWidth = rightDTS.getMaximumWidth();
141:
142: if (rightType.isDecimalTypeId()) {
143: int charMaxWidth = leftDTS.getMaximumWidth();
144: precision += (2 * charMaxWidth);
145: scale += charMaxWidth;
146: maxWidth = precision + 3;
147: }
148:
149: leftOperand = (ValueNode) getNodeFactory().getNode(
150: C_NodeTypes.CAST_NODE,
151: leftOperand,
152: new DataTypeDescriptor(rightType, precision, scale,
153: nullableResult, maxWidth),
154: getContextManager());
155: ((CastNode) leftOperand).bindCastNodeOnly();
156: } else if (rightType.isStringTypeId()
157: && leftType.isNumericTypeId()) {
158: boolean nullableResult;
159: nullableResult = leftDTS.isNullable()
160: || rightDTS.isNullable();
161: /* If other side is decimal/numeric, then we need to diddle
162: * with the precision, scale and max width in order to handle
163: * computations like: 1.1 + '0.111'
164: */
165: int precision = leftDTS.getPrecision();
166: int scale = leftDTS.getScale();
167: int maxWidth = leftDTS.getMaximumWidth();
168:
169: if (leftType.isDecimalTypeId()) {
170: int charMaxWidth = rightDTS.getMaximumWidth();
171: precision += (2 * charMaxWidth);
172: scale += charMaxWidth;
173: maxWidth = precision + 3;
174: }
175:
176: rightOperand = (ValueNode) getNodeFactory().getNode(
177: C_NodeTypes.CAST_NODE,
178: rightOperand,
179: new DataTypeDescriptor(leftType, precision, scale,
180: nullableResult, maxWidth),
181: getContextManager());
182: ((CastNode) rightOperand).bindCastNodeOnly();
183: }
184:
185: /*
186: ** Set the result type of this operator based on the operands.
187: ** By convention, the left operand gets to decide the result type
188: ** of a binary operator.
189: */
190: setType(leftOperand.getTypeCompiler()
191: .resolveArithmeticOperation(
192: leftOperand.getTypeServices(),
193: rightOperand.getTypeServices(), operator));
194:
195: return this;
196: }
197: }
|