KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > iapi > types > NumberDataType


1 /*
2
3    Derby - Class org.apache.derby.iapi.types.NumberDataType
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.iapi.types;
23
24 import org.apache.derby.iapi.error.StandardException;
25 import org.apache.derby.iapi.types.NumberDataValue;
26 import org.apache.derby.iapi.services.sanity.SanityManager;
27 import org.apache.derby.iapi.services.io.Storable;
28 import org.apache.derby.iapi.types.Orderable;
29 import org.apache.derby.iapi.types.DataValueDescriptor;
30 import org.apache.derby.iapi.types.TypeId;
31 import org.apache.derby.iapi.reference.SQLState;
32 import org.apache.derby.iapi.reference.Limits;
33
34 import org.apache.derby.iapi.types.*;
35
36 /**
37  * NumberDataType is the superclass for all exact and approximate
38  * numeric data types. It exists for the purpose of allowing classification
39  * of types for supported implicit conversions among them.
40  *
41  * @see DataType
42  * @author ames
43  */

44 public abstract class NumberDataType extends DataType
45                                      implements NumberDataValue
46 {
47     /**
48      * Set by the booting DataValueFactory implementation.
49      */

50     static DataValueDescriptor ZERO_DECIMAL;
51     
52     /**
53      * Set by the booting DataValueFactory implementation.
54      */

55     static Comparable JavaDoc MINLONG_MINUS_ONE;
56     /**
57      * Set by the booting DataValueFactory implementation.
58      */

59     static Comparable JavaDoc MAXLONG_PLUS_ONE;
60
61     /**
62      * Numbers check for isNegative first and negate it if negative.
63      *
64      * @return this object's absolute value. Null if object is null.
65      * @exception StandardException thrown on error.
66      */

67     public final NumberDataValue absolute(NumberDataValue result)
68                         throws StandardException
69     {
70         if(isNegative())
71             return minus(result);
72
73         if(result == null)
74             result = (NumberDataType)getNewNull();
75         
76         result.setValue(this);
77         return result;
78     }
79
80     /**
81      * This is the sqrt method.
82      *
83      * @return this object's sqrt value. Null if object is null.
84      * Note: -0.0f and -0.0d returns 0.0f and 0.0d.
85      *
86      * @exception StandardException thrown on a negative number.
87      */

88
89     public NumberDataValue sqrt(NumberDataValue result)
90                         throws StandardException
91     {
92         if(result == null)
93         {
94             result = (NumberDataValue)getNewNull();
95         }
96
97         if(this.isNull())
98         {
99             result.setToNull();
100             return result;
101         }
102
103         double doubleValue = getDouble();
104
105         if( this.isNegative() )
106         {
107             if( (new Double JavaDoc(doubleValue)).equals(new Double JavaDoc(-0.0d)) )
108             {
109                 doubleValue = 0.0d;
110             }
111             else
112             {
113                 throw StandardException.newException( SQLState.LANG_SQRT_OF_NEG_NUMBER, this);
114             }
115         }
116
117         result.setValue( Math.sqrt(doubleValue) );
118         return result;
119     }
120     
121     /**
122      * This method implements the + operator for TINYINT,SMALLINT,INT.
123      *
124      * @param addend1 One of the addends
125      * @param addend2 The other addend
126      * @param result The result of a previous call to this method, null
127      * if not called yet
128      *
129      * @return A NumberDataValue containing the result of the addition
130      *
131      * @exception StandardException Thrown on error
132      */

133
134     public NumberDataValue plus(NumberDataValue addend1,
135                             NumberDataValue addend2,
136                             NumberDataValue result)
137                 throws StandardException
138     {
139         if (result == null)
140         {
141             result = (NumberDataValue) getNewNull();
142         }
143
144         if (addend1.isNull() || addend2.isNull())
145         {
146             result.setToNull();
147             return result;
148         }
149         int addend1Int = addend1.getInt();
150         int addend2Int = addend2.getInt();
151
152         int resultValue = addend1Int + addend2Int;
153
154         /*
155         ** Java does not check for overflow with integral types. We have to
156         ** check the result ourselves.
157         **
158         ** Overflow is possible only if the two addends have the same sign.
159         ** Do they? (This method of checking is approved by "The Java
160         ** Programming Language" by Arnold and Gosling.)
161         */

162         if ((addend1Int < 0) == (addend2Int < 0))
163         {
164             /*
165             ** Addends have the same sign. The result should have the same
166             ** sign as the addends. If not, an overflow has occurred.
167             */

168             if ((addend1Int < 0) != (resultValue < 0))
169             {
170                 throw outOfRange();
171             }
172         }
173
174         result.setValue(resultValue);
175
176         return result;
177     }
178     /**
179      * This method implements the - operator for TINYINT, SMALLINT and INTEGER.
180      *
181      * @param left The value to be subtracted from
182      * @param right The value to be subtracted
183      * @param result The result of a previous call to this method, null
184      * if not called yet
185      *
186      * @return A SQLInteger containing the result of the subtraction
187      *
188      * @exception StandardException Thrown on error
189      */

190
191     public NumberDataValue minus(NumberDataValue left,
192                             NumberDataValue right,
193                             NumberDataValue result)
194                 throws StandardException
195     {
196         if (result == null)
197         {
198             result = (NumberDataValue) getNewNull();
199         }
200
201         if (left.isNull() || right.isNull())
202         {
203             result.setToNull();
204             return result;
205         }
206
207         int diff = left.getInt() - right.getInt();
208
209         /*
210         ** Java does not check for overflow with integral types. We have to
211         ** check the result ourselves.
212         **
213         ** Overflow is possible only if the left and the right side have opposite signs.
214         ** Do they? (This method of checking is approved by "The Java
215         ** Programming Language" by Arnold and Gosling.)
216         */

217         if ((left.getInt() < 0) != (right.getInt() < 0))
218         {
219             /*
220             ** Left and right have opposite signs. The result should have the same
221             ** sign as the left (this). If not, an overflow has occurred.
222             */

223             if ((left.getInt() < 0) != (diff < 0))
224             {
225                 throw outOfRange();
226             }
227         }
228
229         result.setValue(diff);
230
231         return result;
232     }
233     
234     /**
235      * This method implements the / operator for TINYINT, SMALLINT and INTEGER.
236      * Specialized methods are not required for TINYINT and SMALLINT as the Java
237      * virtual machine always executes byte and int division as integer.
238      *
239      * @param dividend The numerator
240      * @param divisor The denominator
241      * @param result The result of a previous call to this method, null
242      * if not called yet
243      *
244      * @return A SQLInteger containing the result of the division
245      *
246      * @exception StandardException Thrown on error
247      */

248
249     public NumberDataValue divide(NumberDataValue dividend,
250                              NumberDataValue divisor,
251                              NumberDataValue result)
252                 throws StandardException
253     {
254         if (result == null)
255         {
256             result = (NumberDataValue) getNewNull();
257         }
258
259         if (dividend.isNull() || divisor.isNull())
260         {
261             result.setToNull();
262             return result;
263         }
264
265         /* Catch divide by 0 */
266         int intDivisor = divisor.getInt();
267         if (intDivisor == 0)
268         {
269             throw StandardException.newException(SQLState.LANG_DIVIDE_BY_ZERO);
270         }
271
272         result.setValue(dividend.getInt() / intDivisor);
273         return result;
274     }
275
276     /**
277         Suitable for integral types that ignore scale.
278      */

279     public NumberDataValue divide(NumberDataValue dividend,
280                                   NumberDataValue divisor,
281                                   NumberDataValue result,
282                                   int scale)
283                 throws StandardException
284     {
285         return divide(dividend, divisor, result);
286     }
287
288     public NumberDataValue mod(NumberDataValue dividend,
289                                 NumberDataValue divisor,
290                                 NumberDataValue result)
291                                 throws StandardException {
292         if (SanityManager.DEBUG)
293             SanityManager.NOTREACHED();
294         return null;
295     }
296
297     /** @exception StandardException Thrown on error */
298     public final int compare(DataValueDescriptor arg) throws StandardException
299     {
300         /* Use compare method from dominant type, negating result
301          * to reflect flipping of sides.
302          */

303         if (typePrecedence() < arg.typePrecedence())
304         {
305             return - (arg.compare(this));
306         }
307
308
309         boolean thisNull, otherNull;
310
311         thisNull = this.isNull();
312         otherNull = arg.isNull();
313
314         /*
315          * thisNull otherNull return
316          * T T 0 (this == other)
317          * F T -1 (this > other)
318          * T F 1 (this < other)
319          */

320         if (thisNull || otherNull)
321         {
322             if (!thisNull) // otherNull must be true
323
return -1;
324             if (!otherNull) // thisNull must be true
325
return 1;
326             return 0;
327         }
328
329         return typeCompare(arg);
330
331     }
332     /**
333         Compare this (not null) to a non-null value.
334     
335     @exception StandardException Thrown on error
336     */

337     protected abstract int typeCompare(DataValueDescriptor arg) throws StandardException;
338
339     /**
340         @exception StandardException thrown on error
341      */

342     public final boolean compare(int op,
343                            DataValueDescriptor other,
344                            boolean orderedNulls,
345                            boolean unknownRV)
346         throws StandardException
347     {
348         if (!orderedNulls) // nulls are unordered
349
{
350             if (this.isNull() || other.isNull())
351                 return unknownRV;
352         }
353
354         /* Do the comparison */
355         return super.compare(op, other, orderedNulls, unknownRV);
356     }
357     
358     /**
359      * The isNegative abstract method. Checks to see if this.value is negative.
360      * To be implemented by each NumberDataType.
361      *
362      * @return A boolean. If this.value is negative, return true.
363      * For positive values or null, return false.
364      */

365     protected abstract boolean isNegative();
366     
367     /**
368      * Common code to handle converting a short to this value
369      * by using the int to this value conversion.
370      * Simply calls setValue(int).
371      *
372      */

373     public void setValue(short theValue)
374         throws StandardException
375     {
376         setValue((int) theValue);
377     }
378
379     /**
380      * Common code to handle converting a byte to this value
381      * by using the int to this value conversion.
382      * Simply calls setValue(int).
383      *
384      */

385     public void setValue(byte theValue)
386         throws StandardException
387     {
388         setValue((int) theValue);
389     }
390     /**
391        Common code to handle java.lang.Integer as a Number,
392        used for TINYINT, SMALLINT, INTEGER
393      * @see NumberDataValue#setValue
394      *
395      * @exception StandardException Thrown on error
396      */

397     public void setValue(Number JavaDoc theValue) throws StandardException
398     {
399         if (objectNull(theValue))
400             return;
401         
402         if (SanityManager.ASSERT)
403         {
404             if (!(theValue instanceof java.lang.Integer JavaDoc))
405                 SanityManager.THROWASSERT("NumberDataType.setValue(Number) passed a " + theValue.getClass());
406         }
407         
408         setValue(theValue.intValue());
409     }
410     
411     /**
412      * Set the value from a correctly typed Integer object.
413      * Used for TINYINT, SMALLINT, INTEGER.
414      * @throws StandardException
415      */

416     void setObject(Object JavaDoc theValue) throws StandardException
417     {
418         setValue(((Integer JavaDoc) theValue).intValue());
419     }
420
421     /**
422         setValue for integral exact numerics. Converts the BigDecimal
423         to a long to preserve precision
424     */

425     public void setBigDecimal(Number JavaDoc bigDecimal) throws StandardException
426     {
427         if (objectNull(bigDecimal))
428             return;
429
430         Comparable JavaDoc bdc = (Comparable JavaDoc) bigDecimal;
431
432
433         // See comment in SQLDecimal.getLong()
434

435         if ( (bdc.compareTo(NumberDataType.MINLONG_MINUS_ONE) == 1)
436             && (bdc.compareTo(NumberDataType.MAXLONG_PLUS_ONE) == -1)) {
437
438             setValue(bigDecimal.longValue());
439         } else {
440
441             throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, getTypeName());
442         }
443     }
444     
445     /**
446      * Implementation for integral types. Convert to a BigDecimal using long
447      */

