Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / derby-10.3.2.1 / java / engine / org / apache / derby / iapi / types / DataTypeDescriptor.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/iapi/types/DataTypeDescriptor.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/iapi/types/DataTypeDescriptor.java
new file mode 100644 (file)
index 0000000..f3574f8
--- /dev/null
@@ -0,0 +1,1579 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.iapi.types.DataTypeDescriptor\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 java.io.IOException;\r
+import java.io.ObjectInput;\r
+import java.io.ObjectOutput;\r
+import java.sql.Types;\r
+import java.text.RuleBasedCollator;\r
+\r
+import org.apache.derby.catalog.TypeDescriptor;\r
+import org.apache.derby.catalog.types.TypeDescriptorImpl;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.services.io.Formatable;\r
+import org.apache.derby.iapi.services.io.StoredFormatIds;\r
+import org.apache.derby.iapi.services.loader.ClassFactory;\r
+import org.apache.derby.iapi.services.loader.ClassInspector;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.sql.conn.ConnectionUtil;\r
+\r
+/** \r
+ * This is an implementation of DataTypeDescriptor from the generic language\r
+ * datatype module interface.\r
+ *\r
+ * @version 1.0\r
+ */\r
+\r
+public final class DataTypeDescriptor implements TypeDescriptor, Formatable\r
+{\r
+       /********************************************************\r
+       **\r
+       **      This class implements Formatable. That means that it\r
+       **      can write itself to and from a formatted stream. If\r
+       **      you add more fields to this class, make sure that you\r
+       **      also write/read them with the writeExternal()/readExternal()\r
+       **      methods.\r
+       **\r
+       **      If, inbetween releases, you add more fields to this class,\r
+       **      then you should bump the version number emitted by the getTypeFormatId()\r
+       **      method.\r
+       **\r
+       ********************************************************/\r
+\r
+       /*\r
+       ** Static creators\r
+       */\r
+       /**\r
+        * Get a descriptor that corresponds to a builtin JDBC type.\r
+        *\r
+        * @param jdbcType      The int type of the JDBC type for which to get\r
+        *                                              a corresponding SQL DataTypeDescriptor\r
+        *\r
+        * @return      A new DataTypeDescriptor that corresponds to the Java type.\r
+        *                      A null return value means there is no corresponding SQL type\r
+        */\r
+       public static DataTypeDescriptor getBuiltInDataTypeDescriptor\r
+       (\r
+               int     jdbcType\r
+       )\r
+       {\r
+               return DataTypeDescriptor.getBuiltInDataTypeDescriptor(jdbcType, true);\r
+       }\r
+       public static DataTypeDescriptor getBuiltInDataTypeDescriptor\r
+       (\r
+               int     jdbcType,\r
+               int length\r
+       )\r
+       {\r
+               return DataTypeDescriptor.getBuiltInDataTypeDescriptor(jdbcType, true, length);\r
+       }\r
+\r
+       /**\r
+        * Get a descriptor that corresponds to a builtin JDBC type.\r
+        *\r
+        * @param jdbcType      The int type of the JDBC type for which to get\r
+        *                                              a corresponding SQL DataTypeDescriptor\r
+        * @param isNullable    TRUE means it could contain NULL, FALSE means\r
+        *                      it definitely cannot contain NULL.\r
+        *\r
+        * @return      A new DataTypeDescriptor that corresponds to the Java type.\r
+        *                      A null return value means there is no corresponding SQL type\r
+        */\r
+       public static DataTypeDescriptor getBuiltInDataTypeDescriptor\r
+       (\r
+               int     jdbcType, \r
+               boolean isNullable\r
+       )\r
+       {\r
+               TypeId typeId = TypeId.getBuiltInTypeId(jdbcType);\r
+               if (typeId == null)\r
+               {\r
+                       return null;\r
+               }\r
+\r
+               return new DataTypeDescriptor(typeId, isNullable);\r
+       }\r
+       /**\r
+        * Get a descriptor that corresponds to a builtin JDBC type.\r
+        *\r
+        * @param jdbcType      The int type of the JDBC type for which to get\r
+        *                                              a corresponding SQL DataTypeDescriptor\r
+        * @param isNullable    TRUE means it could contain NULL, FALSE means\r
+        *                      it definitely cannot contain NULL.\r
+        *\r
+        * @return      A new DataTypeDescriptor that corresponds to the Java type.\r
+        *                      A null return value means there is no corresponding SQL type\r
+        */\r
+       public static DataTypeDescriptor getBuiltInDataTypeDescriptor\r
+       (\r
+               int     jdbcType, \r
+               boolean isNullable,\r
+               int maxLength\r
+       )\r
+       {\r
+               TypeId typeId = TypeId.getBuiltInTypeId(jdbcType);\r
+               if (typeId == null)\r
+               {\r
+                       return null;\r
+               }\r
+\r
+               return new DataTypeDescriptor(typeId, isNullable, maxLength);\r
+       }\r
+       /**\r
+        * Get a DataTypeServices that corresponds to a builtin SQL type\r
+        *\r
+        * @param sqlTypeName   The name of the type for which to get\r
+        *                                              a corresponding SQL DataTypeDescriptor\r
+        *\r
+        * @return      A new DataTypeDescriptor that corresponds to the Java type.\r
+        *                      A null return value means there is no corresponding SQL type (only for 'char')\r
+        */\r
+       public static DataTypeDescriptor getBuiltInDataTypeDescriptor\r
+       (\r
+               String  sqlTypeName\r
+       )\r
+       {\r
+               return new DataTypeDescriptor(TypeId.getBuiltInTypeId(sqlTypeName), true);\r
+       }\r
+       /**\r
+        * Get a DataTypeServices that corresponds to a builtin SQL type\r
+        *\r
+        * @param sqlTypeName   The name of the type for which to get\r
+        *                                              a corresponding SQL DataTypeDescriptor\r
+        *\r
+        * @return      A new DataTypeDescriptor that corresponds to the Java type.\r
+        *                      A null return value means there is no corresponding SQL type (only for 'char')\r
+        */\r
+       public static DataTypeDescriptor getBuiltInDataTypeDescriptor\r
+       (\r
+               String  sqlTypeName,\r
+               int length\r
+       )\r
+       {\r
+               return new DataTypeDescriptor(TypeId.getBuiltInTypeId(sqlTypeName), true, length);\r
+       }\r
+       /**\r
+        * Get a DataTypeServices that corresponds to a Java type\r
+        *\r
+        * @param javaTypeName  The name of the Java type for which to get\r
+        *                                              a corresponding SQL DataTypeDescriptor\r
+        *\r
+        * @return      A new DataTypeDescriptor that corresponds to the Java type.\r
+        *                      A null return value means there is no corresponding SQL type (only for 'char')\r
+        */\r
+       public static DataTypeDescriptor getSQLDataTypeDescriptor\r
+       (\r
+               String  javaTypeName\r
+       )\r
+       {\r
+                       return DataTypeDescriptor.getSQLDataTypeDescriptor(javaTypeName, true);\r
+       }\r
+\r
+       /**\r
+        * Get a DataTypeServices that corresponds to a Java type\r
+        *\r
+        * @param javaTypeName  The name of the Java type for which to get\r
+        *                                              a corresponding SQL DataTypeDescriptor\r
+        * @param isNullable    TRUE means it could contain NULL, FALSE means\r
+        *                      it definitely cannot contain NULL.\r
+        *\r
+        * @return      A new DataTypeDescriptor that corresponds to the Java type.\r
+        *                      A null return value means there is no corresponding SQL type (only for 'char')\r
+        */\r
+       public static DataTypeDescriptor getSQLDataTypeDescriptor\r
+       (\r
+               String  javaTypeName, \r
+               boolean isNullable\r
+       )\r
+       {\r
+               TypeId typeId = TypeId.getSQLTypeForJavaType(javaTypeName);\r
+               if (typeId == null)\r
+               {\r
+                       return null;\r
+               }\r
+\r
+               return new DataTypeDescriptor(typeId, isNullable);\r
+       }\r
+\r
+       /**\r
+        * Get a DataTypeDescriptor that corresponds to a Java type\r
+        *\r
+        * @param javaTypeName  The name of the Java type for which to get\r
+        *                                              a corresponding SQL DataTypeDescriptor\r
+        * @param precision     The number of decimal digits\r
+        * @param scale         The number of digits after the decimal point\r
+        * @param isNullable    TRUE means it could contain NULL, FALSE means\r
+        *                      it definitely cannot contain NULL.\r
+        * @param maximumWidth  The maximum width of a data value\r
+        *                      represented by this type.\r
+        *\r
+        * @return      A new DataTypeDescriptor that corresponds to the Java type.\r
+        *                      A null return value means there is no corresponding SQL type.\r
+        */\r
+       public static DataTypeDescriptor getSQLDataTypeDescriptor\r
+       (\r
+               String  javaTypeName, \r
+               int     precision,\r
+               int     scale, \r
+               boolean isNullable, \r
+               int     maximumWidth\r
+       )\r
+       {\r
+               TypeId typeId = TypeId.getSQLTypeForJavaType(javaTypeName);\r
+               if (typeId == null)\r
+               {\r
+                       return null;\r
+               }\r
+\r
+               return new DataTypeDescriptor(typeId,\r
+                                                                                       precision,\r
+                                                                                       scale,\r
+                                                                                       isNullable,\r
+                                                                                       maximumWidth);\r
+       }\r
+    \r
+       /*\r
+       ** Instance fields & methods\r
+       */\r
+\r
+       private TypeDescriptorImpl      typeDescriptor;\r
+       private TypeId                  typeId;\r
+\r
+       /**\r
+        * Public niladic constructor. Needed for Formatable interface to work.\r
+        *\r
+        */\r
+    public     DataTypeDescriptor() {}\r
+\r
+       /**\r
+        * Constructor for use with numeric types\r
+        *\r
+        * @param typeId        The typeId of the type being described\r
+        * @param precision     The number of decimal digits.\r
+        * @param scale         The number of digits after the decimal point.\r
+        * @param isNullable    TRUE means it could contain NULL, FALSE means\r
+        *                      it definitely cannot contain NULL.\r
+        * @param maximumWidth  The maximum number of bytes for this datatype\r
+        */\r
+       public DataTypeDescriptor(TypeId typeId, int precision, int scale,\r
+               boolean isNullable, int maximumWidth)\r
+       {\r
+               this.typeId = typeId;\r
+               typeDescriptor = new TypeDescriptorImpl(typeId.getBaseTypeId(),\r
+                                                                                               precision,\r
+                                                                                               scale,\r
+                                                                                               isNullable,\r
+                                                                                               maximumWidth);\r
+       }\r
+\r
+       /**\r
+        * Constructor to use when the caller doesn't know if it is requesting\r
+        * numeric or no-numeric DTD. For instance, when dealing with MAX/MIN \r
+        * aggregrate operators, AggregateNode.bindExpression could be dealing\r
+        * with a character string operand or a numeric operand. The result of\r
+        * MAX/MIN will depend on the type of it's operand. And hence when this\r
+        * constructor gets called by AggregateNode.bindExpression, we don't know \r
+        * what type we are constructing and hence this constructor supports \r
+        * arguments for both numeric and non-numeric types.\r
+        *\r
+        * @param typeId        The typeId of the type being described\r
+        * @param precision     The number of decimal digits.\r
+        * @param scale         The number of digits after the decimal point.\r
+        * @param isNullable    TRUE means it could contain NULL, FALSE means\r
+        *                      it definitely cannot contain NULL.\r
+        * @param maximumWidth  The maximum number of bytes for this datatype\r
+        * @param collationType The collation type of a string data type\r
+        * @param collationDerivation Collation Derivation of a string data type\r
+        */\r
+       public DataTypeDescriptor(TypeId typeId, int precision, int scale,\r
+               boolean isNullable, int maximumWidth, int collationType,\r
+               int collationDerivation)\r
+       {\r
+               this.typeId = typeId;\r
+               typeDescriptor = new TypeDescriptorImpl(typeId.getBaseTypeId(),\r
+                                                                                               precision,\r
+                                                                                               scale,\r
+                                                                                               isNullable,\r
+                                                                                               maximumWidth,\r
+                                                                                               collationType,\r
+                                                                                               collationDerivation);\r
+       }\r
+\r
+       /**\r
+        * Constructor for use with non-numeric types\r
+        *\r
+        * @param typeId        The typeId of the type being described\r
+        * @param isNullable    TRUE means it could contain NULL, FALSE means\r
+        *                      it definitely cannot contain NULL.\r
+        * @param maximumWidth  The maximum number of bytes for this datatype\r
+        */\r
+       public DataTypeDescriptor(TypeId typeId, boolean isNullable,\r
+               int maximumWidth)\r
+       {\r
+               this.typeId = typeId;\r
+               typeDescriptor = new TypeDescriptorImpl(typeId.getBaseTypeId(),\r
+                                                                                               isNullable,\r
+                                                                                               maximumWidth);\r
+       }\r
+\r
+\r
+       public DataTypeDescriptor(TypeId typeId, boolean isNullable) {\r
+\r
+               this.typeId = typeId;\r
+               typeDescriptor = new TypeDescriptorImpl(typeId.getBaseTypeId(),\r
+                                                                                               typeId.getMaximumPrecision(),\r
+                                                                                               typeId.getMaximumScale(),\r
+                                                                                               isNullable,\r
+                                                                                               typeId.getMaximumMaximumWidth());\r
+       }\r
+       public DataTypeDescriptor(DataTypeDescriptor source, boolean isNullable)\r
+       {\r
+               //There might be other places, but one place this method gets called\r
+               //from is ResultColumn.init. When the ResultColumn(RC) is for a \r
+               //ColumnDescriptor(CD), the RC's TypeDescriptorImpl(TDI) should get \r
+               //all the attributes of CD's TDI. So, if the CD is for a user table's\r
+               //character type column, then this call by RC.init should have CD's \r
+               //collation attributes copied into RC along with other attributes. \r
+               this.typeId = source.typeId;\r
+               typeDescriptor = new TypeDescriptorImpl(source.typeDescriptor,\r
+                                                                                               source.getPrecision(),\r
+                                                                                               source.getScale(),\r
+                                                                                               isNullable,\r
+                                                                                               source.getMaximumWidth(),\r
+                                                                                               source.getCollationType(),\r
+                                                                                               source.getCollationDerivation());\r
+       }\r
+\r
+       /**\r
+        * Constructor for internal uses only.  \r
+        * (This is useful when the precision and scale are potentially wider than\r
+        * those in the source, like when determining the dominant data type.)\r
+        *\r
+        * @param source        The DTSI to copy\r
+        * @param precision     The number of decimal digits.\r
+        * @param scale         The number of digits after the decimal point.\r
+        * @param isNullable    TRUE means it could contain NULL, FALSE means\r
+        *                      it definitely cannot contain NULL.\r
+        * @param maximumWidth  The maximum number of bytes for this datatype\r
+        */\r
+       public DataTypeDescriptor(DataTypeDescriptor source, \r
+                                                               int precision,\r
+                                                               int scale,\r
+                                                               boolean isNullable,\r
+                                                               int maximumWidth)\r
+       {\r
+               this.typeId = source.typeId;\r
+               typeDescriptor = new TypeDescriptorImpl(source.typeDescriptor,\r
+                                                                                               precision,\r
+                                                                                               scale,\r
+                                                                                               isNullable,\r
+                                                                                               maximumWidth,\r
+                                                                                               source.getCollationType(),\r
+                                                                                               source.getCollationDerivation());\r
+       }\r
+\r
+       /**\r
+        * Constructor for internal uses only\r
+        *\r
+        * @param source        The DTSI to copy\r
+        * @param isNullable    TRUE means it could contain NULL, FALSE means\r
+        *                      it definitely cannot contain NULL.\r
+        * @param maximumWidth  The maximum number of bytes for this datatype\r
+        */\r
+       public DataTypeDescriptor(DataTypeDescriptor source, boolean isNullable,\r
+               int maximumWidth)\r
+       {\r
+               this.typeId = source.typeId;\r
+               typeDescriptor = new TypeDescriptorImpl(source.typeDescriptor,\r
+                               source.getPrecision(),\r
+                               source.getScale(),\r
+                               isNullable,\r
+                               maximumWidth,\r
+                               source.getCollationType(),\r
+                               source.getCollationDerivation());\r
+\r
+       }\r
+\r
+       /**\r
+        * Constructor for use in reconstructing a DataTypeDescriptor from a\r
+        * TypeDescriptorImpl and a TypeId\r
+        *\r
+        * @param source        The TypeDescriptorImpl to construct this DTSI from\r
+        */\r
+       public DataTypeDescriptor(TypeDescriptorImpl source, TypeId typeId)\r
+       {\r
+               typeDescriptor = source;\r
+               this.typeId = typeId;;\r
+       }\r
+\r
+       /* DataTypeDescriptor Interface */\r
+       public DataValueDescriptor normalize(DataValueDescriptor source,\r
+                                                                               DataValueDescriptor cachedDest)\r
+                       throws StandardException\r
+       {\r
+               if (SanityManager.DEBUG) {\r
+                       if (cachedDest != null) {\r
+                               if (!getTypeId().isUserDefinedTypeId()) {\r
+                                       String t1 = getTypeName();\r
+                                       String t2 = cachedDest.getTypeName();\r
+                                       if (!t1.equals(t2)) {\r
+\r
+                                               if (!(((t1.equals("DECIMAL") || t1.equals("NUMERIC"))\r
+                                                       && (t2.equals("DECIMAL") || t2.equals("NUMERIC"))) ||\r
+                                                       (t1.startsWith("INT") && t2.startsWith("INT"))))  //INT/INTEGER\r
+\r
+                                                       SanityManager.THROWASSERT(\r
+                                                               "Normalization of " + t2 + " being asked to convert to " + t1);\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               if (source.isNull())\r
+               {\r
+                       if (!isNullable())\r
+                               throw StandardException.newException(SQLState.LANG_NULL_INTO_NON_NULL,"");\r
+\r
+                       if (cachedDest == null)\r
+                               cachedDest = getNull();\r
+                       else\r
+                               cachedDest.setToNull();\r
+               } else {\r
+\r
+                       if (cachedDest == null)\r
+                               cachedDest = getNull();\r
+\r
+                       int jdbcId = getJDBCTypeId();\r
+\r
+                       cachedDest.normalize(this, source);\r
+                       //doing the following check after normalize so that normalize method would get called on long varchs and long varbinary\r
+                       //Need normalize to be called on long varchar for bug 5592 where we need to enforce a lenght limit in db2 mode\r
+                       if ((jdbcId == Types.LONGVARCHAR) || (jdbcId == Types.LONGVARBINARY)) {\r
+                               // special case for possible streams\r
+                               if (source.getClass() == cachedDest.getClass()) \r
+                                       return source;\r
+                       }\r
+\r
+               }\r
+               return cachedDest;\r
+       }\r
+       \r
+       /**\r
+        * Get the dominant type (DataTypeDescriptor) of the 2.\r
+        * For variable length types, the resulting type will have the\r
+        * biggest max length of the 2.\r
+        * If either side is nullable, then the result will also be nullable.\r
+        * \r
+        * If dealing with character string types, then make sure to set the\r
+        * collation info on the dominant type. Following algorithm will be used \r
+        * for dominant DTD's collation determination. Each of the steps of the \r
+        * algorithm have been numbered in the comments below and those same \r
+        * numbers are used in the actual algorithm below so it is easier to \r
+        * understand and maintain.\r
+        * \r
+        * Step 1\r
+        * If the DTD for "this" node has the same collation derivation as the \r
+        * otherDTS, then check if their collation types match too. If the \r
+        * collation types match too, then DTD for dominant type will get the same \r
+        * collation derivation and type.\r
+        *  \r
+        * Step 2\r
+        * If the collation derivation for DTD for "this" node and otherDTS do not \r
+        * match, then check if one of them has the collation derivation of NONE. \r
+        * If that is the case, then dominant DTD will get the collation type and \r
+        * derivation of DTD whose collation derivation is not NONE.\r
+        * \r
+        * Step 3\r
+        * If the collation derivation for DTD for "this" node and otherDTS do not \r
+        * match, and none of them have the derivation of NONE then it means that \r
+        * we are dealing with collation derivation of IMPLICIT and EXPLICIT and \r
+        * hence the dominant DTD should get collation derivation of NONE. This is \r
+        * not a possibility in Derby 10.3 because the only 2 possible collation \r
+        * derivation supported are IMPLICIT and NONE.\r
+        * \r
+        * Step 4\r
+        * If the collation derivation for DTD for "this" node and otherDTS match, \r
+        * then check if the collation types match too. If not, then the dominant \r
+        * DTD should get collation derivation of NONE. \r
+        *\r
+        * @param otherDTS      DataTypeDescriptor to compare with.\r
+        * @param cf            A ClassFactory\r
+        *\r
+        * @return DataTypeDescriptor  DTS for dominant type\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public DataTypeDescriptor getDominantType(DataTypeDescriptor otherDTS, ClassFactory cf)\r
+                       throws StandardException\r
+       {\r
+               boolean                         nullable;\r
+               TypeId                          thisType;\r
+               TypeId                          otherType;\r
+               DataTypeDescriptor      higherType = null;\r
+               DataTypeDescriptor      lowerType = null;\r
+               int                                     maximumWidth;\r
+               int                                     precision = getPrecision();\r
+               int                                     scale = getScale();\r
+\r
+               thisType = getTypeId();\r
+               otherType = otherDTS.getTypeId();\r
+\r
+               /* The result is nullable if either side is nullable */\r
+               nullable = isNullable() || otherDTS.isNullable();\r
+\r
+               /*\r
+               ** The result will have the maximum width of both sides\r
+               */\r
+               maximumWidth = (getMaximumWidth() > otherDTS.getMaximumWidth())\r
+                       ? getMaximumWidth() : otherDTS.getMaximumWidth();\r
+\r
+               /* We need 2 separate methods of determining type dominance - 1 if both\r
+                * types are system built-in types and the other if at least 1 is\r
+                * a user type. (typePrecedence is meaningless for user types.)\r
+                */\r
+               if (!thisType.userType() && !otherType.userType())\r
+               {\r
+                       TypeId  higherTypeId;\r
+                       TypeId  lowerTypeId;\r
+                       if (thisType.typePrecedence() > otherType.typePrecedence())\r
+                       {\r
+                               higherType = this;\r
+                               lowerType = otherDTS;\r
+                               higherTypeId = thisType;\r
+                               lowerTypeId = otherType;\r
+                       }\r
+                       else\r
+                       {\r
+                               higherType = otherDTS;\r
+                               lowerType = this;\r
+                               higherTypeId = otherType;\r
+                               lowerTypeId = thisType;\r
+                       }\r
+\r
+                       //Following is checking if higher type argument is real and other argument is decimal/bigint/integer/smallint,\r
+                       //then result type should be double\r
+                       if (higherTypeId.isRealTypeId() && (!lowerTypeId.isRealTypeId()) && lowerTypeId.isNumericTypeId())\r
+                       {\r
+                               higherType = DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.DOUBLE);\r
+                               higherTypeId = TypeId.getBuiltInTypeId(Types.DOUBLE);\r
+                       }\r
+                       /*\r
+                       ** If we have a DECIMAL/NUMERIC we have to do some\r
+                       ** extra work to make sure the resultant type can\r
+                       ** handle the maximum values for the two input\r
+                       ** types.  We cannot just take the maximum for\r
+                       ** precision.  E.g. we want something like:\r
+                       **\r
+                       **              DEC(10,10) and DEC(3,0) => DEC(13,10)\r
+                       **\r
+                       ** (var)char type needs some conversion handled later.\r
+                       */\r
+                       if (higherTypeId.isDecimalTypeId() && (!lowerTypeId.isStringTypeId()))\r
+                       {\r
+                               precision = higherTypeId.getPrecision(this, otherDTS);\r
+                               if (precision > 31) precision = 31; //db2 silently does this and so do we\r
+                               scale = higherTypeId.getScale(this, otherDTS);\r
+\r
+                               /* maximumWidth needs to count possible leading '-' and\r
+                                * decimal point and leading '0' if scale > 0.  See also\r
+                                * sqlgrammar.jj(exactNumericType).  Beetle 3875\r
+                                */\r
+                               maximumWidth = (scale > 0) ? precision + 3 : precision + 1;\r
+                       }\r
+                       else if (thisType.typePrecedence() != otherType.typePrecedence())\r
+                       {\r
+                               precision = higherType.getPrecision();\r
+                               scale = higherType.getScale();\r
+\r
+                               /* GROSS HACKS:\r
+                                * If we are doing an implicit (var)char->(var)bit conversion\r
+                                * then the maximum width for the (var)char as a (var)bit\r
+                                * is really 16 * its width as a (var)char.  Adjust\r
+                                * maximumWidth accordingly.\r
+                                * If we are doing an implicit (var)char->decimal conversion\r
+                                * then we need to increment the decimal's precision by\r
+                                * 2 * the maximum width for the (var)char and the scale\r
+                                * by the maximum width for the (var)char. The maximumWidth\r
+                                * becomes the new precision + 3.  This is because\r
+                                * the (var)char could contain any decimal value from XXXXXX\r
+                                * to 0.XXXXX.  (In other words, we don't know which side of the\r
+                                * decimal point the characters will be on.)\r
+                                */\r
+                               if (lowerTypeId.isStringTypeId())\r
+                               {\r
+                                       if (higherTypeId.isBitTypeId() &&\r
+                                               ! (higherTypeId.isLongConcatableTypeId()))\r
+                                       {\r
+                                               if (lowerTypeId.isLongConcatableTypeId())\r
+                                               {\r
+                                                       if (maximumWidth > (Integer.MAX_VALUE / 16))\r
+                                                               maximumWidth = Integer.MAX_VALUE;\r
+                                                       else\r
+                                                               maximumWidth *= 16;\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       int charMaxWidth;\r
+\r
+                                                       int fromWidth = lowerType.getMaximumWidth();\r
+                                                       if (fromWidth > (Integer.MAX_VALUE / 16))\r
+                                                               charMaxWidth = Integer.MAX_VALUE;\r
+                                                       else\r
+                                                               charMaxWidth = 16 * fromWidth;\r
+\r
+                                                       maximumWidth = (maximumWidth >= charMaxWidth) ?\r
+                                                                                               maximumWidth : charMaxWidth;\r
+                                               }\r
+                                       }\r
+                               }\r
+\r
+                               /*\r
+                                * If we are doing an implicit (var)char->decimal conversion\r
+                                * then the resulting decimal's precision could be as high as \r
+                                * 2 * the maximum width (precisely 2mw-1) for the (var)char\r
+                                * and the scale could be as high as the maximum width\r
+                                * (precisely mw-1) for the (var)char.\r
+                                * The maximumWidth becomes the new precision + 3.  This is\r
+                                * because the (var)char could contain any decimal value from\r
+                                * XXXXXX to 0.XXXXX.  (In other words, we don't know which\r
+                                * side of the decimal point the characters will be on.)\r
+                                *\r
+                                * We don't follow this algorithm for long varchar because the\r
+                                * maximum length of a long varchar is maxint, and we don't\r
+                                * want to allocate a huge decimal value.  So in this case,\r
+                                * the precision, scale, and maximum width all come from\r
+                                * the decimal type.\r
+                                */\r
+                               if (lowerTypeId.isStringTypeId() &&\r
+                                       ! (lowerTypeId.isLongConcatableTypeId()) &&\r
+                                       higherTypeId.isDecimalTypeId() )\r
+                               {\r
+                                       int charMaxWidth = lowerType.getMaximumWidth();\r
+                                       int charPrecision;\r
+\r
+                                       /*\r
+                                       ** Be careful not to overflow when calculating the\r
+                                       ** precision.  Remember that we will be adding\r
+                                       ** three to the precision to get the maximum width.\r
+                                       */\r
+                                       if (charMaxWidth > (Integer.MAX_VALUE - 3) / 2)\r
+                                               charPrecision = Integer.MAX_VALUE - 3;\r
+                                       else\r
+                                               charPrecision = charMaxWidth * 2;\r
+\r
+                                       if (precision < charPrecision)\r
+                                               precision = charPrecision;\r
+\r
+                                       if (scale < charMaxWidth)\r
+                                               scale = charMaxWidth;\r
+\r
+                                       maximumWidth = precision + 3;\r
+                               }\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       /* At least 1 type is not a system built-in type */\r
+                       ClassInspector          cu = cf.getClassInspector();\r
+\r
+                       TypeId thisCompType = (TypeId) thisType;\r
+                       TypeId otherCompType = (TypeId) otherType;\r
+\r
+                       if (cu.assignableTo(thisCompType.getCorrespondingJavaTypeName(),\r
+                                                           otherCompType.getCorrespondingJavaTypeName()))\r
+                       {\r
+                               higherType = otherDTS;\r
+                       }\r
+                       else\r
+                       {\r
+                               if (SanityManager.DEBUG)\r
+                                               SanityManager.ASSERT(\r
+                                                       cu.assignableTo(otherCompType.getCorrespondingJavaTypeName(),\r
+                                                                       thisCompType.getCorrespondingJavaTypeName()),\r
+                                                       otherCompType.getCorrespondingJavaTypeName() +\r
+                                                       " expected to be assignable to " +\r
+                                                       thisCompType.getCorrespondingJavaTypeName());\r
+\r
+                               higherType = this;\r
+                       }\r
+                       precision = higherType.getPrecision();\r
+                       scale = higherType.getScale();\r
+               }\r
+\r
+\r
+               higherType = new DataTypeDescriptor(higherType, \r
+                               precision, scale, nullable, maximumWidth);\r
+\r
+               //Set collation info on the DTD for dominant type if it is string type\r
+               //The algorithm used is explained in this method's javadoc\r
+               if (higherType.getTypeId().isStringTypeId()) {\r
+                       if (getCollationDerivation() != otherDTS.getCollationDerivation()) {\r
+                               if (getCollationDerivation() == StringDataValue.COLLATION_DERIVATION_NONE) {\r
+                                       //Step 2\r
+                                       higherType.setCollationDerivation(otherDTS.getCollationDerivation());                                   \r
+                                       higherType.setCollationType(otherDTS.getCollationType());                                       \r
+                               } else if (otherDTS.getCollationDerivation() == StringDataValue.COLLATION_DERIVATION_NONE) {\r
+                                       //Step 2\r
+                                       higherType.setCollationDerivation(getCollationDerivation());                                    \r
+                                       higherType.setCollationType(getCollationType());                                                                                \r
+                               } else {\r
+                                       //Step 3\r
+                                       higherType.setCollationDerivation(StringDataValue.COLLATION_DERIVATION_NONE);                                   \r
+                               }\r
+                       } else if (getCollationType() != otherDTS.getCollationType())\r
+                               //Step 4\r
+                               higherType.setCollationDerivation(StringDataValue.COLLATION_DERIVATION_NONE);   \r
+                       else {\r
+                               //Step 1\r
+                               higherType.setCollationDerivation(getCollationDerivation());                                    \r
+                               higherType.setCollationType(getCollationType());                                                                        \r
+                       }\r
+               }\r
+\r
+               return higherType;\r
+       }\r
+\r
+       /**\r
+        * Check whether or not the 2 types (DataTypeDescriptor) have the same type\r
+        * and length.\r
+        * This is useful for UNION when trying to decide whether a NormalizeResultSet\r
+        * is required.\r
+        *\r
+        * @param otherDTS      DataTypeDescriptor to compare with.\r
+        *\r
+        * @return boolean  Whether or not the 2 DTSs have the same type and length.\r
+        */\r
+       public boolean isExactTypeAndLengthMatch(DataTypeDescriptor otherDTS)\r
+       {\r
+               /* Do both sides have the same length? */\r
+               if (getMaximumWidth() != otherDTS.getMaximumWidth()) \r
+               {\r
+                       return false;\r
+               }\r
+               if (getScale() != otherDTS.getScale())\r
+               {\r
+                       return false;\r
+               }\r
+\r
+               if (getPrecision() != otherDTS.getPrecision())\r
+               {       \r
+                       return false;\r
+               }\r
+\r
+               TypeId thisType = getTypeId();\r
+               TypeId otherType = otherDTS.getTypeId();\r
+\r
+               /* Do both sides have the same type? */\r
+               if ( ! thisType.equals(otherType))\r
+               {\r
+                       return false;\r
+               }\r
+\r
+               return true;\r
+       }\r
+\r
+       /**\r
+       * @see TypeDescriptor#getMaximumWidth\r
+        */\r
+       public int      getMaximumWidth()\r
+       {\r
+               return typeDescriptor.getMaximumWidth();\r
+       }\r
+\r
+       /**\r
+        * @see TypeDescriptor#getMaximumWidthInBytes\r
+        */\r
+       public int      getMaximumWidthInBytes()\r
+       {\r
+               return typeDescriptor.getMaximumWidthInBytes();\r
+       }\r
+\r
+       /**\r
+        * Gets the TypeId for the datatype.\r
+        *\r
+        * @return      The TypeId for the datatype.\r
+        */\r
+       public TypeId getTypeId()\r
+       {\r
+               return typeId;\r
+       }\r
+\r
+       /**\r
+               Get a Null for this type.\r
+       */\r
+       public DataValueDescriptor getNull() throws StandardException {\r
+               DataValueDescriptor returnDVD = typeId.getNull();\r
+               //If we are dealing with default collation, then we have got the\r
+               //right DVD already. Just return it.\r
+               if (typeDescriptor.getCollationType() == StringDataValue.COLLATION_TYPE_UCS_BASIC)\r
+                       return returnDVD;                       \r
+               //If we are dealing with territory based collation and returnDVD is \r
+               //of type StringDataValue, then we need to return a StringDataValue   \r
+               //with territory based collation.\r
+               if (returnDVD instanceof StringDataValue) {\r
+                       try {\r
+                               RuleBasedCollator rbs = ConnectionUtil.getCurrentLCC().getDataValueFactory().\r
+                               getCharacterCollator(typeDescriptor.getCollationType());\r
+                               return ((StringDataValue)returnDVD).getValue(rbs);\r
+                       }\r
+                       catch( java.sql.SQLException sqle)\r
+                       {\r
+                               throw StandardException.plainWrapException( sqle);\r
+                       }\r
+               }\r
+               else\r
+                       return returnDVD;                       \r
+       }\r
+\r
+       /**\r
+        * Gets the name of this datatype.\r
+        * \r
+        *\r
+        *  @return     the name of this datatype\r
+        */\r
+       public  String          getTypeName()\r
+       {\r
+               return typeId.getSQLTypeName();\r
+       }\r
+\r
+       /**\r
+        * Get the jdbc type id for this type.  JDBC type can be\r
+        * found in java.sql.Types. \r
+        *\r
+        * @return      a jdbc type, e.g. java.sql.Types.DECIMAL \r
+        *\r
+        * @see Types\r
+        */\r
+       public int getJDBCTypeId()\r
+       {\r
+               return typeId.getJDBCTypeId();\r
+       }\r
+\r
+       /**\r
+        * Returns the number of decimal digits for the datatype, if applicable.\r
+        *\r
+        * @return      The number of decimal digits for the datatype.  Returns\r
+        *              zero for non-numeric datatypes.\r
+        */\r
+       public int      getPrecision()\r
+       {\r
+               return typeDescriptor.getPrecision();\r
+       }\r
+\r
+       /**\r
+        * Returns the number of digits to the right of the decimal for\r
+        * the datatype, if applicable.\r
+        *\r
+        * @return      The number of digits to the right of the decimal for\r
+        *              the datatype.  Returns zero for non-numeric datatypes.\r
+        */\r
+       public int      getScale()\r
+       {\r
+               return typeDescriptor.getScale();\r
+       }\r
+\r
+       /** @see TypeDescriptor#getCollationType() */\r
+       public int      getCollationType()\r
+       {\r
+               return typeDescriptor.getCollationType();\r
+       }\r
+\r
+       /**\r
+        * Gets the name of this datatype.\r
+     * <p>\r
+     * Used to generate strings decribing collation type for error messages.\r
+        * \r
+        *\r
+        *  @return     the name of the collation being used in this type.\r
+        */\r
+       public String getCollationName()\r
+       {\r
+        return(typeDescriptor.getCollationName());\r
+       }\r
+\r
+    /**\r
+     * Set the collation type of this TypeDescriptor\r
+     * @param collationTypeValue This will be COLLATION_TYPE_UCS_BASIC\r
+     * or COLLATION_TYPE_TERRITORY_BASED\r
+     * \r
+     * @see StringDataValue#COLLATION_TYPE_UCS_BASIC\r
+     * @see StringDataValue#COLLATION_TYPE_TERRITORY_BASED\r
+     */\r
+    public void        setCollationType(int collationTypeValue)\r
+       {\r
+               typeDescriptor.setCollationType(collationTypeValue);\r
+       }\r
+\r
+       /** @see TypeDescriptor#getCollationDerivation() */\r
+       public int      getCollationDerivation()\r
+       {\r
+               return typeDescriptor.getCollationDerivation();\r
+       }\r
+\r
+    /**\r
+     * Set the collation derivation of this DTD\r
+     * @param collationDerivationValue This will be \r
+     * COLLATION_DERIVATION_NONE/COLLATION_DERIVATION_IMPLICIT/COLLATION_DERIVATION_EXPLICIT\r
+     * In Derby 10.3, we do not expect to get value COLLATION_DERIVATION_EXPLICIT.\r
+     * \r
+     * @see StringDataValue#COLLATION_DERIVATION_NONE\r
+     * @see StringDataValue#COLLATION_DERIVATION_IMPLICIT\r
+     * @see StringDataValue#COLLATION_DERIVATION_EXPLICIT\r
+\r
+     */\r
+       public void     setCollationDerivation(int collationDerivationValue)\r
+       {\r
+               typeDescriptor.setCollationDerivation(collationDerivationValue);\r
+       }\r
+\r
+       /**\r
+        * Returns TRUE if the datatype can contain NULL, FALSE if not.\r
+        * JDBC supports a return value meaning "nullability unknown" -\r
+        * I assume we will never have columns where the nullability is unknown.\r
+        *\r
+        * @return      TRUE if the datatype can contain NULL, FALSE if not.\r
+        */\r
+       public boolean  isNullable()\r
+       {\r
+               return typeDescriptor.isNullable();\r
+       }\r
+\r
+       /**\r
+        * Set the nullability of the datatype described by this descriptor\r
+        *\r
+        * @param nullable      TRUE means set nullability to TRUE, FALSE\r
+        *                      means set it to FALSE\r
+        */\r
+       public void     setNullability(boolean nullable)\r
+       {\r
+               typeDescriptor.setNullability(nullable);\r
+       }\r
+    \r
+    /**\r
+     * Return a type descriptor identical to the this type\r
+     * with the exception of its nullability. If the nullablity\r
+     * required matches the nullability of this then this is returned.\r
+     * \r
+     * @param isNullable True to return a nullable type, false otherwise.\r
+     */\r
+    public DataTypeDescriptor getNullabilityType(boolean isNullable)\r
+    {\r
+        if (isNullable() == isNullable)\r
+            return this;\r
+        \r
+        return new DataTypeDescriptor(this, isNullable);\r
+    }\r
+\r
+       /**\r
+         Compare if two TypeDescriptors are exactly the same\r
+         @param aTypeDescriptor the typeDescriptor to compare to.\r
+         */\r
+       public boolean equals(Object aTypeDescriptor)\r
+       {\r
+               return typeDescriptor.equals(aTypeDescriptor);\r
+       }\r
+\r
+       /**\r
+        * Check if this type is comparable with the passed type.\r
+        * \r
+        * @param compareWithDTD the type of the instance to compare with this type.\r
+        * @param forEquals True if this is an = or <> comparison, false\r
+        *                                      otherwise.\r
+        * @param cf            A ClassFactory\r
+        * @return true if compareWithDTD is comparable to this type, else false.\r
+        */\r
+       public boolean  comparable(DataTypeDescriptor compareWithDTD,\r
+            boolean forEquals,\r
+            ClassFactory cf){\r
+\r
+               TypeId compareWithTypeID = compareWithDTD.getTypeId();\r
+               int compareWithJDBCTypeId = compareWithTypeID.getJDBCTypeId();\r
+\r
+               // Long types cannot be compared. \r
+               // XML types also fall in this window\r
+               // Says SQL/XML[2003] spec:\r
+               // 4.2.2 XML comparison and assignment\r
+               // "XML values are not comparable."\r
+               // An XML value cannot be compared to any type--\r
+               // not even to other XML values.\r
+               if (compareWithTypeID.isLongConcatableTypeId() || typeId.isLongConcatableTypeId())\r
+                       return false;\r
+\r
+               // Ref types cannot be compared\r
+               if (typeId.isRefTypeId() || compareWithTypeID.isRefTypeId())\r
+                       return false;\r
+               \r
+               //If this DTD is not user defined type but the DTD to be compared with \r
+               //is user defined type, then let the other DTD decide what should be the\r
+               //outcome of the comparable method.\r
+               if (!(typeId.isUserDefinedTypeId()) && \r
+                               (compareWithTypeID.isUserDefinedTypeId()))\r
+                       return compareWithDTD.comparable(this, forEquals, cf);\r
+\r
+       //Numeric types are comparable to numeric types, boolean types and to \r
+               //comparable user types\r
+               if (typeId.isNumericTypeId())\r
+               return (compareWithTypeID.isNumericTypeId() || \r
+                       compareWithTypeID.isBooleanTypeId());\r
+\r
+               //CHAR, VARCHAR and LONGVARCHAR are comparable to strings, boolean, \r
+               //DATE/TIME/TIMESTAMP and to comparable user types\r
+               if (typeId.isStringTypeId()) {\r
+               if((compareWithTypeID.isDateTimeTimeStampTypeID() ||\r
+                               compareWithTypeID.isBooleanTypeId()))\r
+                               return true;\r
+               //If both the types are string types, then we need to make sure\r
+               //they have the same collation set on them\r
+               if (compareWithTypeID.isStringTypeId() && typeId.isStringTypeId()) {\r
+                       return compareCollationInfo(compareWithDTD);                            \r
+               } else\r
+                       return false;//can't be compared                        \r
+               }\r
+\r
+       //Are comparable to other bit types and comparable user types\r
+               if (typeId.isBitTypeId()) \r
+               return (compareWithTypeID.isBitTypeId()); \r
+               \r
+               //Booleans are comparable to Boolean, string, numeric and to \r
+               //comparable user types \r
+               if (typeId.isBooleanTypeId())\r
+               return (compareWithTypeID.getSQLTypeName().equals(typeId.getSQLTypeName()) ||\r
+                               compareWithTypeID.isStringTypeId() ||\r
+                               compareWithTypeID.isNumericTypeId()); \r
+\r
+               //Dates are comparable to dates, strings and to comparable\r
+               //user types.\r
+               if (typeId.getJDBCTypeId() == Types.DATE)\r
+               if (compareWithJDBCTypeId == Types.DATE || \r
+                               compareWithTypeID.isStringTypeId())\r
+                       return true;\r
+               else\r
+                       return false;\r
+\r
+       //Times are comparable to times, strings and to comparable\r
+               //user types.\r
+               if (typeId.getJDBCTypeId() == Types.TIME)\r
+               if (compareWithJDBCTypeId == Types.TIME || \r
+                               compareWithTypeID.isStringTypeId())\r
+                       return true;\r
+               else\r
+                       return false;\r
+\r
+       //Timestamps are comparable to timestamps, strings and to\r
+               //comparable user types.\r
+               if (typeId.getJDBCTypeId() == Types.TIMESTAMP)\r
+               if (compareWithJDBCTypeId == Types.TIMESTAMP || \r
+                               compareWithTypeID.isStringTypeId())\r
+                       return true;\r
+               else\r
+                       return false;\r
+\r
+               //User types are comparable to other user types only if\r
+               //(for now) they are the same type and are being used to\r
+               //implement some JDBC type.  This is sufficient for\r
+               //date/time types; it may be generalized later for e.g.\r
+               //comparison of any user type with one of its subtypes.\r
+               if (typeId.isUserDefinedTypeId() || typeId.getJDBCTypeId() == Types.OTHER) {\r
+               if (forEquals)\r
+                       return true;\r
+               try {\r
+               \r
+                       Class thisClass = cf.getClassInspector().getClass(\r
+                               typeId.getCorrespondingJavaTypeName());\r
+                       \r
+                       return java.lang.Comparable.class.isAssignableFrom(thisClass);\r
+               } catch (ClassNotFoundException cnfe) {\r
+                       return false;\r
+               }                       \r
+               }\r
+\r
+               return false;\r
+       }\r
+       \r
+       /**\r
+        * Compare the collation info on this DTD with the passed DTD. The rules\r
+        * for comparison are as follows (these are as per SQL standard 2003 \r
+        * Section 9.13)\r
+        * \r
+        * 1)If both the DTDs have collation derivation of NONE, then they can't be\r
+        * compared and we return false.\r
+        * 2)If both the DTDs have same collation derivation (which in Derby's case\r
+        * at this point will mean collation derivation of IMPLICIT), then check\r
+        * the collation types. If they match, then return true. If they do not \r
+        * match, then they can't be compared and hence return false.\r
+        * 3)If one DTD has collation derivation of IMPLICIT and other DTD has\r
+        * collation derivation of NONE, then 2 DTDs are comparable using the\r
+        * collation type of DTD with collation derivation of IMPLICIT. Derby does\r
+        * not implement this rule currently and it is being traked as DERBY-2678.\r
+        * Derby's current behavior is to throw an exception if both the DTDs \r
+        * involved in collation operation do not have collation derivation of \r
+        * IMPLICIT. This behavior is a subset of SQL standard.\r
+        * 4)Derby currently does not support collation derivation of EXPLICIT and\r
+        * hence we do not have the code to enforce rules as mentioned in Section\r
+        * 9.13 of SQL spec for collation derivation of EXPLICIT. When we implement\r
+        * collation derivation of EXPLICIT, we should make sure that we follow the\r
+        * rules as specified in the SQL spec for comparability.\r
+        * \r
+        * @param compareWithDTD compare this DTD's collation info\r
+        *  \r
+        * @return value depends on the algorithm above.\r
+        */\r
+       public boolean compareCollationInfo(DataTypeDescriptor compareWithDTD){\r
+               //both the operands can not have the collation derivation of\r
+               //NONE. This is because in that case, we do not know what kind\r
+               //of collation to use for comparison.\r
+               if (getCollationDerivation() == compareWithDTD.getCollationDerivation() &&\r
+                               getCollationDerivation() == StringDataValue.COLLATION_DERIVATION_NONE)\r
+                       return false;\r
+               if (getCollationDerivation() == compareWithDTD.getCollationDerivation() &&\r
+                               getCollationType() == compareWithDTD.getCollationType())\r
+                       return true;//collation matches\r
+               else\r
+                       return false;//collation does not match\r
+               }\r
+                                               \r
+       /**\r
+        * Converts this data type descriptor (including length/precision)\r
+        * to a string. E.g.\r
+        *\r
+        *                      VARCHAR(30)\r
+        *\r
+        *      or\r
+        *\r
+        *                       java.util.Hashtable \r
+        *\r
+        * @return      String version of datatype, suitable for running through\r
+        *                      the Parser.\r
+        */\r
+       public String   getSQLstring()\r
+       {\r
+               return typeId.toParsableString( this );\r
+       }\r
+\r
+       /**\r
+        * Get the simplified type descriptor that is intended to be stored\r
+        * in the system tables.\r
+        */\r
+       public TypeDescriptorImpl getCatalogType()\r
+       {\r
+               return typeDescriptor;\r
+       }\r
+\r
+       /**\r
+        * Get the estimated memory usage for this type descriptor.\r
+        */\r
+       public double estimatedMemoryUsage() {\r
+               switch (typeId.getTypeFormatId())\r
+               {\r
+                       case StoredFormatIds.LONGVARBIT_TYPE_ID:\r
+                               /* Who knows?  Let's just use some big number */\r
+                               return 10000.0;\r
+\r
+                       case StoredFormatIds.BIT_TYPE_ID:\r
+                               return (double) ( ( ((float) getMaximumWidth()) / 8.0) + 0.5);\r
+\r
+                       case StoredFormatIds.BOOLEAN_TYPE_ID:\r
+                               return 4.0;\r
+\r
+                       case StoredFormatIds.CHAR_TYPE_ID:\r
+                       case StoredFormatIds.VARCHAR_TYPE_ID:\r
+                               return (double) (2.0 * getMaximumWidth());\r
+\r
+                       case StoredFormatIds.LONGVARCHAR_TYPE_ID:\r
+                               /* Who knows? Let's just use some big number */\r
+                               return 10000.0;\r
+\r
+                       case StoredFormatIds.DECIMAL_TYPE_ID:\r
+                               /*\r
+                               ** 0.415 converts from number decimal digits to number of 8-bit digits. \r
+                               ** Add 1.0 for the sign byte, and 0.5 to force it to round up.\r
+                               */\r
+                               return (double) ( (getPrecision() * 0.415) + 1.5 );\r
+\r
+                       case StoredFormatIds.DOUBLE_TYPE_ID:\r
+                               return 8.0;\r
+\r
+                       case StoredFormatIds.INT_TYPE_ID:\r
+                               return 4.0;\r
+\r
+                       case StoredFormatIds.LONGINT_TYPE_ID:\r
+                               return 8.0;\r
+\r
+                       case StoredFormatIds.REAL_TYPE_ID:\r
+                               return 4.0;\r
+\r
+                       case StoredFormatIds.SMALLINT_TYPE_ID:\r
+                               return 2.0;\r
+\r
+                       case StoredFormatIds.TINYINT_TYPE_ID:\r
+                               return 1.0;\r
+\r
+                       case StoredFormatIds.REF_TYPE_ID:\r
+                               /* I think 12 is the right number */\r
+                               return 12.0;\r
+\r
+                       case StoredFormatIds.USERDEFINED_TYPE_ID_V3:\r
+                               if (typeId.userType()) {\r
+                                       /* Who knows?  Let's just use some medium-sized number */\r
+                                       return 256.0;\r
+                               }\r
+                       case StoredFormatIds.DATE_TYPE_ID:\r
+                       case StoredFormatIds.TIME_TYPE_ID:\r
+                       case StoredFormatIds.TIMESTAMP_TYPE_ID:\r
+                               return 12.0; \r
+\r
+                       default:\r
+                               return 0.0;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Compare JdbcTypeIds to determine if they represent equivalent\r
+        * SQL types. For example Types.NUMERIC and Types.DECIMAL are\r
+        * equivalent\r
+        *\r
+        * @param existingType  JDBC type id of Derby data type\r
+        * @param jdbcTypeId   JDBC type id passed in from application.\r
+        *\r
+        * @return boolean true if types are equivalent, false if not\r
+        */\r
+\r
+       public static boolean isJDBCTypeEquivalent(int existingType, int jdbcTypeId)\r
+       {\r
+               // Any type matches itself.\r
+               if (existingType == jdbcTypeId)\r
+                       return true;\r
+\r
+               // To a numeric type\r
+               if (DataTypeDescriptor.isNumericType(existingType)) {\r
+                       if (DataTypeDescriptor.isNumericType(jdbcTypeId))\r
+                               return true;\r
+\r
+                       if (DataTypeDescriptor.isCharacterType(jdbcTypeId))\r
+                               return true;\r
+\r
+                       return false;\r
+               }\r
+\r
+               // To character type.\r
+               if (DataTypeDescriptor.isCharacterType(existingType)) {\r
+\r
+                       if (DataTypeDescriptor.isCharacterType(jdbcTypeId))\r
+                               return true;\r
+\r
+                       if (DataTypeDescriptor.isNumericType(jdbcTypeId))\r
+                               return true;\r
+\r
+\r
+                       switch (jdbcTypeId) {\r
+                       case Types.DATE:\r
+                       case Types.TIME:\r
+                       case Types.TIMESTAMP:\r
+                               return true;\r
+                       default:\r
+                               break;\r
+                       }\r
+\r
+                       \r
+                       return false;\r
+\r
+               }\r
+\r
+               // To binary type\r
+               if (DataTypeDescriptor.isBinaryType(existingType)) {\r
+\r
+                       if (DataTypeDescriptor.isBinaryType(jdbcTypeId))\r
+                               return true;\r
+\r
+                       return false;\r
+               }\r
+\r
+               // To DATE, TIME\r
+               if (existingType == Types.DATE || existingType == Types.TIME) {\r
+                       if (DataTypeDescriptor.isCharacterType(jdbcTypeId))\r
+                               return true;\r
+\r
+                       if (jdbcTypeId == Types.TIMESTAMP)\r
+                               return true;\r
+\r
+                       return false;\r
+               }\r
+\r
+               // To TIMESTAMP\r
+               if (existingType == Types.TIMESTAMP) {\r
+                       if (DataTypeDescriptor.isCharacterType(jdbcTypeId))\r
+                               return true;\r
+\r
+                       if (jdbcTypeId == Types.DATE)\r
+                               return true;\r
+\r
+                       return false;\r
+               }\r
+               \r
+               // To CLOB\r
+               if (existingType == Types.CLOB && DataTypeDescriptor.isCharacterType(jdbcTypeId))\r
+                       return true;\r
+\r
+               return false;\r
+       }\r
+\r
+       public static boolean isNumericType(int jdbcType) {\r
+\r
+               switch (jdbcType) {\r
+               case Types.BIT:\r
+               case org.apache.derby.iapi.reference.JDBC30Translation.SQL_TYPES_BOOLEAN:\r
+               case Types.TINYINT:\r
+               case Types.SMALLINT:\r
+               case Types.INTEGER:\r
+               case Types.BIGINT:\r
+               case Types.REAL:\r
+               case Types.FLOAT:\r
+               case Types.DOUBLE:\r
+               case Types.DECIMAL:\r
+               case Types.NUMERIC:\r
+                       return true;\r
+               default:\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Check whether a JDBC type is one of the character types that are\r
+        * compatible with the Java type <code>String</code>.\r
+        *\r
+        * <p><strong>Note:</strong> <code>CLOB</code> is not compatible with\r
+        * <code>String</code>. See tables B-4, B-5 and B-6 in the JDBC 3.0\r
+        * Specification.\r
+        *\r
+        * <p> There are some non-character types that are compatible with\r
+        * <code>String</code> (examples: numeric types, binary types and\r
+        * time-related types), but they are not covered by this method.\r
+        *\r
+        * @param jdbcType a JDBC type\r
+        * @return <code>true</code> iff <code>jdbcType</code> is a character type\r
+        * and compatible with <code>String</code>\r
+        * @see java.sql.Types\r
+        */\r
+       private static boolean isCharacterType(int jdbcType) {\r
+\r
+               switch (jdbcType) {\r
+               case Types.CHAR:\r
+               case Types.VARCHAR:\r
+               case Types.LONGVARCHAR:\r
+                       return true;\r
+               default:\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Check whether a JDBC type is compatible with the Java type\r
+        * <code>byte[]</code>.\r
+        *\r
+        * <p><strong>Note:</strong> <code>BLOB</code> is not compatible with\r
+        * <code>byte[]</code>. See tables B-4, B-5 and B-6 in the JDBC 3.0\r
+        * Specification.\r
+        *\r
+        * @param jdbcType a JDBC type\r
+        * @return <code>true</code> iff <code>jdbcType</code> is compatible with\r
+        * <code>byte[]</code>\r
+        * @see java.sql.Types\r
+        */\r
+       private static boolean isBinaryType(int jdbcType) {\r
+               switch (jdbcType) {\r
+               case Types.BINARY:\r
+               case Types.VARBINARY:\r
+               case Types.LONGVARBINARY:\r
+                       return true;\r
+               default:\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Determine if an ASCII stream can be inserted into a column or parameter\r
+        * of type <code>jdbcType</code>.\r
+        *\r
+        * @param jdbcType JDBC type of column or parameter\r
+        * @return <code>true</code> if an ASCII stream can be inserted;\r
+        *         <code>false</code> otherwise\r
+        */\r
+       public static boolean isAsciiStreamAssignable(int jdbcType) {\r
+               return jdbcType == Types.CLOB || isCharacterType(jdbcType);\r
+       }\r
+\r
+       /**\r
+        * Determine if a binary stream can be inserted into a column or parameter\r
+        * of type <code>jdbcType</code>.\r
+        *\r
+        * @param jdbcType JDBC type of column or parameter\r
+        * @return <code>true</code> if a binary stream can be inserted;\r
+        *         <code>false</code> otherwise\r
+        */\r
+       public static boolean isBinaryStreamAssignable(int jdbcType) {\r
+               return jdbcType == Types.BLOB || isBinaryType(jdbcType);\r
+       }\r
+\r
+       /**\r
+        * Determine if a character stream can be inserted into a column or\r
+        * parameter of type <code>jdbcType</code>.\r
+        *\r
+        * @param jdbcType JDBC type of column or parameter\r
+        * @return <code>true</code> if a character stream can be inserted;\r
+        *         <code>false</code> otherwise\r
+        */\r
+       public static boolean isCharacterStreamAssignable(int jdbcType) {\r
+               // currently, we support the same types for ASCII streams and\r
+               // character streams\r
+               return isAsciiStreamAssignable(jdbcType);\r
+       }\r
+\r
+       public String   toString()\r
+       {\r
+               return typeDescriptor.toString();\r
+       }\r
+\r
+       // Formatable methods\r
+\r
+       /**\r
+        * Read this object from a stream of stored objects.\r
+        *\r
+        * @param in read this.\r
+        *\r
+        * @exception IOException                                       thrown on error\r
+        * @exception ClassNotFoundException            thrown on error\r
+        */\r
+       public void readExternal( ObjectInput in )\r
+                throws IOException, ClassNotFoundException\r
+       {\r
+               /* NOTE: We only write out the generic type id.\r
+                * typeId will be reset to be the generic type id\r
+                * when we get read back in since the generic\r
+                * one is all that is needed at execution time.\r
+                */\r
+               typeId = (TypeId) in.readObject();\r
+               typeDescriptor = (TypeDescriptorImpl) in.readObject();\r
+       }\r
+\r
+       /**\r
+        * Write this object to a stream of stored objects.\r
+        *\r
+        * @param out write bytes here.\r
+        *\r
+        * @exception IOException               thrown on error\r
+        */\r
+       public void writeExternal( ObjectOutput out )\r
+                throws IOException\r
+       {\r
+               out.writeObject( typeId );\r
+               out.writeObject( typeDescriptor );\r
+       }\r
\r
+       /**\r
+        * Get the formatID which corresponds to this class.\r
+        *\r
+        *      @return the formatID of this class\r
+        */\r
+       public  int     getTypeFormatId()       { return StoredFormatIds.DATA_TYPE_SERVICES_IMPL_V01_ID; }\r
+\r
+    /**\r
+     * Check to make sure that this type id is something a user can create\r
+     * him/herself directly through an SQL CREATE TABLE statement.\r
+     * \r
+     * This method is used for CREATE TABLE AS ... WITH [NO] DATA binding\r
+     * because it's possible for the query to return types which are not\r
+     * actually creatable for a user.  DERBY-2605.\r
+     *\r
+     * Three examples are:\r
+     *\r
+     *  BOOLEAN: A user can select boolean columns from system tables, but\r
+     *   s/he is not allowed to create such a column him/herself.\r
+     *\r
+     *  JAVA_OBJECT: A user can select columns of various java object types\r
+     *   from system tables, but s/he is not allowed to create such a column\r
+     *   him/herself.\r
+     *  \r
+     *  DECIMAL: A user can specify a VALUES clause with a constant that\r
+     *   has a precision of greater than 31.  Derby can apparently handle\r
+     *   such a value internally, but the user is not supposed to be able\r
+     *   create such a column him/herself.\r
+     * \r
+     * @return True if the type associated with this DTD can be created via\r
+     *  the CREATE TABLE syntax; false otherwise.\r
+     */\r
+    public boolean isUserCreatableType() throws StandardException\r
+    {\r
+        switch (typeId.getJDBCTypeId())\r
+        {\r
+            case Types.BOOLEAN:\r
+            case Types.JAVA_OBJECT:\r
+               return false;\r
+            case Types.DECIMAL:\r
+                return\r
+                (getPrecision() <= typeId.getMaximumPrecision()) &&\r
+                (getScale() <= typeId.getMaximumScale()) &&\r
+                (getMaximumWidth() <= typeId.getMaximumMaximumWidth());\r
+            default: break;\r
+        }\r
+        return true;\r
+    }\r
+\r
+    /**\r
+     * Return the SQL type name and, if applicable, scale/precision/length\r
+     * for this DataTypeDescriptor.  Note that we want the values from *this*\r
+     * object specifically, not the max values defined on this.typeId.\r
+     */\r
+    public String getFullSQLTypeName()\r
+    {\r
+        StringBuffer sbuf = new StringBuffer(typeId.getSQLTypeName());\r
+        if (typeId.isDecimalTypeId() || typeId.isNumericTypeId())\r
+        {\r
+            sbuf.append("(");\r
+            sbuf.append(getPrecision());\r
+            sbuf.append(", ");\r
+            sbuf.append(getScale());\r
+            sbuf.append(")");\r
+        }\r
+        else if (typeId.variableLength())\r
+        {\r
+            sbuf.append("(");\r
+            sbuf.append(getMaximumWidth());\r
+            sbuf.append(")");\r
+        }\r
+\r
+        return sbuf.toString();\r
+    }\r
+\r
+    /* Return the typename with the collation name for \r
+     * String types.\r
+     */\r
+    public String getSQLTypeNameWithCollation() {\r
+        String name = typeId.getSQLTypeName();\r
+        if (typeId.isStringTypeId()) {\r
+            name = name + " (" + getCollationName() + ")";\r
+        }\r
+        return name;    \r
+    }\r
+}\r
+\r