001: /*
002:
003: Derby - Class org.apache.derby.iapi.types.SQLDouble
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.reference.SQLState;
025:
026: import org.apache.derby.iapi.services.io.ArrayInputStream;
027:
028: import org.apache.derby.iapi.services.io.StoredFormatIds;
029: import org.apache.derby.iapi.services.io.Storable;
030:
031: import org.apache.derby.iapi.services.sanity.SanityManager;
032:
033: import org.apache.derby.iapi.error.StandardException;
034:
035: import org.apache.derby.iapi.types.BooleanDataValue;
036: import org.apache.derby.iapi.types.DataValueDescriptor;
037: import org.apache.derby.iapi.types.NumberDataValue;
038: import org.apache.derby.iapi.types.TypeId;
039:
040: import org.apache.derby.iapi.services.cache.ClassSize;
041:
042: import org.apache.derby.iapi.types.NumberDataType;
043: import org.apache.derby.iapi.types.SQLBoolean;
044:
045: import java.io.ObjectOutput;
046: import java.io.ObjectInput;
047: import java.io.IOException;
048:
049: import java.sql.ResultSet;
050: import java.sql.PreparedStatement;
051: import java.sql.SQLException;
052:
053: /**
054: * SQLDouble satisfies the DataValueDescriptor
055: * interfaces (i.e., OrderableDataType). It implements a double column,
056: * e.g. for * storing a column value; it can be specified
057: * when constructed to not allow nulls. Nullability cannot be changed
058: * after construction, as it affects the storage size and mechanism.
059: * <p>
060: * Because OrderableDataType is a subtype of DataType,
061: * SQLDouble can play a role in either a DataType/Row
062: * or a OrderableDataType/Row, interchangeably.
063: * <p>
064: * We assume the store has a flag for nullness of the value,
065: * and simply return a 0-length array for the stored form
066: * when the value is null.
067: * <p>
068: * PERFORMANCE: There are likely alot of performance improvements
069: * possible for this implementation -- it new's Double
070: * more than it probably wants to.
071: * <p>
072: * This is modeled after SQLInteger.
073: * <p>
074: * We don't let doubles get constructed with NaN or Infinity values, and
075: * check for those values where they can occur on operations, so the
076: * set* operations do not check for them coming in.
077: *
078: * @author ames
079: */
080: public final class SQLDouble extends NumberDataType {
081:
082: /*
083: * DataValueDescriptor interface
084: * (mostly implemented in DataType)
085: */
086:
087: // JDBC is lax in what it permits and what it
088: // returns, so we are similarly lax
089: // @see DataValueDescriptor
090: /**
091: * @exception StandardException thrown on failure to convert
092: */
093: public int getInt() throws StandardException {
094: // REMIND: do we want to check for truncation?
095: if ((value > (((double) Integer.MAX_VALUE) + 1.0d))
096: || (value < (((double) Integer.MIN_VALUE) - 1.0d)))
097: throw StandardException
098: .newException(
099: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
100: "INTEGER");
101: return (int) value;
102: }
103:
104: /**
105: * @exception StandardException thrown on failure to convert
106: */
107: public byte getByte() throws StandardException {
108: if ((value > (((double) Byte.MAX_VALUE) + 1.0d))
109: || (value < (((double) Byte.MIN_VALUE) - 1.0d)))
110: throw StandardException
111: .newException(
112: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
113: "TINYINT");
114: return (byte) value;
115: }
116:
117: /**
118: * @exception StandardException thrown on failure to convert
119: */
120: public short getShort() throws StandardException {
121: if ((value > (((double) Short.MAX_VALUE) + 1.0d))
122: || (value < (((double) Short.MIN_VALUE) - 1.0d)))
123: throw StandardException.newException(
124: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
125: "SMALLINT");
126: return (short) value;
127: }
128:
129: /**
130: * @exception StandardException thrown on failure to convert
131: */
132: public long getLong() throws StandardException {
133: if ((value > (((double) Long.MAX_VALUE) + 1.0d))
134: || (value < (((double) Long.MIN_VALUE) - 1.0d)))
135: throw StandardException.newException(
136: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "BIGINT");
137: return (long) value;
138: }
139:
140: /**
141: * @exception StandardException thrown on failure to convert
142: */
143: public float getFloat() throws StandardException {
144: if (Float.isInfinite((float) value))
145: throw StandardException.newException(
146: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
147: TypeId.REAL_NAME);
148: return (float) value;
149: }
150:
151: public double getDouble() {
152: /* This value is bogus if the SQLDouble is null */
153: return value;
154: }
155:
156: /**
157: * DOUBLE implementation. Convert to a BigDecimal using getString.
158: */
159: public int typeToBigDecimal() {
160: return java.sql.Types.CHAR;
161: }
162:
163: // for lack of a specification: getDouble()==0 gives true
164: // independent of the NULL flag
165: public boolean getBoolean() {
166: return (value != 0);
167: }
168:
169: public String getString() {
170: if (isNull())
171: return null;
172: else
173: return Double.toString(value);
174: }
175:
176: public Object getObject() {
177: // REMIND: could create one Double and reuse it?
178: if (isNull())
179: return null;
180: else
181: return new Double(value);
182: }
183:
184: /**
185: * Set the value from a correctly typed Double object.
186: * @throws StandardException
187: */
188: void setObject(Object theValue) throws StandardException {
189: setValue(((Double) theValue).doubleValue());
190: }
191:
192: protected void setFrom(DataValueDescriptor theValue)
193: throws StandardException {
194: setValue(theValue.getDouble());
195: }
196:
197: public int getLength() {
198: return DOUBLE_LENGTH;
199: }
200:
201: // this is for DataType's error generator
202: public String getTypeName() {
203: return TypeId.DOUBLE_NAME;
204: }
205:
206: /*
207: * Storable interface, implies Externalizable, TypedFormat
208: */
209:
210: /**
211: Return my format identifier.
212:
213: @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId
214: */
215: public int getTypeFormatId() {
216: return StoredFormatIds.SQL_DOUBLE_ID;
217: }
218:
219: /*
220: * see if the double value is null.
221: */
222: /** @see Storable#isNull */
223: public boolean isNull() {
224: return isnull;
225: }
226:
227: public void writeExternal(ObjectOutput out) throws IOException {
228:
229: // never called when value is null
230: if (SanityManager.DEBUG)
231: SanityManager.ASSERT(!isNull());
232:
233: out.writeDouble(value);
234: }
235:
236: /** @see java.io.Externalizable#readExternal */
237: public void readExternal(ObjectInput in) throws IOException {
238:
239: value = in.readDouble();
240: isnull = false;
241: }
242:
243: /** @see java.io.Externalizable#readExternal */
244: public void readExternalFromArray(ArrayInputStream in)
245: throws IOException {
246:
247: value = in.readDouble();
248: isnull = false;
249: }
250:
251: /**
252: * @see Storable#restoreToNull
253: *
254: */
255:
256: public void restoreToNull() {
257: value = 0;
258: isnull = true;
259: }
260:
261: /** @exception StandardException Thrown on error */
262: protected int typeCompare(DataValueDescriptor arg)
263: throws StandardException {
264: /* neither are null, get the value */
265:
266: double this Value = this .getDouble();
267:
268: double otherValue = arg.getDouble();
269:
270: if (this Value == otherValue)
271: return 0;
272: else if (this Value > otherValue)
273: return 1;
274: else
275: return -1;
276: }
277:
278: /*
279: * DataValueDescriptor interface
280: */
281:
282: /** @see DataValueDescriptor#getClone */
283: public DataValueDescriptor getClone() {
284: try {
285: return new SQLDouble(value, isnull);
286: } catch (StandardException se) {
287: if (SanityManager.DEBUG)
288: SanityManager.THROWASSERT("error on clone, se = " + se
289: + " value = " + value + " isnull = " + isnull);
290: return null;
291: }
292: }
293:
294: /**
295: * @see DataValueDescriptor#getNewNull
296: */
297: public DataValueDescriptor getNewNull() {
298: return new SQLDouble();
299: }
300:
301: /**
302: * @see DataValueDescriptor#setValueFromResultSet
303: *
304: * @exception StandardException Thrown on error
305: * @exception SQLException Thrown on error
306: */
307: public void setValueFromResultSet(ResultSet resultSet,
308: int colNumber, boolean isNullable)
309: throws StandardException, SQLException {
310: double dv = resultSet.getDouble(colNumber);
311: isnull = (isNullable && resultSet.wasNull());
312: if (isnull)
313: value = 0;
314: else
315: value = NumberDataType.normalizeDOUBLE(dv);
316: }
317:
318: /**
319: Set the value into a PreparedStatement.
320:
321: @exception SQLException Error setting value in PreparedStatement
322: */
323: public final void setInto(PreparedStatement ps, int position)
324: throws SQLException {
325:
326: if (isNull()) {
327: ps.setNull(position, java.sql.Types.DOUBLE);
328: return;
329: }
330:
331: ps.setDouble(position, value);
332: }
333:
334: /**
335: Set this value into a ResultSet for a subsequent ResultSet.insertRow
336: or ResultSet.updateRow. This method will only be called for non-null values.
337:
338: @exception SQLException thrown by the ResultSet object
339: @exception StandardException thrown by me accessing my value.
340: */
341: public final void setInto(ResultSet rs, int position)
342: throws SQLException, StandardException {
343: rs.updateDouble(position, value);
344: }
345:
346: /*
347: * class interface
348: */
349:
350: /*
351: * constructors
352: */
353:
354: /** no-arg constructor, required by Formattable */
355: // This constructor also gets used when we are
356: // allocating space for a double.
357: public SQLDouble() {
358: isnull = true;
359: }
360:
361: public SQLDouble(double val) throws StandardException {
362: value = NumberDataType.normalizeDOUBLE(val);
363: }
364:
365: public SQLDouble(Double obj) throws StandardException {
366: if (isnull = (obj == null))
367: ;
368: else
369: value = NumberDataType.normalizeDOUBLE(obj.doubleValue());
370: }
371:
372: private SQLDouble(double val, boolean startsnull)
373: throws StandardException {
374: value = NumberDataType.normalizeDOUBLE(val); // maybe only do if !startsnull
375: isnull = startsnull;
376: }
377:
378: /**
379: @exception StandardException throws NumberFormatException
380: when the String format is not recognized.
381: */
382: public void setValue(String theValue) throws StandardException {
383: if (theValue == null) {
384: value = 0;
385: isnull = true;
386: } else {
387: double doubleValue = 0;
388: try {
389: // ??? jsk: rounding???
390: doubleValue = Double.valueOf(theValue.trim())
391: .doubleValue();
392: } catch (NumberFormatException nfe) {
393: throw invalidFormat();
394: }
395: value = NumberDataType.normalizeDOUBLE(doubleValue);
396: isnull = false;
397: }
398: }
399:
400: /**
401: * @exception StandardException on NaN or Infinite double
402: */
403: public void setValue(double theValue) throws StandardException {
404: value = NumberDataType.normalizeDOUBLE(theValue);
405: isnull = false;
406: }
407:
408: /**
409: * @exception StandardException on NaN or Infinite float
410: */
411: public void setValue(float theValue) throws StandardException {
412: value = NumberDataType.normalizeDOUBLE(theValue);
413: isnull = false;
414: }
415:
416: public void setValue(long theValue) {
417: value = theValue; // no check needed
418: isnull = false;
419: }
420:
421: public void setValue(int theValue) {
422: value = theValue; // no check needed
423: isnull = false;
424: }
425:
426: public void setValue(Number theValue) throws StandardException {
427: if (objectNull(theValue))
428: return;
429:
430: if (SanityManager.ASSERT) {
431: if (!(theValue instanceof java.lang.Double))
432: SanityManager
433: .THROWASSERT("SQLDouble.setValue(Number) passed a "
434: + theValue.getClass());
435: }
436:
437: setValue(theValue.doubleValue());
438: }
439:
440: /**
441: Called for an application setting this value using a BigDecimal
442: */
443: public void setBigDecimal(Number bigDecimal)
444: throws StandardException {
445: if (objectNull(bigDecimal))
446: return;
447:
448: // Note BigDecimal.doubleValue() handles the case where
449: // its value is outside the range of a double. It returns
450: // infinity values which should throw an exception in setValue(double).
451: setValue(bigDecimal.doubleValue());
452:
453: }
454:
455: /**
456: * @see NumberDataValue#setValue
457: *
458: */
459: public void setValue(boolean theValue) {
460: value = theValue ? 1 : 0;
461: isnull = false;
462: }
463:
464: /*
465: * DataValueDescriptor interface
466: */
467:
468: /** @see DataValueDescriptor#typePrecedence */
469: public int typePrecedence() {
470: return TypeId.DOUBLE_PRECEDENCE;
471: }
472:
473: /*
474: ** SQL Operators
475: */
476:
477: /**
478: * The = operator as called from the language module, as opposed to
479: * the storage module.
480: *
481: * @param left The value on the left side of the =
482: * @param right The value on the right side of the =
483: * is not.
484: *
485: * @return A SQL boolean value telling whether the two parameters are equal
486: *
487: * @exception StandardException Thrown on error
488: */
489:
490: public BooleanDataValue equals(DataValueDescriptor left,
491: DataValueDescriptor right) throws StandardException {
492: return SQLBoolean.truthValue(left, right,
493: left.getDouble() == right.getDouble());
494: }
495:
496: /**
497: * The <> operator as called from the language module, as opposed to
498: * the storage module.
499: *
500: * @param left The value on the left side of the <>
501: * @param right The value on the right side of the <>
502: * is not.
503: *
504: * @return A SQL boolean value telling whether the two parameters
505: * are not equal
506: *
507: * @exception StandardException Thrown on error
508: */
509:
510: public BooleanDataValue notEquals(DataValueDescriptor left,
511: DataValueDescriptor right) throws StandardException {
512: return SQLBoolean.truthValue(left, right,
513: left.getDouble() != right.getDouble());
514: }
515:
516: /**
517: * The < operator as called from the language module, as opposed to
518: * the storage module.
519: *
520: * @param left The value on the left side of the <
521: * @param right The value on the right side of the <
522: *
523: * @return A SQL boolean value telling whether the first operand is less
524: * than the second operand
525: *
526: * @exception StandardException Thrown on error
527: */
528:
529: public BooleanDataValue lessThan(DataValueDescriptor left,
530: DataValueDescriptor right) throws StandardException {
531: return SQLBoolean.truthValue(left, right,
532: left.getDouble() < right.getDouble());
533: }
534:
535: /**
536: * The > operator as called from the language module, as opposed to
537: * the storage module.
538: *
539: * @param left The value on the left side of the >
540: * @param right The value on the right side of the >
541: *
542: * @return A SQL boolean value telling whether the first operand is greater
543: * than the second operand
544: *
545: * @exception StandardException Thrown on error
546: */
547:
548: public BooleanDataValue greaterThan(DataValueDescriptor left,
549: DataValueDescriptor right) throws StandardException {
550: return SQLBoolean.truthValue(left, right,
551: left.getDouble() > right.getDouble());
552: }
553:
554: /**
555: * The <= operator as called from the language module, as opposed to
556: * the storage module.
557: *
558: * @param left The value on the left side of the <=
559: * @param right The value on the right side of the <=
560: *
561: * @return A SQL boolean value telling whether the first operand is less
562: * than or equal to the second operand
563: *
564: * @exception StandardException Thrown on error
565: */
566:
567: public BooleanDataValue lessOrEquals(DataValueDescriptor left,
568: DataValueDescriptor right) throws StandardException {
569: return SQLBoolean.truthValue(left, right,
570: left.getDouble() <= right.getDouble());
571: }
572:
573: /**
574: * The >= operator as called from the language module, as opposed to
575: * the storage module.
576: *
577: * @param left The value on the left side of the >=
578: * @param right The value on the right side of the >=
579: *
580: * @return A SQL boolean value telling whether the first operand is greater
581: * than or equal to the second operand
582: *
583: * @exception StandardException Thrown on error
584: */
585:
586: public BooleanDataValue greaterOrEquals(DataValueDescriptor left,
587: DataValueDescriptor right) throws StandardException {
588: return SQLBoolean.truthValue(left, right,
589: left.getDouble() >= right.getDouble());
590: }
591:
592: /**
593: * This method implements the + operator for "double + double".
594: *
595: * @param addend1 One of the addends
596: * @param addend2 The other addend
597: * @param result The result of a previous call to this method, null
598: * if not called yet
599: *
600: * @return A SQLDouble containing the result of the addition
601: *
602: * @exception StandardException Thrown on error
603: */
604:
605: public NumberDataValue plus(NumberDataValue addend1,
606: NumberDataValue addend2, NumberDataValue result)
607: throws StandardException {
608: if (result == null) {
609: result = new SQLDouble();
610: }
611:
612: if (addend1.isNull() || addend2.isNull()) {
613: result.setToNull();
614: return result;
615: }
616:
617: double tmpresult = addend1.getDouble() + addend2.getDouble();
618: // No need to check underflow (result rounded to 0.0),
619: // since the difference between two non-equal valid DB2 DOUBLE values is always non-zero in java.lang.Double precision.
620: result.setValue(tmpresult);
621:
622: return result;
623: }
624:
625: /**
626: * This method implements the - operator for "double - double".
627: *
628: * @param left The value to be subtracted from
629: * @param right The value to be subtracted
630: * @param result The result of a previous call to this method, null
631: * if not called yet
632: *
633: * @return A SQLDouble containing the result of the subtraction
634: *
635: * @exception StandardException Thrown on error
636: */
637:
638: public NumberDataValue minus(NumberDataValue left,
639: NumberDataValue right, NumberDataValue result)
640: throws StandardException {
641: if (result == null) {
642: result = new SQLDouble();
643: }
644:
645: if (left.isNull() || right.isNull()) {
646: result.setToNull();
647: return result;
648: }
649:
650: double tmpresult = left.getDouble() - right.getDouble();
651: // No need to check underflow (result rounded to 0.0),
652: // since no difference between two valid DB2 DOUBLE values can be rounded off to 0.0 in java.lang.Double
653: result.setValue(tmpresult);
654: return result;
655: }
656:
657: /**
658: * This method implements the * operator for "double * double".
659: *
660: * @param left The first value to be multiplied
661: * @param right The second value to be multiplied
662: * @param result The result of a previous call to this method, null
663: * if not called yet
664: *
665: * @return A SQLDouble containing the result of the multiplication
666: *
667: * @exception StandardException Thrown on error
668: */
669:
670: public NumberDataValue times(NumberDataValue left,
671: NumberDataValue right, NumberDataValue result)
672: throws StandardException {
673: if (result == null) {
674: result = new SQLDouble();
675: }
676:
677: if (left.isNull() || right.isNull()) {
678: result.setToNull();
679: return result;
680: }
681:
682: double leftValue = left.getDouble();
683: double rightValue = right.getDouble();
684: double tempResult = leftValue * rightValue;
685: // check underflow (result rounded to 0.0)
686: if ((tempResult == 0.0)
687: && ((leftValue != 0.0) && (rightValue != 0.0))) {
688: throw StandardException.newException(
689: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
690: TypeId.DOUBLE_NAME);
691: }
692:
693: result.setValue(tempResult);
694: return result;
695: }
696:
697: /**
698: * This method implements the / operator for "double / double".
699: *
700: * @param dividend The numerator
701: * @param divisor The denominator
702: * @param result The result of a previous call to this method, null
703: * if not called yet
704: *
705: * @return A SQLDouble containing the result of the division
706: *
707: * @exception StandardException Thrown on error
708: */
709:
710: public NumberDataValue divide(NumberDataValue dividend,
711: NumberDataValue divisor, NumberDataValue result)
712: throws StandardException {
713: if (result == null) {
714: result = new SQLDouble();
715: }
716:
717: if (dividend.isNull() || divisor.isNull()) {
718: result.setToNull();
719: return result;
720: }
721:
722: /*
723: ** For double division, we can't catch divide by zero with Double.NaN;
724: ** So we check the divisor before the division.
725: */
726:
727: double divisorValue = divisor.getDouble();
728:
729: if (divisorValue == 0.0e0D) {
730: throw StandardException
731: .newException(SQLState.LANG_DIVIDE_BY_ZERO);
732: }
733:
734: double dividendValue = dividend.getDouble();
735: double divideResult = dividendValue / divisorValue;
736:
737: if (Double.isNaN(divideResult)) {
738: throw StandardException
739: .newException(SQLState.LANG_DIVIDE_BY_ZERO);
740: }
741:
742: // check underflow (result rounded to 0.0d)
743: if ((divideResult == 0.0d) && (dividendValue != 0.0d)) {
744: throw StandardException.newException(
745: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
746: TypeId.DOUBLE_NAME);
747: }
748:
749: result.setValue(divideResult);
750: return result;
751: }
752:
753: /**
754: * This method implements the unary minus operator for double.
755: *
756: * @param result The result of a previous call to this method, null
757: * if not called yet
758: *
759: * @return A SQLDouble containing the result of the division
760: *
761: * @exception StandardException Thrown on error
762: */
763:
764: public NumberDataValue minus(NumberDataValue result)
765: throws StandardException {
766: double minusResult;
767:
768: if (result == null) {
769: result = new SQLDouble();
770: }
771:
772: if (this .isNull()) {
773: result.setToNull();
774: return result;
775: }
776:
777: /*
778: ** Doubles are assumed to be symmetric -- that is, their
779: ** smallest negative value is representable as a positive
780: ** value, and vice-versa.
781: */
782: minusResult = -(this .getDouble());
783:
784: result.setValue(minusResult);
785: return result;
786: }
787:
788: /**
789: * This method implements the isNegative method.
790: *
791: * @return A boolean. If this.value is negative, return true.
792: * For positive values or null, return false.
793: */
794:
795: protected boolean isNegative() {
796: return !isNull() && (value < 0.0d);
797: }
798:
799: /*
800: * String display of value
801: */
802:
803: public String toString() {
804: if (isNull())
805: return "NULL";
806: else
807: return Double.toString(value);
808: }
809:
810: /*
811: * Hash code
812: */
813: public int hashCode() {
814: long longVal = (long) value;
815: double doubleLongVal = (double) longVal;
816:
817: /*
818: ** NOTE: This is coded to work around a bug in Visual Cafe 3.0.
819: ** If longVal is compared directly to value on that platform
820: ** with the JIT enabled, the values will not always compare
821: ** as equal even when they should be equal. This happens with
822: ** the value Long.MAX_VALUE, for example.
823: **
824: ** Assigning the long value back to a double and then doing
825: ** the comparison works around the bug.
826: **
827: ** This fixes Cloudscape bug number 1757.
828: **
829: ** - Jeff Lichtman
830: */
831: if (doubleLongVal != value) {
832: longVal = Double.doubleToLongBits(value);
833: }
834:
835: return (int) (longVal ^ (longVal >> 32));
836: }
837:
838: /*
839: * useful constants...
840: */
841: static final int DOUBLE_LENGTH = 32; // must match the number of bytes written by DataOutput.writeDouble()
842:
843: private static final int BASE_MEMORY_USAGE = ClassSize
844: .estimateBaseFromCatalog(SQLDouble.class);
845:
846: public int estimateMemoryUsage() {
847: return BASE_MEMORY_USAGE;
848: }
849:
850: /*
851: * object state
852: */
853: private double value;
854: private boolean isnull;
855: }
|