001: /*
002:
003: Derby - Class org.apache.derby.iapi.types.SQLTinyint
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.sanity.SanityManager;
029: import org.apache.derby.iapi.services.io.StoredFormatIds;
030: import org.apache.derby.iapi.services.io.Storable;
031:
032: import org.apache.derby.iapi.error.StandardException;
033:
034: import org.apache.derby.iapi.types.BooleanDataValue;
035: import org.apache.derby.iapi.types.DataValueDescriptor;
036: import org.apache.derby.iapi.types.NumberDataValue;
037: import org.apache.derby.iapi.types.TypeId;
038:
039: import org.apache.derby.iapi.services.cache.ClassSize;
040:
041: import org.apache.derby.iapi.types.NumberDataType;
042: import org.apache.derby.iapi.types.SQLBoolean;
043:
044: import java.io.ObjectOutput;
045: import java.io.ObjectInput;
046: import java.io.IOException;
047:
048: import java.sql.ResultSet;
049: import java.sql.PreparedStatement;
050: import java.sql.SQLException;
051:
052: /**
053: * SQLTinyint satisfies the DataValueDescriptor
054: * interfaces (i.e., OrderableDataType). It implements a tinyint column,
055: * e.g. for storing a column value; it can be specified
056: * when constructed to not allow nulls. Nullability cannot be changed
057: * after construction, as it affects the storage size and mechanism.
058: * <p>
059: * Because OrderableDataType is a subtype of ValueColumn,
060: * SQLTinyint can play a role in either a ValueColumn/Row
061: * or a OrderableDataType/Row, interchangeably.
062: * <p>
063: * We assume the store has a flag for nullness of the value,
064: * and simply return a 0-length array for the stored form
065: * when the value is null.
066: */
067: public final class SQLTinyint extends NumberDataType {
068:
069: /*
070: * constants
071: */
072: static final int TINYINT_LENGTH = 1;
073:
074: /*
075: * object state
076: */
077: private byte value;
078: private boolean isnull;
079:
080: private static final int BASE_MEMORY_USAGE = ClassSize
081: .estimateBaseFromCatalog(SQLTinyint.class);
082:
083: public int estimateMemoryUsage() {
084: return BASE_MEMORY_USAGE;
085: }
086:
087: /*
088: * class interface
089: */
090:
091: /*
092: * Constructors
093: */
094:
095: /**
096: * No-arg constructor, required by Formattable.
097: * This constructor also gets used when we are
098: * allocating space for a byte.
099: */
100: public SQLTinyint() {
101: isnull = true;
102: }
103:
104: public SQLTinyint(byte val) {
105: value = val;
106: }
107:
108: /* This constructor gets used for the getClone() method */
109: public SQLTinyint(byte val, boolean isnull) {
110: value = val;
111: this .isnull = isnull;
112: }
113:
114: //////////////////////////////////////////////////////////////
115: //
116: // DataValueDescriptor interface
117: // (mostly implemented in DataType)
118: //
119: //////////////////////////////////////////////////////////////
120:
121: /**
122: * @see DataValueDescriptor#getInt
123: */
124: public int getInt() {
125: return (int) value;
126: }
127:
128: /**
129: * @see DataValueDescriptor#getByte
130: */
131: public byte getByte() {
132: return value;
133: }
134:
135: /**
136: * @see DataValueDescriptor#getShort
137: */
138: public short getShort() {
139: return (short) value;
140: }
141:
142: /**
143: * @see DataValueDescriptor#getLong
144: */
145: public long getLong() {
146: return (long) value;
147: }
148:
149: /**
150: * @see DataValueDescriptor#getFloat
151: */
152: public float getFloat() {
153: return (float) value;
154: }
155:
156: /**
157: * @see DataValueDescriptor#getDouble
158: */
159: public double getDouble() {
160: return (double) value;
161: }
162:
163: /**
164: * @see DataValueDescriptor#getBoolean
165: */
166: public boolean getBoolean() {
167: return (value != 0);
168: }
169:
170: /**
171: * @see DataValueDescriptor#getString
172: */
173: public String getString() {
174: return (isNull()) ? null : Byte.toString(value);
175: }
176:
177: /**
178: * @see DataValueDescriptor#getLength
179: */
180: public int getLength() {
181: return TINYINT_LENGTH;
182: }
183:
184: /**
185: * @see DataValueDescriptor#getObject
186: */
187: public Object getObject() {
188: return (isNull()) ? null : new Integer(value);
189: }
190:
191: // this is for DataType's error generator
192: public String getTypeName() {
193: return TypeId.TINYINT_NAME;
194: }
195:
196: /*
197: * Storable interface, implies Externalizable, TypedFormat
198: */
199:
200: /**
201: Return my format identifier.
202:
203: @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId
204: */
205: public int getTypeFormatId() {
206: return StoredFormatIds.SQL_TINYINT_ID;
207: }
208:
209: /**
210: * @see Storable#isNull
211: */
212: public boolean isNull() {
213: return isnull;
214: }
215:
216: public void writeExternal(ObjectOutput out) throws IOException {
217:
218: // never called when value is null
219: if (SanityManager.DEBUG)
220: SanityManager.ASSERT(!isNull());
221:
222: out.writeByte(value);
223: }
224:
225: /** @see java.io.Externalizable#readExternal */
226: public void readExternal(ObjectInput in) throws IOException {
227:
228: value = in.readByte();
229: isnull = false;
230: }
231:
232: public void readExternalFromArray(ArrayInputStream in)
233: throws IOException {
234:
235: value = in.readByte();
236: isnull = false;
237: }
238:
239: /**
240: * @see Storable#restoreToNull
241: *
242: */
243: public void restoreToNull() {
244: value = 0;
245: isnull = true;
246: }
247:
248: /** @exception StandardException Thrown on error */
249: protected int typeCompare(DataValueDescriptor arg)
250: throws StandardException {
251: /* neither are null, get the value */
252: int this Value, otherValue;
253:
254: /* Do comparisons with ints to avoid overflow problems */
255: this Value = this .getInt();
256: otherValue = arg.getInt();
257: if (this Value == otherValue)
258: return 0;
259: else if (this Value > otherValue)
260: return 1;
261: else
262: return -1;
263: }
264:
265: /*
266: * DataValueDescriptor interface
267: */
268:
269: /** @see DataValueDescriptor#getClone */
270: public DataValueDescriptor getClone() {
271: return new SQLTinyint(value, isnull);
272: }
273:
274: /**
275: * @see DataValueDescriptor#getNewNull
276: */
277: public DataValueDescriptor getNewNull() {
278: return new SQLTinyint();
279: }
280:
281: /**
282: * @see DataValueDescriptor#setValueFromResultSet
283: *
284: * @exception SQLException Thrown on error
285: */
286: public void setValueFromResultSet(ResultSet resultSet,
287: int colNumber, boolean isNullable) throws SQLException {
288: value = resultSet.getByte(colNumber);
289: isnull = (isNullable && resultSet.wasNull());
290: }
291:
292: /**
293: Set the value into a PreparedStatement.
294:
295: @exception SQLException Error setting value in PreparedStatement
296: */
297: public final void setInto(PreparedStatement ps, int position)
298: throws SQLException {
299:
300: if (isNull()) {
301: ps.setNull(position, java.sql.Types.TINYINT);
302: return;
303: }
304:
305: ps.setByte(position, value);
306: }
307:
308: /**
309: Set this value into a ResultSet for a subsequent ResultSet.insertRow
310: or ResultSet.updateRow. This method will only be called for non-null values.
311:
312: @exception SQLException thrown by the ResultSet object
313: @exception StandardException thrown by me accessing my value.
314: */
315: public final void setInto(ResultSet rs, int position)
316: throws SQLException, StandardException {
317: rs.updateByte(position, value);
318: }
319:
320: /**
321: @exception StandardException thrown if string not accepted
322: */
323: public void setValue(String theValue) throws StandardException {
324: if (theValue == null) {
325: value = 0;
326: isnull = true;
327: } else {
328: try {
329: value = Byte.valueOf(theValue.trim()).byteValue();
330: } catch (NumberFormatException nfe) {
331: throw invalidFormat();
332: }
333: isnull = false;
334: }
335: }
336:
337: public void setValue(byte theValue) {
338: value = theValue;
339: isnull = false;
340: }
341:
342: /**
343: @exception StandardException if outsideRangeForTinyint
344: */
345: public void setValue(short theValue) throws StandardException {
346: if (theValue > Byte.MAX_VALUE || theValue < Byte.MIN_VALUE)
347: throw StandardException
348: .newException(
349: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
350: "TINYINT");
351: value = (byte) theValue;
352: isnull = false;
353: }
354:
355: /**
356: @exception StandardException if outsideRangeForTinyint
357: */
358: public void setValue(int theValue) throws StandardException {
359: if (theValue > Byte.MAX_VALUE || theValue < Byte.MIN_VALUE)
360: throw StandardException
361: .newException(
362: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
363: "TINYINT");
364: value = (byte) theValue;
365: isnull = false;
366: }
367:
368: /**
369: @exception StandardException if outsideRangeForTinyint
370: */
371: public void setValue(long theValue) throws StandardException {
372: if (theValue > Byte.MAX_VALUE || theValue < Byte.MIN_VALUE)
373: throw StandardException
374: .newException(
375: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
376: "TINYINT");
377: value = (byte) theValue;
378: isnull = false;
379: }
380:
381: /**
382: * @see NumberDataValue#setValue
383: *
384: * @exception StandardException Thrown on error
385: */
386: public void setValue(float theValue) throws StandardException {
387: theValue = NumberDataType.normalizeREAL(theValue);
388:
389: if (theValue > Byte.MAX_VALUE || theValue < Byte.MIN_VALUE)
390: throw StandardException
391: .newException(
392: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
393: "TINYINT");
394:
395: float floorValue = (float) Math.floor(theValue);
396:
397: value = (byte) floorValue;
398: isnull = false;
399:
400: }
401:
402: /**
403: * @see NumberDataValue#setValue
404: *
405: * @exception StandardException Thrown on error
406: */
407: public void setValue(double theValue) throws StandardException {
408: theValue = NumberDataType.normalizeDOUBLE(theValue);
409:
410: if (theValue > Byte.MAX_VALUE || theValue < Byte.MIN_VALUE)
411: throw outOfRange();
412:
413: double floorValue = Math.floor(theValue);
414:
415: value = (byte) floorValue;
416: isnull = false;
417: }
418:
419: /**
420: * @see NumberDataValue#setValue
421: *
422: */
423: public void setValue(boolean theValue) {
424: value = theValue ? (byte) 1 : (byte) 0;
425: isnull = false;
426: }
427:
428: protected void setFrom(DataValueDescriptor theValue)
429: throws StandardException {
430:
431: setValue(theValue.getByte());
432: }
433:
434: /*
435: * DataValueDescriptor interface
436: */
437:
438: /** @see DataValueDescriptor#typePrecedence */
439: public int typePrecedence() {
440: return TypeId.TINYINT_PRECEDENCE;
441: }
442:
443: /*
444: ** SQL Operators
445: */
446:
447: /**
448: * The = operator as called from the language module, as opposed to
449: * the storage module.
450: *
451: * @param left The value on the left side of the =
452: * @param right The value on the right side of the =
453: *
454: * @return A SQL boolean value telling whether the two parameters are equal
455: *
456: * @exception StandardException Thrown on error
457: */
458:
459: public BooleanDataValue equals(DataValueDescriptor left,
460: DataValueDescriptor right) throws StandardException {
461: return SQLBoolean.truthValue(left, right,
462: left.getByte() == right.getByte());
463: }
464:
465: /**
466: * The <> operator as called from the language module, as opposed to
467: * the storage module.
468: *
469: * @param left The value on the left side of the <>
470: * @param right The value on the right side of the <>
471: *
472: * @return A SQL boolean value telling whether the two parameters
473: * are not equal
474: *
475: * @exception StandardException Thrown on error
476: */
477:
478: public BooleanDataValue notEquals(DataValueDescriptor left,
479: DataValueDescriptor right) throws StandardException {
480: return SQLBoolean.truthValue(left, right,
481: left.getByte() != right.getByte());
482: }
483:
484: /**
485: * The < operator as called from the language module, as opposed to
486: * the storage module.
487: *
488: * @param left The value on the left side of the <
489: * @param right The value on the right side of the <
490: *
491: * @return A SQL boolean value telling whether the first operand is less
492: * than the second operand
493: *
494: * @exception StandardException Thrown on error
495: */
496:
497: public BooleanDataValue lessThan(DataValueDescriptor left,
498: DataValueDescriptor right) throws StandardException {
499: return SQLBoolean.truthValue(left, right,
500: left.getByte() < right.getByte());
501: }
502:
503: /**
504: * The > operator as called from the language module, as opposed to
505: * the storage module.
506: *
507: * @param left The value on the left side of the >
508: * @param right The value on the right side of the >
509: *
510: * @return A SQL boolean value telling whether the first operand is greater
511: * than the second operand
512: *
513: * @exception StandardException Thrown on error
514: */
515:
516: public BooleanDataValue greaterThan(DataValueDescriptor left,
517: DataValueDescriptor right) throws StandardException {
518: return SQLBoolean.truthValue(left, right,
519: left.getByte() > right.getByte());
520: }
521:
522: /**
523: * The <= operator as called from the language module, as opposed to
524: * the storage module.
525: *
526: * @param left The value on the left side of the <=
527: * @param right The value on the right side of the <=
528: *
529: * @return A SQL boolean value telling whether the first operand is less
530: * than or equal to the second operand
531: *
532: * @exception StandardException Thrown on error
533: */
534:
535: public BooleanDataValue lessOrEquals(DataValueDescriptor left,
536: DataValueDescriptor right) throws StandardException {
537: return SQLBoolean.truthValue(left, right,
538: left.getByte() <= right.getByte());
539: }
540:
541: /**
542: * The >= operator as called from the language module, as opposed to
543: * the storage module.
544: *
545: * @param left The value on the left side of the >=
546: * @param right The value on the right side of the >=
547: *
548: * @return A SQL boolean value telling whether the first operand is greater
549: * than or equal to the second operand
550: *
551: * @exception StandardException Thrown on error
552: */
553:
554: public BooleanDataValue greaterOrEquals(DataValueDescriptor left,
555: DataValueDescriptor right) throws StandardException {
556: return SQLBoolean.truthValue(left, right,
557: left.getByte() >= right.getByte());
558: }
559:
560: /**
561: * This method implements the * operator for "tinyint * tinyint".
562: *
563: * @param left The first value to be multiplied
564: * @param right The second value to be multiplied
565: * @param result The result of a previous call to this method, null
566: * if not called yet
567: *
568: * @return A SQLTinyint containing the result of the multiplication
569: *
570: * @exception StandardException Thrown on error
571: */
572:
573: public NumberDataValue times(NumberDataValue left,
574: NumberDataValue right, NumberDataValue result)
575: throws StandardException {
576: if (result == null) {
577: result = new SQLTinyint();
578: }
579:
580: if (left.isNull() || right.isNull()) {
581: result.setToNull();
582: return result;
583: }
584:
585: /*
586: ** Java does not check for overflow with integral types. We have to
587: ** check the result ourselves.
588: **
589: ** The product of 2 bytes is an int, so we check to see if the product
590: ** is in the range of values for a byte.
591: */
592: int product = left.getByte() * right.getByte();
593: result.setValue(product);
594: return result;
595: }
596:
597: /**
598: mod(tinyint, tinyint)
599: */
600:
601: public NumberDataValue mod(NumberDataValue dividend,
602: NumberDataValue divisor, NumberDataValue result)
603: throws StandardException {
604: if (result == null) {
605: result = new SQLTinyint();
606: }
607:
608: if (dividend.isNull() || divisor.isNull()) {
609: result.setToNull();
610: return result;
611: }
612:
613: /* Catch divide by 0 */
614: byte byteDivisor = divisor.getByte();
615: if (byteDivisor == 0) {
616: throw StandardException
617: .newException(SQLState.LANG_DIVIDE_BY_ZERO);
618: }
619:
620: result.setValue(dividend.getByte() % byteDivisor);
621: return result;
622: }
623:
624: /**
625: * This method implements the unary minus operator for tinyint.
626: *
627: * @param result The result of a previous call to this method, null
628: * if not called yet
629: *
630: * @return A SQLTinyint containing the result of the division
631: *
632: * @exception StandardException Thrown on error
633: */
634:
635: public NumberDataValue minus(NumberDataValue result)
636: throws StandardException {
637: if (result == null) {
638: result = new SQLTinyint();
639: }
640:
641: if (this .isNull()) {
642: result.setToNull();
643: return result;
644: }
645:
646: int operandValue = this .getByte();
647:
648: result.setValue(-operandValue);
649: return result;
650: }
651:
652: /**
653: * This method implements the isNegative method.
654: *
655: * @return A boolean. If this.value is negative, return true.
656: * For positive values or null, return false.
657: */
658:
659: protected boolean isNegative() {
660: return !isNull() && value < 0;
661: }
662:
663: /*
664: * String display of value
665: */
666:
667: public String toString() {
668: if (isNull())
669: return "NULL";
670: else
671: return Byte.toString(value);
672: }
673:
674: /*
675: * Hash code
676: */
677: public int hashCode() {
678: return (int) value;
679: }
680: }
|