448     public int typeToBigDecimal()
449     {
450         return java.sql.Types.BIGINT;
451     }
452     /**
453         Return the precision of this specific DECIMAL value.
454         If the value does not represent a SQL DECIMAL then
455         the return is undefined.
456     */

457     public int getDecimalValuePrecision()
458     {
459         return -1;
460     }
461
462     /**
463         Return the scale of this specific DECIMAL value.
464         If the value does not represent a SQL DECIMAL then
465         the return is undefined.
466     */

467     public int getDecimalValueScale()
468     {
469         return -1;
470     }
471    
472     protected final boolean objectNull(Object JavaDoc o)
473     {
474         if (o == null)
475         {
476             restoreToNull();
477             return true;
478         }
479         return false;
480     }
481
482     /**
483        normalizeREAL checks the validity of the given java float that
484        it fits within the range of DB2 REALs. In addition it
485        normalizes the value, so that negative zero (-0.0) becomes positive.
486     */

487     public static float normalizeREAL(float v) throws StandardException
488     {
489         if ( (Float.isNaN(v) || Float.isInfinite(v)) ||
490              ((v < Limits.DB2_SMALLEST_REAL) || (v > Limits.DB2_LARGEST_REAL)) ||
491              ((v > 0) && (v < Limits.DB2_SMALLEST_POSITIVE_REAL)) ||
492              ((v < 0) && (v > Limits.DB2_LARGEST_NEGATIVE_REAL)) )
493         {
494             throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, TypeId.REAL_NAME);
495         }
496         // Normalize negative floats to be "positive" (can't detect easily without using Float object because -0.0f = 0.0f)
497
if (v == 0.0f) v = 0.0f;
498
499         return v;
500     }
501
502     /**
503        normalizeREAL checks the validity of the given java double that
504        it fits within the range of DB2 REALs. In addition it
505        normalizes the value, so that negative zero (-0.0) becomes positive.
506
507        The reason for having normalizeREAL with two signatures is to
508        avoid that normalizeREAL is called with a casted (float)doublevalue,
509        since this invokes an unwanted rounding (of underflow values to 0.0),
510        in contradiction to DB2s casting semantics.
511     */

