001: /*
002:
003: Derby - Class org.apache.derby.iapi.types.NumberDataType
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.iapi.types;
023:
024: import org.apache.derby.iapi.error.StandardException;
025: import org.apache.derby.iapi.types.NumberDataValue;
026: import org.apache.derby.iapi.services.sanity.SanityManager;
027: import org.apache.derby.iapi.services.io.Storable;
028: import org.apache.derby.iapi.types.Orderable;
029: import org.apache.derby.iapi.types.DataValueDescriptor;
030: import org.apache.derby.iapi.types.TypeId;
031: import org.apache.derby.iapi.reference.SQLState;
032: import org.apache.derby.iapi.reference.Limits;
033:
034: import org.apache.derby.iapi.types.*;
035:
036: /**
037: * NumberDataType is the superclass for all exact and approximate
038: * numeric data types. It exists for the purpose of allowing classification
039: * of types for supported implicit conversions among them.
040: *
041: * @see DataType
042: * @author ames
043: */
044: public abstract class NumberDataType extends DataType implements
045: NumberDataValue {
046: /**
047: * Set by the booting DataValueFactory implementation.
048: */
049: static DataValueDescriptor ZERO_DECIMAL;
050:
051: /**
052: * Set by the booting DataValueFactory implementation.
053: */
054: static Comparable MINLONG_MINUS_ONE;
055: /**
056: * Set by the booting DataValueFactory implementation.
057: */
058: static Comparable MAXLONG_PLUS_ONE;
059:
060: /**
061: * Numbers check for isNegative first and negate it if negative.
062: *
063: * @return this object's absolute value. Null if object is null.
064: * @exception StandardException thrown on error.
065: */
066: public final NumberDataValue absolute(NumberDataValue result)
067: throws StandardException {
068: if (isNegative())
069: return minus(result);
070:
071: if (result == null)
072: result = (NumberDataType) getNewNull();
073:
074: result.setValue(this );
075: return result;
076: }
077:
078: /**
079: * This is the sqrt method.
080: *
081: * @return this object's sqrt value. Null if object is null.
082: * Note: -0.0f and -0.0d returns 0.0f and 0.0d.
083: *
084: * @exception StandardException thrown on a negative number.
085: */
086:
087: public NumberDataValue sqrt(NumberDataValue result)
088: throws StandardException {
089: if (result == null) {
090: result = (NumberDataValue) getNewNull();
091: }
092:
093: if (this .isNull()) {
094: result.setToNull();
095: return result;
096: }
097:
098: double doubleValue = getDouble();
099:
100: if (this .isNegative()) {
101: if ((new Double(doubleValue)).equals(new Double(-0.0d))) {
102: doubleValue = 0.0d;
103: } else {
104: throw StandardException.newException(
105: SQLState.LANG_SQRT_OF_NEG_NUMBER, this );
106: }
107: }
108:
109: result.setValue(Math.sqrt(doubleValue));
110: return result;
111: }
112:
113: /**
114: * This method implements the + operator for TINYINT,SMALLINT,INT.
115: *
116: * @param addend1 One of the addends
117: * @param addend2 The other addend
118: * @param result The result of a previous call to this method, null
119: * if not called yet
120: *
121: * @return A NumberDataValue containing the result of the addition
122: *
123: * @exception StandardException Thrown on error
124: */
125:
126: public NumberDataValue plus(NumberDataValue addend1,
127: NumberDataValue addend2, NumberDataValue result)
128: throws StandardException {
129: if (result == null) {
130: result = (NumberDataValue) getNewNull();
131: }
132:
133: if (addend1.isNull() || addend2.isNull()) {
134: result.setToNull();
135: return result;
136: }
137: int addend1Int = addend1.getInt();
138: int addend2Int = addend2.getInt();
139:
140: int resultValue = addend1Int + addend2Int;
141:
142: /*
143: ** Java does not check for overflow with integral types. We have to
144: ** check the result ourselves.
145: **
146: ** Overflow is possible only if the two addends have the same sign.
147: ** Do they? (This method of checking is approved by "The Java
148: ** Programming Language" by Arnold and Gosling.)
149: */
150: if ((addend1Int < 0) == (addend2Int < 0)) {
151: /*
152: ** Addends have the same sign. The result should have the same
153: ** sign as the addends. If not, an overflow has occurred.
154: */
155: if ((addend1Int < 0) != (resultValue < 0)) {
156: throw outOfRange();
157: }
158: }
159:
160: result.setValue(resultValue);
161:
162: return result;
163: }
164:
165: /**
166: * This method implements the - operator for TINYINT, SMALLINT and INTEGER.
167: *
168: * @param left The value to be subtracted from
169: * @param right The value to be subtracted
170: * @param result The result of a previous call to this method, null
171: * if not called yet
172: *
173: * @return A SQLInteger containing the result of the subtraction
174: *
175: * @exception StandardException Thrown on error
176: */
177:
178: public NumberDataValue minus(NumberDataValue left,
179: NumberDataValue right, NumberDataValue result)
180: throws StandardException {
181: if (result == null) {
182: result = (NumberDataValue) getNewNull();
183: }
184:
185: if (left.isNull() || right.isNull()) {
186: result.setToNull();
187: return result;
188: }
189:
190: int diff = left.getInt() - right.getInt();
191:
192: /*
193: ** Java does not check for overflow with integral types. We have to
194: ** check the result ourselves.
195: **
196: ** Overflow is possible only if the left and the right side have opposite signs.
197: ** Do they? (This method of checking is approved by "The Java
198: ** Programming Language" by Arnold and Gosling.)
199: */
200: if ((left.getInt() < 0) != (right.getInt() < 0)) {
201: /*
202: ** Left and right have opposite signs. The result should have the same
203: ** sign as the left (this). If not, an overflow has occurred.
204: */
205: if ((left.getInt() < 0) != (diff < 0)) {
206: throw outOfRange();
207: }
208: }
209:
210: result.setValue(diff);
211:
212: return result;
213: }
214:
215: /**
216: * This method implements the / operator for TINYINT, SMALLINT and INTEGER.
217: * Specialized methods are not required for TINYINT and SMALLINT as the Java
218: * virtual machine always executes byte and int division as integer.
219: *
220: * @param dividend The numerator
221: * @param divisor The denominator
222: * @param result The result of a previous call to this method, null
223: * if not called yet
224: *
225: * @return A SQLInteger containing the result of the division
226: *
227: * @exception StandardException Thrown on error
228: */
229:
230: public NumberDataValue divide(NumberDataValue dividend,
231: NumberDataValue divisor, NumberDataValue result)
232: throws StandardException {
233: if (result == null) {
234: result = (NumberDataValue) getNewNull();
235: }
236:
237: if (dividend.isNull() || divisor.isNull()) {
238: result.setToNull();
239: return result;
240: }
241:
242: /* Catch divide by 0 */
243: int intDivisor = divisor.getInt();
244: if (intDivisor == 0) {
245: throw StandardException
246: .newException(SQLState.LANG_DIVIDE_BY_ZERO);
247: }
248:
249: result.setValue(dividend.getInt() / intDivisor);
250: return result;
251: }
252:
253: /**
254: Suitable for integral types that ignore scale.
255: */
256: public NumberDataValue divide(NumberDataValue dividend,
257: NumberDataValue divisor, NumberDataValue result, int scale)
258: throws StandardException {
259: return divide(dividend, divisor, result);
260: }
261:
262: public NumberDataValue mod(NumberDataValue dividend,
263: NumberDataValue divisor, NumberDataValue result)
264: throws StandardException {
265: if (SanityManager.DEBUG)
266: SanityManager.NOTREACHED();
267: return null;
268: }
269:
270: /** @exception StandardException Thrown on error */
271: public final int compare(DataValueDescriptor arg)
272: throws StandardException {
273: /* Use compare method from dominant type, negating result
274: * to reflect flipping of sides.
275: */
276: if (typePrecedence() < arg.typePrecedence()) {
277: return -(arg.compare(this ));
278: }
279:
280: boolean this Null, otherNull;
281:
282: this Null = this .isNull();
283: otherNull = arg.isNull();
284:
285: /*
286: * thisNull otherNull return
287: * T T 0 (this == other)
288: * F T -1 (this > other)
289: * T F 1 (this < other)
290: */
291: if (this Null || otherNull) {
292: if (!this Null) // otherNull must be true
293: return -1;
294: if (!otherNull) // thisNull must be true
295: return 1;
296: return 0;
297: }
298:
299: return typeCompare(arg);
300:
301: }
302:
303: /**
304: Compare this (not null) to a non-null value.
305:
306: @exception StandardException Thrown on error
307: */
308: protected abstract int typeCompare(DataValueDescriptor arg)
309: throws StandardException;
310:
311: /**
312: @exception StandardException thrown on error
313: */
314: public final boolean compare(int op, DataValueDescriptor other,
315: boolean orderedNulls, boolean unknownRV)
316: throws StandardException {
317: if (!orderedNulls) // nulls are unordered
318: {
319: if (this .isNull() || other.isNull())
320: return unknownRV;
321: }
322:
323: /* Do the comparison */
324: return super .compare(op, other, orderedNulls, unknownRV);
325: }
326:
327: /**
328: * The isNegative abstract method. Checks to see if this.value is negative.
329: * To be implemented by each NumberDataType.
330: *
331: * @return A boolean. If this.value is negative, return true.
332: * For positive values or null, return false.
333: */
334: protected abstract boolean isNegative();
335:
336: /**
337: * Common code to handle converting a short to this value
338: * by using the int to this value conversion.
339: * Simply calls setValue(int).
340: *
341: */
342: public void setValue(short theValue) throws StandardException {
343: setValue((int) theValue);
344: }
345:
346: /**
347: * Common code to handle converting a byte to this value
348: * by using the int to this value conversion.
349: * Simply calls setValue(int).
350: *
351: */
352: public void setValue(byte theValue) throws StandardException {
353: setValue((int) theValue);
354: }
355:
356: /**
357: Common code to handle java.lang.Integer as a Number,
358: used for TINYINT, SMALLINT, INTEGER
359: * @see NumberDataValue#setValue
360: *
361: * @exception StandardException Thrown on error
362: */
363: public void setValue(Number theValue) throws StandardException {
364: if (objectNull(theValue))
365: return;
366:
367: if (SanityManager.ASSERT) {
368: if (!(theValue instanceof java.lang.Integer))
369: SanityManager
370: .THROWASSERT("NumberDataType.setValue(Number) passed a "
371: + theValue.getClass());
372: }
373:
374: setValue(theValue.intValue());
375: }
376:
377: /**
378: * Set the value from a correctly typed Integer object.
379: * Used for TINYINT, SMALLINT, INTEGER.
380: * @throws StandardException
381: */
382: void setObject(Object theValue) throws StandardException {
383: setValue(((Integer) theValue).intValue());
384: }
385:
386: /**
387: setValue for integral exact numerics. Converts the BigDecimal
388: to a long to preserve precision
389: */
390: public void setBigDecimal(Number bigDecimal)
391: throws StandardException {
392: if (objectNull(bigDecimal))
393: return;
394:
395: Comparable bdc = (Comparable) bigDecimal;
396:
397: // See comment in SQLDecimal.getLong()
398:
399: if ((bdc.compareTo(NumberDataType.MINLONG_MINUS_ONE) == 1)
400: && (bdc.compareTo(NumberDataType.MAXLONG_PLUS_ONE) == -1)) {
401:
402: setValue(bigDecimal.longValue());
403: } else {
404:
405: throw StandardException.newException(
406: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
407: getTypeName());
408: }
409: }
410:
411: /**
412: * Implementation for integral types. Convert to a BigDecimal using long
413: */
414: public int typeToBigDecimal() {
415: return java.sql.Types.BIGINT;
416: }
417:
418: /**
419: Return the precision of this specific DECIMAL value.
420: If the value does not represent a SQL DECIMAL then
421: the return is undefined.
422: */
423: public int getDecimalValuePrecision() {
424: return -1;
425: }
426:
427: /**
428: Return the scale of this specific DECIMAL value.
429: If the value does not represent a SQL DECIMAL then
430: the return is undefined.
431: */
432: public int getDecimalValueScale() {
433: return -1;
434: }
435:
436: protected final boolean objectNull(Object o) {
437: if (o == null) {
438: restoreToNull();
439: return true;
440: }
441: return false;
442: }
443:
444: /**
445: normalizeREAL checks the validity of the given java float that
446: it fits within the range of DB2 REALs. In addition it
447: normalizes the value, so that negative zero (-0.0) becomes positive.
448: */
449: public static float normalizeREAL(float v) throws StandardException {
450: if ((Float.isNaN(v) || Float.isInfinite(v))
451: || ((v < Limits.DB2_SMALLEST_REAL) || (v > Limits.DB2_LARGEST_REAL))
452: || ((v > 0) && (v < Limits.DB2_SMALLEST_POSITIVE_REAL))
453: || ((v < 0) && (v > Limits.DB2_LARGEST_NEGATIVE_REAL))) {
454: throw StandardException.newException(
455: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
456: TypeId.REAL_NAME);
457: }
458: // Normalize negative floats to be "positive" (can't detect easily without using Float object because -0.0f = 0.0f)
459: if (v == 0.0f)
460: v = 0.0f;
461:
462: return v;
463: }
464:
465: /**
466: normalizeREAL checks the validity of the given java double that
467: it fits within the range of DB2 REALs. In addition it
468: normalizes the value, so that negative zero (-0.0) becomes positive.
469:
470: The reason for having normalizeREAL with two signatures is to
471: avoid that normalizeREAL is called with a casted (float)doublevalue,
472: since this invokes an unwanted rounding (of underflow values to 0.0),
473: in contradiction to DB2s casting semantics.
474: */
475: public static float normalizeREAL(double v)
476: throws StandardException {
477: // can't just cast it to float and call normalizeFloat(float) since casting can round down to 0.0
478: if ((Double.isNaN(v) || Double.isInfinite(v))
479: || ((v < Limits.DB2_SMALLEST_REAL) || (v > Limits.DB2_LARGEST_REAL))
480: || ((v > 0) && (v < Limits.DB2_SMALLEST_POSITIVE_REAL))
481: || ((v < 0) && (v > Limits.DB2_LARGEST_NEGATIVE_REAL))) {
482: throw StandardException.newException(
483: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
484: TypeId.REAL_NAME);
485: }
486: // Normalize negative floats to be "positive" (can't detect easily without using Float object because -0.0f = 0.0f)
487: if (v == 0.0d)
488: v = 0.0d;
489:
490: return (float) v;
491: }
492:
493: /**
494: normalizeDOUBLE checks the validity of the given java double that
495: it fits within the range of DB2 DOUBLEs. In addition it
496: normalizes the value, so that negative zero (-0.0) becomes positive.
497: */
498: public static double normalizeDOUBLE(double v)
499: throws StandardException {
500: if ((Double.isNaN(v) || Double.isInfinite(v))
501: || ((v < Limits.DB2_SMALLEST_DOUBLE) || (v > Limits.DB2_LARGEST_DOUBLE))
502: || ((v > 0) && (v < Limits.DB2_SMALLEST_POSITIVE_DOUBLE))
503: || ((v < 0) && (v > Limits.DB2_LARGEST_NEGATIVE_DOUBLE))) {
504: throw StandardException.newException(
505: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
506: TypeId.DOUBLE_NAME);
507: }
508: // Normalize negative doubles to be "positive" (can't detect easily without using Double object because -0.0f = 0.0f)
509: if (v == 0.0d)
510: v = 0.0d;
511:
512: return v;
513: }
514:
515: }
|