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