512     public static float normalizeREAL(double v) throws StandardException
513     {
514         // can't just cast it to float and call normalizeFloat(float) since casting can round down to 0.0
515
if ( (Double.isNaN(v) || Double.isInfinite(v)) ||
516              ((v < Limits.DB2_SMALLEST_REAL) || (v > Limits.DB2_LARGEST_REAL)) ||
517              ((v > 0) && (v < Limits.DB2_SMALLEST_POSITIVE_REAL)) ||
518              ((v < 0) && (v > Limits.DB2_LARGEST_NEGATIVE_REAL)) )
519         {
520             throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, TypeId.REAL_NAME);
521         }
522         // Normalize negative floats to be "positive" (can't detect easily without using Float object because -0.0f = 0.0f)
523
if (v == 0.0d) v = 0.0d;
524
525         return (float)v;
526     }
527
528     /**
529        normalizeDOUBLE checks the validity of the given java double that
530        it fits within the range of DB2 DOUBLEs. In addition it
531        normalizes the value, so that negative zero (-0.0) becomes positive.
532     */

533     public static double normalizeDOUBLE(double v) throws StandardException
534     {
535         if ( (Double.isNaN(v) || Double.isInfinite(v)) ||
536              ((v < Limits.DB2_SMALLEST_DOUBLE) || (v > Limits.DB2_LARGEST_DOUBLE)) ||
537              ((v > 0) && (v < Limits.DB2_SMALLEST_POSITIVE_DOUBLE)) ||
538              ((v < 0) && (v > Limits.DB2_LARGEST_NEGATIVE_DOUBLE)) )
539         {
540             throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, TypeId.DOUBLE_NAME);
541         }
542         // Normalize negative doubles to be "positive" (can't detect easily without using Double object because -0.0f = 0.0f)
543
if (v == 0.0d) v = 0.0d;
544
545         return v;
546     }
547
548
549 }
550
551
Popular Tags