--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.iapi.types.UserType\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.iapi.types;\r
+\r
+import org.apache.derby.catalog.TypeDescriptor;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.services.io.ArrayInputStream;\r
+\r
+import org.apache.derby.iapi.services.loader.ClassInspector;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.services.io.StoredFormatIds;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.TypeId;\r
+\r
+import org.apache.derby.iapi.types.BooleanDataValue;\r
+import org.apache.derby.iapi.types.UserDataValue;\r
+\r
+import org.apache.derby.iapi.services.cache.ClassSize;\r
+\r
+import java.sql.Date;\r
+import java.sql.Time;\r
+import java.sql.Timestamp;\r
+\r
+import java.io.ObjectOutput;\r
+import java.io.ObjectInput;\r
+import java.io.IOException;\r
+\r
+import java.sql.ResultSet;\r
+import java.sql.SQLException;\r
+\r
+import java.util.Calendar;\r
+\r
+\r
+/**\r
+ * This contains an instance of a user-defined type, that is, a java object.\r
+ *\r
+ */\r
+\r
+public class UserType extends DataType\r
+ implements UserDataValue\r
+{\r
+ private Object value;\r
+\r
+ /*\r
+ ** DataValueDescriptor interface\r
+ ** (mostly implemented in DataType)\r
+ */\r
+\r
+ private static final int BASE_MEMORY_USAGE = ClassSize.estimateBaseFromCatalog( UserType.class);\r
+\r
+ public int estimateMemoryUsage()\r
+ {\r
+ int sz = BASE_MEMORY_USAGE;\r
+ if( null != value)\r
+ {\r
+ // Probably an underestimate. Examining each field value would be expensive\r
+ // and would produce an overestimate when fields reference shared objects\r
+ sz += ClassSize.estimateAndCatalogBase( value.getClass());\r
+ }\r
+ \r
+ return sz;\r
+ } // end of estimateMemoryUsage\r
+\r
+ public String getString()\r
+ {\r
+ if (! isNull())\r
+ {\r
+ return value.toString();\r
+\r
+ }\r
+ else\r
+ {\r
+ return null;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @exception StandardException thrown on failure to convert\r
+ */\r
+ public boolean getBoolean() throws StandardException\r
+ {\r
+ if (! isNull())\r
+ if (value instanceof Boolean) return ((Boolean)value).booleanValue();\r
+ return super.getBoolean();\r
+ }\r
+\r
+ /**\r
+ * @exception StandardException thrown on failure to convert\r
+ */\r
+ public byte getByte() throws StandardException\r
+ {\r
+ if (! isNull())\r
+ // REMIND: check for overflow and truncation\r
+ if (value instanceof Number) return ((Number)value).byteValue();\r
+ return super.getByte();\r
+ }\r
+\r
+ /**\r
+ * @exception StandardException thrown on failure to convert\r
+ */\r
+ public short getShort() throws StandardException\r
+ {\r
+ if (! isNull())\r
+ // REMIND: check for overflow and truncation\r
+ if (value instanceof Number) return ((Number)value).shortValue();\r
+ return super.getShort();\r
+ }\r
+\r
+ /**\r
+ * @exception StandardException thrown on failure to convert\r
+ */\r
+ public int getInt() throws StandardException\r
+ {\r
+ if (! isNull())\r
+ // REMIND: check for overflow and truncation\r
+ if (value instanceof Number) return ((Number)value).intValue();\r
+ return super.getInt();\r
+ }\r
+\r
+ /**\r
+ * @exception StandardException thrown on failure to convert\r
+ */\r
+\r
+ public long getLong() throws StandardException\r
+ {\r
+ if (! isNull())\r
+ // REMIND: check for overflow and truncation\r
+ if (value instanceof Number) return ((Number)value).longValue();\r
+ return super.getLong();\r
+ }\r
+\r
+\r
+ /**\r
+ * @exception StandardException thrown on failure to convert\r
+ */\r
+ public float getFloat() throws StandardException\r
+ {\r
+ if (! isNull())\r
+ // REMIND: check for overflow\r
+ if (value instanceof Number) return ((Number)value).floatValue();\r
+ return super.getFloat();\r
+ }\r
+\r
+\r
+ /**\r
+ * @exception StandardException thrown on failure to convert\r
+ */\r
+ public double getDouble() throws StandardException\r
+ {\r
+ if (! isNull())\r
+ // REMIND: check for overflow\r
+ if (value instanceof Number) return ((Number)value).doubleValue();\r
+ return super.getDouble();\r
+ }\r
+\r
+ /**\r
+ * @exception StandardException thrown on failure to convert\r
+ */\r
+ public byte[] getBytes() throws StandardException\r
+ {\r
+ if (! isNull())\r
+ if (value instanceof byte[]) return ((byte[])value);\r
+ return super.getBytes();\r
+ }\r
+\r
+ /**\r
+\r
+ @exception StandardException thrown on failure\r
+ */\r
+ public Date getDate( Calendar cal) throws StandardException\r
+ {\r
+ if (! isNull())\r
+ {\r
+ if (value instanceof Date) \r
+ return ((Date)value);\r
+ else if (value instanceof Timestamp)\r
+ return (new SQLTimestamp((Timestamp)value).getDate(cal));\r
+ }\r
+ return super.getDate(cal);\r
+ }\r
+\r
+ /**\r
+ @exception StandardException thrown on failure\r
+ */\r
+ public Time getTime( Calendar cal) throws StandardException\r
+ {\r
+ if (! isNull())\r
+ {\r
+ if (value instanceof Time) \r
+ return ((Time)value);\r
+ else if (value instanceof Timestamp)\r
+ return (new SQLTimestamp((Timestamp)value).getTime(cal));\r
+ }\r
+ return super.getTime(cal);\r
+ }\r
+\r
+ /**\r
+ @exception StandardException thrown on failure\r
+ */\r
+ public Timestamp getTimestamp( Calendar cal) throws StandardException\r
+ {\r
+ if (! isNull())\r
+ {\r
+ if (value instanceof Timestamp) \r
+ return ((Timestamp)value);\r
+ else if (value instanceof Date)\r
+ return (new SQLDate((Date)value).getTimestamp(cal));\r
+ else if (value instanceof Time)\r
+ return (new SQLTime((Time)value).getTimestamp(cal));\r
+ }\r
+ return super.getTimestamp(cal);\r
+ }\r
+\r
+ public Object getObject()\r
+ {\r
+ return value;\r
+ }\r
+ \r
+ public int getLength()\r
+ {\r
+ return TypeDescriptor.MAXIMUM_WIDTH_UNKNOWN;\r
+ }\r
+\r
+ /* this is for DataType's error generator */\r
+ public String getTypeName()\r
+ {\r
+\r
+ return isNull() ? "JAVA_OBJECT" : ClassInspector.readableClassName(value.getClass());\r
+ }\r
+ \r
+ /**\r
+ * Get the type name of this value, overriding\r
+ * with the passed in class name (for user/java types).\r
+ */\r
+ String getTypeName(String className)\r
+ {\r
+ return className;\r
+ }\r
+\r
+ /*\r
+ * Storable interface, implies Externalizable, TypedFormat\r
+ */\r
+\r
+ /**\r
+ Return my format identifier.\r
+\r
+ @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId\r
+ */\r
+ public int getTypeFormatId() {\r
+ return StoredFormatIds.SQL_USERTYPE_ID_V3;\r
+ }\r
+\r
+ /** \r
+ @exception IOException error writing data\r
+\r
+ */\r
+ public void writeExternal(ObjectOutput out) throws IOException {\r
+\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(!isNull(), "writeExternal() is not supposed to be called for null values.");\r
+\r
+ out.writeObject(value);\r
+ }\r
+\r
+ /**\r
+ * @see java.io.Externalizable#readExternal\r
+ *\r
+ * @exception IOException Thrown on error reading the object\r
+ * @exception ClassNotFoundException Thrown if the class of the object\r
+ * is not found\r
+ */\r
+ public void readExternal(ObjectInput in) \r
+ throws IOException, ClassNotFoundException\r
+ {\r
+ /* RESOLVE: Sanity check for right class */\r
+ value = in.readObject();\r
+ }\r
+ public void readExternalFromArray(ArrayInputStream in) \r
+ throws IOException, ClassNotFoundException\r
+ {\r
+ /* RESOLVE: Sanity check for right class */\r
+ value = in.readObject();\r
+ }\r
+\r
+ /*\r
+ * DataValueDescriptor interface\r
+ */\r
+\r
+ /** @see DataValueDescriptor#getClone */\r
+ public DataValueDescriptor getClone()\r
+ {\r
+ // Call constructor with all of our info\r
+ return new UserType(value);\r
+ }\r
+\r
+ /**\r
+ * @see DataValueDescriptor#getNewNull\r
+ */\r
+ public DataValueDescriptor getNewNull()\r
+ {\r
+ return new UserType();\r
+ }\r
+ /**\r
+ * @see org.apache.derby.iapi.services.io.Storable#restoreToNull\r
+ *\r
+ */\r
+\r
+ public void restoreToNull()\r
+ {\r
+ value = null;\r
+ }\r
+\r
+ /*\r
+ * DataValueDescriptor interface\r
+ */\r
+\r
+ /** \r
+ * @see DataValueDescriptor#setValueFromResultSet \r
+ *\r
+ * @exception SQLException Thrown on error\r
+ */\r
+ public void setValueFromResultSet(ResultSet resultSet, int colNumber,\r
+ boolean isNullable)\r
+ throws SQLException\r
+ {\r
+ value = resultSet.getObject(colNumber);\r
+ }\r
+\r
+ /**\r
+ * Orderable interface\r
+ *\r
+ *\r
+ * @see org.apache.derby.iapi.types.Orderable\r
+ *\r
+ * @exception StandardException thrown on failure\r
+ */\r
+ public int compare(DataValueDescriptor other)\r
+ throws StandardException\r
+ {\r
+ /* Use compare method from dominant type, negating result\r
+ * to reflect flipping of sides.\r
+ */\r
+ if (typePrecedence() < other.typePrecedence())\r
+ {\r
+ return - (other.compare(this));\r
+ }\r
+\r
+ boolean thisNull, otherNull;\r
+\r
+ thisNull = this.isNull();\r
+ otherNull = other.isNull();\r
+\r
+ /*\r
+ * thisNull otherNull return\r
+ * T T 0 (this == other)\r
+ * F T -1 (this < other)\r
+ * T F 1 (this > other)\r
+ */\r
+ if (thisNull || otherNull)\r
+ {\r
+ if (!thisNull) // otherNull must be true\r
+ return -1;\r
+ if (!otherNull) // thisNull must be true\r
+ return 1;\r
+ return 0;\r
+ }\r
+\r
+ /*\r
+ Neither are null compare them \r
+ */\r
+\r
+ int comparison;\r
+\r
+ try\r
+ {\r
+ comparison = ((java.lang.Comparable) value).compareTo(other.getObject());\r
+ }\r
+ catch (ClassCastException cce)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_INVALID_COMPARE_TO, \r
+ getTypeName(),\r
+ ClassInspector.readableClassName(other.getObject().getClass()));\r
+ }\r
+ /*\r
+ ** compareTo() can return any negative number if less than, and\r
+ ** any positive number if greater than. Change to -1, 0, 1.\r
+ */\r
+ if (comparison < 0)\r
+ comparison = -1;\r
+ else if (comparison > 0)\r
+ comparison = 1;\r
+\r
+ return comparison;\r
+ }\r
+\r
+ /**\r
+ @exception StandardException thrown on error\r
+ */\r
+ public boolean compare(int op,\r
+ DataValueDescriptor other,\r
+ boolean orderedNulls,\r
+ boolean unknownRV)\r
+ throws StandardException\r
+ {\r
+ if (!orderedNulls) // nulls are unordered\r
+ {\r
+ if (this.isNull() || other.isNull())\r
+ return unknownRV;\r
+ }\r
+\r
+ /* For usertypes and equal do some special processing when\r
+ * neither value is null. (Superclass will handle comparison\r
+ * if either value is null.)\r
+ */\r
+ if ( (op == ORDER_OP_EQUALS) &&\r
+ (! this.isNull()) && (! other.isNull()) ) \r
+ {\r
+ // if this object implements java.lang.Comparable (JDK1.2)\r
+ // then we let the compareTo method handle equality\r
+ // if it doesn't then we use the equals() method\r
+ Object o = getObject();\r
+\r
+ if (!(o instanceof java.lang.Comparable)) \r
+ {\r
+ return o.equals(other.getObject());\r
+ }\r
+ }\r
+ \r
+\r
+ /* Do the comparison */\r
+ return super.compare(op, other, orderedNulls, unknownRV);\r
+ }\r
+\r
+ /*\r
+ ** Class interface\r
+ */\r
+\r
+ /*\r
+ ** Constructors\r
+ */\r
+\r
+ /** no-arg constructor required by Formattable */\r
+ public UserType() { }\r
+\r
+ public UserType(Object value)\r
+ {\r
+ this.value = value;\r
+ }\r
+ /**\r
+ * @see UserDataValue#setValue\r
+ *\r
+ */\r
+ public void setValue(Object value)\r
+ {\r
+ this.value = value;\r
+ }\r
+ protected void setFrom(DataValueDescriptor theValue) throws StandardException {\r
+\r
+ setValue(theValue.getObject());\r
+ }\r
+\r
+ /**\r
+ * @see UserDataValue#setValue\r
+ *\r
+ */\r
+ public void setBigDecimal(Number theValue)\r
+ {\r
+ // needed to allow serializable BigDecimal\r
+ setValue((Object) theValue);\r
+ }\r
+\r
+ public void setValue(String theValue)\r
+ {\r
+ if (theValue == null)\r
+ {\r
+ value = null;\r
+ }\r
+ else\r
+ {\r
+ // Higher levels must have performed type checking for us.\r
+ value = theValue;\r
+ }\r
+ }\r
+\r
+ /*\r
+ ** SQL Operators\r
+ */\r
+\r
+ /**\r
+ * The = operator as called from the language module, as opposed to\r
+ * the storage module.\r
+ *\r
+ * @param left The value on the left side of the =\r
+ * @param right The value on the right side of the =\r
+ *\r
+ * @return A SQL boolean value telling whether the two parameters are equal\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ public BooleanDataValue equals(DataValueDescriptor left,\r
+ DataValueDescriptor right)\r
+ throws StandardException\r
+ {\r
+ return SQLBoolean.truthValue(left,\r
+ right,\r
+ left.compare(ORDER_OP_EQUALS, right, true, false));\r
+ }\r
+\r
+ /**\r
+ * The <> operator as called from the language module, as opposed to\r
+ * the storage module.\r
+ *\r
+ * @param left The value on the left side of the <>\r
+ * @param right The value on the right side of the <>\r
+ *\r
+ * @return A SQL boolean value telling whether the two parameters\r
+ * are not equal\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ public BooleanDataValue notEquals(DataValueDescriptor left,\r
+ DataValueDescriptor right)\r
+ throws StandardException\r
+ {\r
+ return SQLBoolean.truthValue(left,\r
+ right,\r
+ !left.compare(ORDER_OP_EQUALS, right, true, false));\r
+ }\r
+\r
+\r
+\r
+ /*\r
+ ** String display of value\r
+ */\r
+\r
+ public String toString()\r
+ {\r
+ if (isNull())\r
+ {\r
+ return "NULL";\r
+ }\r
+ else\r
+ {\r
+ return value.toString();\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Hash code\r
+ */\r
+ public int hashCode()\r
+ {\r
+ if (isNull())\r
+ return 0;\r
+ return value.hashCode();\r
+ }\r
+\r
+ /** @see DataValueDescriptor#typePrecedence */\r
+ public int typePrecedence()\r
+ {\r
+ return TypeId.USER_PRECEDENCE;\r
+ }\r
+\r
+ /**\r
+ * Check if the value is null. \r
+ *\r
+ * @return Whether or not value is logically null.\r
+ */\r
+ public final boolean isNull()\r
+ {\r
+ return (value == null);\r
+ }\r
+}\r
+\r