001: /*
002:
003: Derby - Class org.apache.derby.iapi.types.UserType
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.catalog.TypeDescriptor;
025:
026: import org.apache.derby.iapi.reference.SQLState;
027:
028: import org.apache.derby.iapi.services.io.ArrayInputStream;
029:
030: import org.apache.derby.iapi.services.loader.ClassInspector;
031: import org.apache.derby.iapi.services.sanity.SanityManager;
032: import org.apache.derby.iapi.services.io.StoredFormatIds;
033:
034: import org.apache.derby.iapi.error.StandardException;
035:
036: import org.apache.derby.iapi.types.DataValueDescriptor;
037: import org.apache.derby.iapi.types.TypeId;
038:
039: import org.apache.derby.iapi.types.BooleanDataValue;
040: import org.apache.derby.iapi.types.UserDataValue;
041:
042: import org.apache.derby.iapi.services.cache.ClassSize;
043:
044: import java.sql.Date;
045: import java.sql.Time;
046: import java.sql.Timestamp;
047:
048: import java.io.ObjectOutput;
049: import java.io.ObjectInput;
050: import java.io.IOException;
051:
052: import java.sql.ResultSet;
053: import java.sql.SQLException;
054:
055: import java.util.Calendar;
056:
057: /**
058: * This contains an instance of a user-defined type, that is, a java object.
059: *
060: */
061:
062: public class UserType extends DataType implements UserDataValue {
063: private Object value;
064:
065: /*
066: ** DataValueDescriptor interface
067: ** (mostly implemented in DataType)
068: */
069:
070: private static final int BASE_MEMORY_USAGE = ClassSize
071: .estimateBaseFromCatalog(UserType.class);
072:
073: public int estimateMemoryUsage() {
074: int sz = BASE_MEMORY_USAGE;
075: if (null != value) {
076: // Probably an underestimate. Examining each field value would be expensive
077: // and would produce an overestimate when fields reference shared objects
078: sz += ClassSize.estimateAndCatalogBase(value.getClass());
079: }
080:
081: return sz;
082: } // end of estimateMemoryUsage
083:
084: public String getString() {
085: if (!isNull()) {
086: return value.toString();
087:
088: } else {
089: return null;
090: }
091: }
092:
093: /**
094: * @exception StandardException thrown on failure to convert
095: */
096: public boolean getBoolean() throws StandardException {
097: if (!isNull())
098: if (value instanceof Boolean)
099: return ((Boolean) value).booleanValue();
100: return super .getBoolean();
101: }
102:
103: /**
104: * @exception StandardException thrown on failure to convert
105: */
106: public byte getByte() throws StandardException {
107: if (!isNull())
108: // REMIND: check for overflow and truncation
109: if (value instanceof Number)
110: return ((Number) value).byteValue();
111: return super .getByte();
112: }
113:
114: /**
115: * @exception StandardException thrown on failure to convert
116: */
117: public short getShort() throws StandardException {
118: if (!isNull())
119: // REMIND: check for overflow and truncation
120: if (value instanceof Number)
121: return ((Number) value).shortValue();
122: return super .getShort();
123: }
124:
125: /**
126: * @exception StandardException thrown on failure to convert
127: */
128: public int getInt() throws StandardException {
129: if (!isNull())
130: // REMIND: check for overflow and truncation
131: if (value instanceof Number)
132: return ((Number) value).intValue();
133: return super .getInt();
134: }
135:
136: /**
137: * @exception StandardException thrown on failure to convert
138: */
139:
140: public long getLong() throws StandardException {
141: if (!isNull())
142: // REMIND: check for overflow and truncation
143: if (value instanceof Number)
144: return ((Number) value).longValue();
145: return super .getLong();
146: }
147:
148: /**
149: * @exception StandardException thrown on failure to convert
150: */
151: public float getFloat() throws StandardException {
152: if (!isNull())
153: // REMIND: check for overflow
154: if (value instanceof Number)
155: return ((Number) value).floatValue();
156: return super .getFloat();
157: }
158:
159: /**
160: * @exception StandardException thrown on failure to convert
161: */
162: public double getDouble() throws StandardException {
163: if (!isNull())
164: // REMIND: check for overflow
165: if (value instanceof Number)
166: return ((Number) value).doubleValue();
167: return super .getDouble();
168: }
169:
170: /**
171: * @exception StandardException thrown on failure to convert
172: */
173: public byte[] getBytes() throws StandardException {
174: if (!isNull())
175: if (value instanceof byte[])
176: return ((byte[]) value);
177: return super .getBytes();
178: }
179:
180: /**
181:
182: @exception StandardException thrown on failure
183: */
184: public Date getDate(Calendar cal) throws StandardException {
185: if (!isNull()) {
186: if (value instanceof Date)
187: return ((Date) value);
188: else if (value instanceof Timestamp)
189: return (new SQLTimestamp((Timestamp) value)
190: .getDate(cal));
191: }
192: return super .getDate(cal);
193: }
194:
195: /**
196: @exception StandardException thrown on failure
197: */
198: public Time getTime(Calendar cal) throws StandardException {
199: if (!isNull()) {
200: if (value instanceof Time)
201: return ((Time) value);
202: else if (value instanceof Timestamp)
203: return (new SQLTimestamp((Timestamp) value)
204: .getTime(cal));
205: }
206: return super .getTime(cal);
207: }
208:
209: /**
210: @exception StandardException thrown on failure
211: */
212: public Timestamp getTimestamp(Calendar cal)
213: throws StandardException {
214: if (!isNull()) {
215: if (value instanceof Timestamp)
216: return ((Timestamp) value);
217: else if (value instanceof Date)
218: return (new SQLDate((Date) value).getTimestamp(cal));
219: else if (value instanceof Time)
220: return (new SQLTime((Time) value).getTimestamp(cal));
221: }
222: return super .getTimestamp(cal);
223: }
224:
225: public Object getObject() {
226: return value;
227: }
228:
229: public int getLength() {
230: return TypeDescriptor.MAXIMUM_WIDTH_UNKNOWN;
231: }
232:
233: /* this is for DataType's error generator */
234: public String getTypeName() {
235:
236: return isNull() ? "JAVA_OBJECT" : ClassInspector
237: .readableClassName(value.getClass());
238: }
239:
240: /**
241: * Get the type name of this value, overriding
242: * with the passed in class name (for user/java types).
243: */
244: String getTypeName(String className) {
245: return className;
246: }
247:
248: /*
249: * Storable interface, implies Externalizable, TypedFormat
250: */
251:
252: /**
253: Return my format identifier.
254:
255: @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId
256: */
257: public int getTypeFormatId() {
258: return StoredFormatIds.SQL_USERTYPE_ID_V3;
259: }
260:
261: /**
262: @exception IOException error writing data
263:
264: */
265: public void writeExternal(ObjectOutput out) throws IOException {
266:
267: if (SanityManager.DEBUG)
268: SanityManager
269: .ASSERT(!isNull(),
270: "writeExternal() is not supposed to be called for null values.");
271:
272: out.writeObject(value);
273: }
274:
275: /**
276: * @see java.io.Externalizable#readExternal
277: *
278: * @exception IOException Thrown on error reading the object
279: * @exception ClassNotFoundException Thrown if the class of the object
280: * is not found
281: */
282: public void readExternal(ObjectInput in) throws IOException,
283: ClassNotFoundException {
284: /* RESOLVE: Sanity check for right class */
285: value = in.readObject();
286: }
287:
288: public void readExternalFromArray(ArrayInputStream in)
289: throws IOException, ClassNotFoundException {
290: /* RESOLVE: Sanity check for right class */
291: value = in.readObject();
292: }
293:
294: /*
295: * DataValueDescriptor interface
296: */
297:
298: /** @see DataValueDescriptor#getClone */
299: public DataValueDescriptor getClone() {
300: // Call constructor with all of our info
301: return new UserType(value);
302: }
303:
304: /**
305: * @see DataValueDescriptor#getNewNull
306: */
307: public DataValueDescriptor getNewNull() {
308: return new UserType();
309: }
310:
311: /**
312: * @see org.apache.derby.iapi.services.io.Storable#restoreToNull
313: *
314: */
315:
316: public void restoreToNull() {
317: value = null;
318: }
319:
320: /*
321: * DataValueDescriptor interface
322: */
323:
324: /**
325: * @see DataValueDescriptor#setValueFromResultSet
326: *
327: * @exception SQLException Thrown on error
328: */
329: public void setValueFromResultSet(ResultSet resultSet,
330: int colNumber, boolean isNullable) throws SQLException {
331: value = resultSet.getObject(colNumber);
332: }
333:
334: /**
335: * Orderable interface
336: *
337: *
338: * @see org.apache.derby.iapi.types.Orderable
339: *
340: * @exception StandardException thrown on failure
341: */
342: public int compare(DataValueDescriptor other)
343: throws StandardException {
344: /* Use compare method from dominant type, negating result
345: * to reflect flipping of sides.
346: */
347: if (typePrecedence() < other.typePrecedence()) {
348: return -(other.compare(this ));
349: }
350:
351: boolean this Null, otherNull;
352:
353: this Null = this .isNull();
354: otherNull = other.isNull();
355:
356: /*
357: * thisNull otherNull return
358: * T T 0 (this == other)
359: * F T -1 (this < other)
360: * T F 1 (this > other)
361: */
362: if (this Null || otherNull) {
363: if (!this Null) // otherNull must be true
364: return -1;
365: if (!otherNull) // thisNull must be true
366: return 1;
367: return 0;
368: }
369:
370: /*
371: Neither are null compare them
372: */
373:
374: int comparison;
375:
376: try {
377: comparison = ((java.lang.Comparable) value).compareTo(other
378: .getObject());
379: } catch (ClassCastException cce) {
380: throw StandardException.newException(
381: SQLState.LANG_INVALID_COMPARE_TO, getTypeName(),
382: ClassInspector.readableClassName(other.getObject()
383: .getClass()));
384: }
385: /*
386: ** compareTo() can return any negative number if less than, and
387: ** any positive number if greater than. Change to -1, 0, 1.
388: */
389: if (comparison < 0)
390: comparison = -1;
391: else if (comparison > 0)
392: comparison = 1;
393:
394: return comparison;
395: }
396:
397: /**
398: @exception StandardException thrown on error
399: */
400: public boolean compare(int op, DataValueDescriptor other,
401: boolean orderedNulls, boolean unknownRV)
402: throws StandardException {
403: if (!orderedNulls) // nulls are unordered
404: {
405: if (this .isNull() || other.isNull())
406: return unknownRV;
407: }
408:
409: /* For usertypes and equal do some special processing when
410: * neither value is null. (Superclass will handle comparison
411: * if either value is null.)
412: */
413: if ((op == ORDER_OP_EQUALS) && (!this .isNull())
414: && (!other.isNull())) {
415: // if this object implements java.lang.Comparable (JDK1.2)
416: // then we let the compareTo method handle equality
417: // if it doesn't then we use the equals() method
418: Object o = getObject();
419:
420: if (!(o instanceof java.lang.Comparable)) {
421: return o.equals(other.getObject());
422: }
423: }
424:
425: /* Do the comparison */
426: return super .compare(op, other, orderedNulls, unknownRV);
427: }
428:
429: /*
430: ** Class interface
431: */
432:
433: /*
434: ** Constructors
435: */
436:
437: /** no-arg constructor required by Formattable */
438: public UserType() {
439: }
440:
441: public UserType(Object value) {
442: this .value = value;
443: }
444:
445: /**
446: * @see UserDataValue#setValue
447: *
448: */
449: public void setValue(Object value) {
450: this .value = value;
451: }
452:
453: protected void setFrom(DataValueDescriptor theValue)
454: throws StandardException {
455:
456: setValue(theValue.getObject());
457: }
458:
459: /**
460: * @see UserDataValue#setValue
461: *
462: */
463: public void setBigDecimal(Number theValue) {
464: // needed to allow serializable BigDecimal
465: setValue((Object) theValue);
466: }
467:
468: public void setValue(String theValue) {
469: if (theValue == null) {
470: value = null;
471: } else {
472: // Higher levels must have performed type checking for us.
473: value = theValue;
474: }
475: }
476:
477: /*
478: ** SQL Operators
479: */
480:
481: /**
482: * The = operator as called from the language module, as opposed to
483: * the storage module.
484: *
485: * @param left The value on the left side of the =
486: * @param right The value on the right side of the =
487: *
488: * @return A SQL boolean value telling whether the two parameters are equal
489: *
490: * @exception StandardException Thrown on error
491: */
492:
493: public BooleanDataValue equals(DataValueDescriptor left,
494: DataValueDescriptor right) throws StandardException {
495: return SQLBoolean.truthValue(left, right, left.compare(
496: ORDER_OP_EQUALS, right, true, false));
497: }
498:
499: /**
500: * The <> operator as called from the language module, as opposed to
501: * the storage module.
502: *
503: * @param left The value on the left side of the <>
504: * @param right The value on the right side of the <>
505: *
506: * @return A SQL boolean value telling whether the two parameters
507: * are not equal
508: *
509: * @exception StandardException Thrown on error
510: */
511:
512: public BooleanDataValue notEquals(DataValueDescriptor left,
513: DataValueDescriptor right) throws StandardException {
514: return SQLBoolean.truthValue(left, right, !left.compare(
515: ORDER_OP_EQUALS, right, true, false));
516: }
517:
518: /*
519: ** String display of value
520: */
521:
522: public String toString() {
523: if (isNull()) {
524: return "NULL";
525: } else {
526: return value.toString();
527: }
528: }
529:
530: /*
531: * Hash code
532: */
533: public int hashCode() {
534: if (isNull())
535: return 0;
536: return value.hashCode();
537: }
538:
539: /** @see DataValueDescriptor#typePrecedence */
540: public int typePrecedence() {
541: return TypeId.USER_PRECEDENCE;
542: }
543:
544: /**
545: * Check if the value is null.
546: *
547: * @return Whether or not value is logically null.
548: */
549: public final boolean isNull() {
550: return (value == null);
551: }
552: }
|