0001: /*
0002:
0003: Derby - Class org.apache.derby.iapi.types.DataTypeDescriptor
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to you under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. You may obtain a copy of the License at
0011:
0012: http://www.apache.org/licenses/LICENSE-2.0
0013:
0014: Unless required by applicable law or agreed to in writing, software
0015: distributed under the License is distributed on an "AS IS" BASIS,
0016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: See the License for the specific language governing permissions and
0018: limitations under the License.
0019:
0020: */
0021:
0022: package org.apache.derby.iapi.types;
0023:
0024: import org.apache.derby.iapi.services.io.Formatable;
0025: import org.apache.derby.iapi.error.StandardException;
0026: import org.apache.derby.iapi.services.loader.ClassFactory;
0027:
0028: import org.apache.derby.catalog.TypeDescriptor;
0029: import org.apache.derby.catalog.types.TypeDescriptorImpl;
0030:
0031: import org.apache.derby.iapi.services.sanity.SanityManager;
0032:
0033: import org.apache.derby.iapi.services.io.StoredFormatIds;
0034: import org.apache.derby.iapi.services.io.FormatIdUtil;
0035: import org.apache.derby.iapi.services.io.Formatable;
0036:
0037: import org.apache.derby.iapi.error.StandardException;
0038:
0039: import org.apache.derby.iapi.types.RowLocation;
0040:
0041: import org.apache.derby.iapi.services.loader.ClassFactory;
0042: import org.apache.derby.iapi.services.loader.ClassInspector;
0043:
0044: import org.apache.derby.iapi.reference.SQLState;
0045:
0046: import java.io.ObjectOutput;
0047: import java.io.ObjectInput;
0048: import java.io.IOException;
0049:
0050: import java.sql.Types;
0051:
0052: /**
0053: * This is an implementation of DataTypeDescriptor from the generic language
0054: * datatype module interface.
0055: *
0056: * @author Jeff Lichtman
0057: * @version 1.0
0058: */
0059:
0060: public final class DataTypeDescriptor implements TypeDescriptor,
0061: Formatable {
0062: /********************************************************
0063: **
0064: ** This class implements Formatable. That means that it
0065: ** can write itself to and from a formatted stream. If
0066: ** you add more fields to this class, make sure that you
0067: ** also write/read them with the writeExternal()/readExternal()
0068: ** methods.
0069: **
0070: ** If, inbetween releases, you add more fields to this class,
0071: ** then you should bump the version number emitted by the getTypeFormatId()
0072: ** method.
0073: **
0074: ********************************************************/
0075:
0076: /*
0077: ** Static creators
0078: */
0079: /**
0080: * Get a descriptor that corresponds to a builtin JDBC type.
0081: *
0082: * @param jdbcType The int type of the JDBC type for which to get
0083: * a corresponding SQL DataTypeDescriptor
0084: *
0085: * @return A new DataTypeDescriptor that corresponds to the Java type.
0086: * A null return value means there is no corresponding SQL type
0087: */
0088: public static DataTypeDescriptor getBuiltInDataTypeDescriptor(
0089: int jdbcType) {
0090: return DataTypeDescriptor.getBuiltInDataTypeDescriptor(
0091: jdbcType, true);
0092: }
0093:
0094: public static DataTypeDescriptor getBuiltInDataTypeDescriptor(
0095: int jdbcType, int length) {
0096: return DataTypeDescriptor.getBuiltInDataTypeDescriptor(
0097: jdbcType, true, length);
0098: }
0099:
0100: /**
0101: * Get a descriptor that corresponds to a builtin JDBC type.
0102: *
0103: * @param jdbcType The int type of the JDBC type for which to get
0104: * a corresponding SQL DataTypeDescriptor
0105: * @param isNullable TRUE means it could contain NULL, FALSE means
0106: * it definitely cannot contain NULL.
0107: *
0108: * @return A new DataTypeDescriptor that corresponds to the Java type.
0109: * A null return value means there is no corresponding SQL type
0110: */
0111: public static DataTypeDescriptor getBuiltInDataTypeDescriptor(
0112: int jdbcType, boolean isNullable) {
0113: TypeId typeId = TypeId.getBuiltInTypeId(jdbcType);
0114: if (typeId == null) {
0115: return null;
0116: }
0117:
0118: return new DataTypeDescriptor(typeId, isNullable);
0119: }
0120:
0121: /**
0122: * Get a descriptor that corresponds to a builtin JDBC type.
0123: *
0124: * @param jdbcType The int type of the JDBC type for which to get
0125: * a corresponding SQL DataTypeDescriptor
0126: * @param isNullable TRUE means it could contain NULL, FALSE means
0127: * it definitely cannot contain NULL.
0128: *
0129: * @return A new DataTypeDescriptor that corresponds to the Java type.
0130: * A null return value means there is no corresponding SQL type
0131: */
0132: public static DataTypeDescriptor getBuiltInDataTypeDescriptor(
0133: int jdbcType, boolean isNullable, int maxLength) {
0134: TypeId typeId = TypeId.getBuiltInTypeId(jdbcType);
0135: if (typeId == null) {
0136: return null;
0137: }
0138:
0139: return new DataTypeDescriptor(typeId, isNullable, maxLength);
0140: }
0141:
0142: /**
0143: * Get a DataTypeServices that corresponds to a builtin SQL type
0144: *
0145: * @param sqlTypeName The name of the type for which to get
0146: * a corresponding SQL DataTypeDescriptor
0147: *
0148: * @return A new DataTypeDescriptor that corresponds to the Java type.
0149: * A null return value means there is no corresponding SQL type (only for 'char')
0150: */
0151: public static DataTypeDescriptor getBuiltInDataTypeDescriptor(
0152: String sqlTypeName) {
0153: return new DataTypeDescriptor(TypeId
0154: .getBuiltInTypeId(sqlTypeName), true);
0155: }
0156:
0157: /**
0158: * Get a DataTypeServices that corresponds to a builtin SQL type
0159: *
0160: * @param sqlTypeName The name of the type for which to get
0161: * a corresponding SQL DataTypeDescriptor
0162: *
0163: * @return A new DataTypeDescriptor that corresponds to the Java type.
0164: * A null return value means there is no corresponding SQL type (only for 'char')
0165: */
0166: public static DataTypeDescriptor getBuiltInDataTypeDescriptor(
0167: String sqlTypeName, int length) {
0168: return new DataTypeDescriptor(TypeId
0169: .getBuiltInTypeId(sqlTypeName), true, length);
0170: }
0171:
0172: /**
0173: * Get a DataTypeServices that corresponds to a Java type
0174: *
0175: * @param javaTypeName The name of the Java type for which to get
0176: * a corresponding SQL DataTypeDescriptor
0177: *
0178: * @return A new DataTypeDescriptor that corresponds to the Java type.
0179: * A null return value means there is no corresponding SQL type (only for 'char')
0180: */
0181: public static DataTypeDescriptor getSQLDataTypeDescriptor(
0182: String javaTypeName) {
0183: return DataTypeDescriptor.getSQLDataTypeDescriptor(
0184: javaTypeName, true);
0185: }
0186:
0187: /**
0188: * Get a DataTypeServices that corresponds to a Java type
0189: *
0190: * @param javaTypeName The name of the Java type for which to get
0191: * a corresponding SQL DataTypeDescriptor
0192: * @param isNullable TRUE means it could contain NULL, FALSE means
0193: * it definitely cannot contain NULL.
0194: *
0195: * @return A new DataTypeDescriptor that corresponds to the Java type.
0196: * A null return value means there is no corresponding SQL type (only for 'char')
0197: */
0198: public static DataTypeDescriptor getSQLDataTypeDescriptor(
0199: String javaTypeName, boolean isNullable) {
0200: TypeId typeId = TypeId.getSQLTypeForJavaType(javaTypeName);
0201: if (typeId == null) {
0202: return null;
0203: }
0204:
0205: return new DataTypeDescriptor(typeId, isNullable);
0206: }
0207:
0208: /**
0209: * Get a DataTypeDescriptor that corresponds to a Java type
0210: *
0211: * @param javaTypeName The name of the Java type for which to get
0212: * a corresponding SQL DataTypeDescriptor
0213: * @param precision The number of decimal digits
0214: * @param scale The number of digits after the decimal point
0215: * @param isNullable TRUE means it could contain NULL, FALSE means
0216: * it definitely cannot contain NULL.
0217: * @param maximumWidth The maximum width of a data value
0218: * represented by this type.
0219: *
0220: * @return A new DataTypeDescriptor that corresponds to the Java type.
0221: * A null return value means there is no corresponding SQL type.
0222: */
0223: public static DataTypeDescriptor getSQLDataTypeDescriptor(
0224: String javaTypeName, int precision, int scale,
0225: boolean isNullable, int maximumWidth) {
0226: TypeId typeId = TypeId.getSQLTypeForJavaType(javaTypeName);
0227: if (typeId == null) {
0228: return null;
0229: }
0230:
0231: return new DataTypeDescriptor(typeId, precision, scale,
0232: isNullable, maximumWidth);
0233: }
0234:
0235: /*
0236: ** Instance fields & methods
0237: */
0238:
0239: private TypeDescriptorImpl typeDescriptor;
0240: private TypeId typeId;
0241:
0242: /**
0243: * Public niladic constructor. Needed for Formatable interface to work.
0244: *
0245: */
0246: public DataTypeDescriptor() {
0247: }
0248:
0249: /**
0250: * Constructor for use with numeric types
0251: *
0252: * @param typeId The typeId of the type being described
0253: * @param precision The number of decimal digits.
0254: * @param scale The number of digits after the decimal point.
0255: * @param isNullable TRUE means it could contain NULL, FALSE means
0256: * it definitely cannot contain NULL.
0257: * @param maximumWidth The maximum number of bytes for this datatype
0258: */
0259: public DataTypeDescriptor(TypeId typeId, int precision, int scale,
0260: boolean isNullable, int maximumWidth) {
0261: this .typeId = typeId;
0262: typeDescriptor = new TypeDescriptorImpl(typeId.getBaseTypeId(),
0263: precision, scale, isNullable, maximumWidth);
0264: }
0265:
0266: /**
0267: * Constructor for use with non-numeric types
0268: *
0269: * @param typeId The typeId of the type being described
0270: * @param isNullable TRUE means it could contain NULL, FALSE means
0271: * it definitely cannot contain NULL.
0272: * @param maximumWidth The maximum number of bytes for this datatype
0273: */
0274: public DataTypeDescriptor(TypeId typeId, boolean isNullable,
0275: int maximumWidth) {
0276: this .typeId = typeId;
0277: typeDescriptor = new TypeDescriptorImpl(typeId.getBaseTypeId(),
0278: isNullable, maximumWidth);
0279: }
0280:
0281: public DataTypeDescriptor(TypeId typeId, boolean isNullable) {
0282:
0283: this .typeId = typeId;
0284: typeDescriptor = new TypeDescriptorImpl(typeId.getBaseTypeId(),
0285: typeId.getMaximumPrecision(), typeId.getMaximumScale(),
0286: isNullable, typeId.getMaximumMaximumWidth());
0287: }
0288:
0289: public DataTypeDescriptor(DataTypeDescriptor source,
0290: boolean isNullable) {
0291: this .typeId = source.typeId;
0292: typeDescriptor = new TypeDescriptorImpl(source.typeDescriptor,
0293: source.getPrecision(), source.getScale(), isNullable,
0294: source.getMaximumWidth());
0295: }
0296:
0297: /**
0298: * Constructor for internal uses only.
0299: * (This is useful when the precision and scale are potentially wider than
0300: * those in the source, like when determining the dominant data type.)
0301: *
0302: * @param source The DTSI to copy
0303: * @param precision The number of decimal digits.
0304: * @param scale The number of digits after the decimal point.
0305: * @param isNullable TRUE means it could contain NULL, FALSE means
0306: * it definitely cannot contain NULL.
0307: * @param maximumWidth The maximum number of bytes for this datatype
0308: */
0309: public DataTypeDescriptor(DataTypeDescriptor source, int precision,
0310: int scale, boolean isNullable, int maximumWidth) {
0311: this .typeId = source.typeId;
0312: typeDescriptor = new TypeDescriptorImpl(source.typeDescriptor,
0313: precision, scale, isNullable, maximumWidth);
0314: }
0315:
0316: /**
0317: * Constructor for internal uses only
0318: *
0319: * @param source The DTSI to copy
0320: * @param isNullable TRUE means it could contain NULL, FALSE means
0321: * it definitely cannot contain NULL.
0322: * @param maximumWidth The maximum number of bytes for this datatype
0323: */
0324: public DataTypeDescriptor(DataTypeDescriptor source,
0325: boolean isNullable, int maximumWidth) {
0326: this .typeId = source.typeId;
0327: typeDescriptor = new TypeDescriptorImpl(source.typeDescriptor,
0328: isNullable, maximumWidth);
0329: }
0330:
0331: /**
0332: * Constructor for use in reconstructing a DataTypeDescriptor from a
0333: * TypeDescriptorImpl and a TypeId
0334: *
0335: * @param source The TypeDescriptorImpl to construct this DTSI from
0336: */
0337: public DataTypeDescriptor(TypeDescriptorImpl source, TypeId typeId) {
0338: typeDescriptor = source;
0339: this .typeId = typeId;
0340: ;
0341: }
0342:
0343: /* DataTypeDescriptor Interface */
0344: public DataValueDescriptor normalize(DataValueDescriptor source,
0345: DataValueDescriptor cachedDest) throws StandardException {
0346: if (SanityManager.DEBUG) {
0347: if (cachedDest != null) {
0348: if (!getTypeId().isUserDefinedTypeId()) {
0349: String t1 = getTypeName();
0350: String t2 = cachedDest.getTypeName();
0351: if (!t1.equals(t2)) {
0352:
0353: if (!(((t1.equals("DECIMAL") || t1
0354: .equals("NUMERIC")) && (t2
0355: .equals("DECIMAL") || t2
0356: .equals("NUMERIC"))) || (t1
0357: .startsWith("INT") && t2
0358: .startsWith("INT")))) //INT/INTEGER
0359:
0360: SanityManager
0361: .THROWASSERT("Normalization of "
0362: + t2
0363: + " being asked to convert to "
0364: + t1);
0365: }
0366: }
0367: }
0368: }
0369:
0370: if (source.isNull()) {
0371: if (!isNullable())
0372: throw StandardException.newException(
0373: SQLState.LANG_NULL_INTO_NON_NULL, "");
0374:
0375: if (cachedDest == null)
0376: cachedDest = getNull();
0377: else
0378: cachedDest.setToNull();
0379: } else {
0380:
0381: if (cachedDest == null)
0382: cachedDest = getNull();
0383:
0384: int jdbcId = getJDBCTypeId();
0385:
0386: cachedDest.normalize(this , source);
0387: //doing the following check after normalize so that normalize method would get called on long varchs and long varbinary
0388: //Need normalize to be called on long varchar for bug 5592 where we need to enforce a lenght limit in db2 mode
0389: if ((jdbcId == Types.LONGVARCHAR)
0390: || (jdbcId == Types.LONGVARBINARY)) {
0391: // special case for possible streams
0392: if (source.getClass() == cachedDest.getClass())
0393: return source;
0394: }
0395:
0396: }
0397: return cachedDest;
0398: }
0399:
0400: /**
0401: * Get the dominant type (DataTypeDescriptor) of the 2.
0402: * For variable length types, the resulting type will have the
0403: * biggest max length of the 2.
0404: * If either side is nullable, then the result will also be nullable.
0405: *
0406: * @param otherDTS DataTypeDescriptor to compare with.
0407: * @param cf A ClassFactory
0408: *
0409: * @return DataTypeDescriptor DTS for dominant type
0410: *
0411: * @exception StandardException Thrown on error
0412: */
0413: public DataTypeDescriptor getDominantType(
0414: DataTypeDescriptor otherDTS, ClassFactory cf)
0415: throws StandardException {
0416: boolean nullable;
0417: TypeId this Type;
0418: TypeId otherType;
0419: DataTypeDescriptor higherType = null;
0420: DataTypeDescriptor lowerType = null;
0421: int maximumWidth;
0422: int precision = getPrecision();
0423: int scale = getScale();
0424:
0425: this Type = getTypeId();
0426: otherType = otherDTS.getTypeId();
0427:
0428: /* The result is nullable if either side is nullable */
0429: nullable = isNullable() || otherDTS.isNullable();
0430:
0431: /*
0432: ** The result will have the maximum width of both sides
0433: */
0434: maximumWidth = (getMaximumWidth() > otherDTS.getMaximumWidth()) ? getMaximumWidth()
0435: : otherDTS.getMaximumWidth();
0436:
0437: /* We need 2 separate methods of determining type dominance - 1 if both
0438: * types are system built-in types and the other if at least 1 is
0439: * a user type. (typePrecedence is meaningless for user types.)
0440: */
0441: if (!this Type.userType() && !otherType.userType()) {
0442: TypeId higherTypeId;
0443: TypeId lowerTypeId;
0444: if (this Type.typePrecedence() > otherType.typePrecedence()) {
0445: higherType = this ;
0446: lowerType = otherDTS;
0447: higherTypeId = this Type;
0448: lowerTypeId = otherType;
0449: } else {
0450: higherType = otherDTS;
0451: lowerType = this ;
0452: higherTypeId = otherType;
0453: lowerTypeId = this Type;
0454: }
0455:
0456: //Following is checking if higher type argument is real and other argument is decimal/bigint/integer/smallint,
0457: //then result type should be double
0458: if (higherTypeId.isRealTypeId()
0459: && (!lowerTypeId.isRealTypeId())
0460: && lowerTypeId.isNumericTypeId()) {
0461: higherType = DataTypeDescriptor
0462: .getBuiltInDataTypeDescriptor(Types.DOUBLE);
0463: higherTypeId = TypeId.getBuiltInTypeId(Types.DOUBLE);
0464: }
0465: /*
0466: ** If we have a DECIMAL/NUMERIC we have to do some
0467: ** extra work to make sure the resultant type can
0468: ** handle the maximum values for the two input
0469: ** types. We cannot just take the maximum for
0470: ** precision. E.g. we want something like:
0471: **
0472: ** DEC(10,10) and DEC(3,0) => DEC(13,10)
0473: **
0474: ** (var)char type needs some conversion handled later.
0475: */
0476: if (higherTypeId.isDecimalTypeId()
0477: && (!lowerTypeId.isStringTypeId())) {
0478: precision = higherTypeId.getPrecision(this , otherDTS);
0479: if (precision > 31)
0480: precision = 31; //db2 silently does this and so do we
0481: scale = higherTypeId.getScale(this , otherDTS);
0482:
0483: /* maximumWidth needs to count possible leading '-' and
0484: * decimal point and leading '0' if scale > 0. See also
0485: * sqlgrammar.jj(exactNumericType). Beetle 3875
0486: */
0487: maximumWidth = (scale > 0) ? precision + 3
0488: : precision + 1;
0489: } else if (this Type.typePrecedence() != otherType
0490: .typePrecedence()) {
0491: precision = higherType.getPrecision();
0492: scale = higherType.getScale();
0493:
0494: /* GROSS HACKS:
0495: * If we are doing an implicit (var)char->(var)bit conversion
0496: * then the maximum width for the (var)char as a (var)bit
0497: * is really 16 * its width as a (var)char. Adjust
0498: * maximumWidth accordingly.
0499: * If we are doing an implicit (var)char->decimal conversion
0500: * then we need to increment the decimal's precision by
0501: * 2 * the maximum width for the (var)char and the scale
0502: * by the maximum width for the (var)char. The maximumWidth
0503: * becomes the new precision + 3. This is because
0504: * the (var)char could contain any decimal value from XXXXXX
0505: * to 0.XXXXX. (In other words, we don't know which side of the
0506: * decimal point the characters will be on.)
0507: */
0508: if (lowerTypeId.isStringTypeId()) {
0509: if (higherTypeId.isBitTypeId()
0510: && !(higherTypeId.isLongConcatableTypeId())) {
0511: if (lowerTypeId.isLongConcatableTypeId()) {
0512: if (maximumWidth > (Integer.MAX_VALUE / 16))
0513: maximumWidth = Integer.MAX_VALUE;
0514: else
0515: maximumWidth *= 16;
0516: } else {
0517: int charMaxWidth;
0518:
0519: int fromWidth = lowerType.getMaximumWidth();
0520: if (fromWidth > (Integer.MAX_VALUE / 16))
0521: charMaxWidth = Integer.MAX_VALUE;
0522: else
0523: charMaxWidth = 16 * fromWidth;
0524:
0525: maximumWidth = (maximumWidth >= charMaxWidth) ? maximumWidth
0526: : charMaxWidth;
0527: }
0528: }
0529: }
0530:
0531: /*
0532: * If we are doing an implicit (var)char->decimal conversion
0533: * then the resulting decimal's precision could be as high as
0534: * 2 * the maximum width (precisely 2mw-1) for the (var)char
0535: * and the scale could be as high as the maximum width
0536: * (precisely mw-1) for the (var)char.
0537: * The maximumWidth becomes the new precision + 3. This is
0538: * because the (var)char could contain any decimal value from
0539: * XXXXXX to 0.XXXXX. (In other words, we don't know which
0540: * side of the decimal point the characters will be on.)
0541: *
0542: * We don't follow this algorithm for long varchar because the
0543: * maximum length of a long varchar is maxint, and we don't
0544: * want to allocate a huge decimal value. So in this case,
0545: * the precision, scale, and maximum width all come from
0546: * the decimal type.
0547: */
0548: if (lowerTypeId.isStringTypeId()
0549: && !(lowerTypeId.isLongConcatableTypeId())
0550: && higherTypeId.isDecimalTypeId()) {
0551: int charMaxWidth = lowerType.getMaximumWidth();
0552: int charPrecision;
0553:
0554: /*
0555: ** Be careful not to overflow when calculating the
0556: ** precision. Remember that we will be adding
0557: ** three to the precision to get the maximum width.
0558: */
0559: if (charMaxWidth > (Integer.MAX_VALUE - 3) / 2)
0560: charPrecision = Integer.MAX_VALUE - 3;
0561: else
0562: charPrecision = charMaxWidth * 2;
0563:
0564: if (precision < charPrecision)
0565: precision = charPrecision;
0566:
0567: if (scale < charMaxWidth)
0568: scale = charMaxWidth;
0569:
0570: maximumWidth = precision + 3;
0571: }
0572: }
0573: } else {
0574: /* At least 1 type is not a system built-in type */
0575: ClassInspector cu = cf.getClassInspector();
0576:
0577: TypeId this CompType = (TypeId) this Type;
0578: TypeId otherCompType = (TypeId) otherType;
0579:
0580: if (cu.assignableTo(this CompType
0581: .getCorrespondingJavaTypeName(), otherCompType
0582: .getCorrespondingJavaTypeName())) {
0583: higherType = otherDTS;
0584: } else {
0585: if (SanityManager.DEBUG)
0586: SanityManager
0587: .ASSERT(
0588: cu
0589: .assignableTo(
0590: otherCompType
0591: .getCorrespondingJavaTypeName(),
0592: this CompType
0593: .getCorrespondingJavaTypeName()),
0594: otherCompType
0595: .getCorrespondingJavaTypeName()
0596: + " expected to be assignable to "
0597: + this CompType
0598: .getCorrespondingJavaTypeName());
0599:
0600: higherType = this ;
0601: }
0602: precision = higherType.getPrecision();
0603: scale = higherType.getScale();
0604: }
0605:
0606: higherType = new DataTypeDescriptor(higherType, precision,
0607: scale, nullable, maximumWidth);
0608:
0609: return higherType;
0610: }
0611:
0612: /**
0613: * Check whether or not the 2 types (DataTypeDescriptor) have the same type
0614: * and length.
0615: * This is useful for UNION when trying to decide whether a NormalizeResultSet
0616: * is required.
0617: *
0618: * @param otherDTS DataTypeDescriptor to compare with.
0619: *
0620: * @return boolean Whether or not the 2 DTSs have the same type and length.
0621: */
0622: public boolean isExactTypeAndLengthMatch(DataTypeDescriptor otherDTS) {
0623: /* Do both sides have the same length? */
0624: if (getMaximumWidth() != otherDTS.getMaximumWidth()) {
0625: return false;
0626: }
0627: if (getScale() != otherDTS.getScale()) {
0628: return false;
0629: }
0630:
0631: if (getPrecision() != otherDTS.getPrecision()) {
0632: return false;
0633: }
0634:
0635: TypeId this Type = getTypeId();
0636: TypeId otherType = otherDTS.getTypeId();
0637:
0638: /* Do both sides have the same type? */
0639: if (!this Type.equals(otherType)) {
0640: return false;
0641: }
0642:
0643: return true;
0644: }
0645:
0646: /**
0647: * @see TypeDescriptor#getMaximumWidth
0648: */
0649: public int getMaximumWidth() {
0650: return typeDescriptor.getMaximumWidth();
0651: }
0652:
0653: /**
0654: * @see TypeDescriptor#getMaximumWidthInBytes
0655: */
0656: public int getMaximumWidthInBytes() {
0657: return typeDescriptor.getMaximumWidthInBytes();
0658: }
0659:
0660: /**
0661: * Gets the TypeId for the datatype.
0662: *
0663: * @return The TypeId for the datatype.
0664: */
0665: public TypeId getTypeId() {
0666: return typeId;
0667: }
0668:
0669: /**
0670: Get a Null for this type.
0671: */
0672: public DataValueDescriptor getNull() {
0673: return typeId.getNull();
0674: }
0675:
0676: /**
0677: * Gets the name of this datatype.
0678: *
0679: *
0680: * @return the name of this datatype
0681: */
0682: public String getTypeName() {
0683: return typeId.getSQLTypeName();
0684: }
0685:
0686: /**
0687: * Get the jdbc type id for this type. JDBC type can be
0688: * found in java.sql.Types.
0689: *
0690: * @return a jdbc type, e.g. java.sql.Types.DECIMAL
0691: *
0692: * @see Types
0693: */
0694: public int getJDBCTypeId() {
0695: return typeId.getJDBCTypeId();
0696: }
0697:
0698: /**
0699: * Returns the number of decimal digits for the datatype, if applicable.
0700: *
0701: * @return The number of decimal digits for the datatype. Returns
0702: * zero for non-numeric datatypes.
0703: */
0704: public int getPrecision() {
0705: return typeDescriptor.getPrecision();
0706: }
0707:
0708: /**
0709: * Returns the number of digits to the right of the decimal for
0710: * the datatype, if applicable.
0711: *
0712: * @return The number of digits to the right of the decimal for
0713: * the datatype. Returns zero for non-numeric datatypes.
0714: */
0715: public int getScale() {
0716: return typeDescriptor.getScale();
0717: }
0718:
0719: /**
0720: * Returns TRUE if the datatype can contain NULL, FALSE if not.
0721: * JDBC supports a return value meaning "nullability unknown" -
0722: * I assume we will never have columns where the nullability is unknown.
0723: *
0724: * @return TRUE if the datatype can contain NULL, FALSE if not.
0725: */
0726: public boolean isNullable() {
0727: return typeDescriptor.isNullable();
0728: }
0729:
0730: /**
0731: * Set the nullability of the datatype described by this descriptor
0732: *
0733: * @param nullable TRUE means set nullability to TRUE, FALSE
0734: * means set it to FALSE
0735: */
0736: public void setNullability(boolean nullable) {
0737: typeDescriptor.setNullability(nullable);
0738: }
0739:
0740: /**
0741: Compare if two TypeDescriptors are exactly the same
0742: @param aTypeDescriptor the typeDescriptor to compare to.
0743: */
0744: public boolean equals(Object aTypeDescriptor) {
0745: return typeDescriptor.equals(aTypeDescriptor);
0746: }
0747:
0748: /**
0749: * Converts this data type descriptor (including length/precision)
0750: * to a string. E.g.
0751: *
0752: * VARCHAR(30)
0753: *
0754: * or
0755: *
0756: * java.util.Hashtable
0757: *
0758: * @return String version of datatype, suitable for running through
0759: * the Parser.
0760: */
0761: public String getSQLstring() {
0762: return typeId.toParsableString(this );
0763: }
0764:
0765: /**
0766: * Get the simplified type descriptor that is intended to be stored
0767: * in the system tables.
0768: */
0769: public TypeDescriptorImpl getCatalogType() {
0770: return typeDescriptor;
0771: }
0772:
0773: /**
0774: * Get the estimated memory usage for this type descriptor.
0775: */
0776: public double estimatedMemoryUsage() {
0777: switch (typeId.getTypeFormatId()) {
0778: case StoredFormatIds.LONGVARBIT_TYPE_ID:
0779: /* Who knows? Let's just use some big number */
0780: return 10000.0;
0781:
0782: case StoredFormatIds.BIT_TYPE_ID:
0783: return (double) ((((float) getMaximumWidth()) / 8.0) + 0.5);
0784:
0785: case StoredFormatIds.BOOLEAN_TYPE_ID:
0786: return 4.0;
0787:
0788: case StoredFormatIds.CHAR_TYPE_ID:
0789: case StoredFormatIds.VARCHAR_TYPE_ID:
0790: case StoredFormatIds.NATIONAL_CHAR_TYPE_ID:
0791: case StoredFormatIds.NATIONAL_VARCHAR_TYPE_ID:
0792: return (double) (2.0 * getMaximumWidth());
0793:
0794: case StoredFormatIds.LONGVARCHAR_TYPE_ID:
0795: case StoredFormatIds.NATIONAL_LONGVARCHAR_TYPE_ID:
0796: /* Who knows? Let's just use some big number */
0797: return 10000.0;
0798:
0799: case StoredFormatIds.DECIMAL_TYPE_ID:
0800: /*
0801: ** 0.415 converts from number decimal digits to number of 8-bit digits.
0802: ** Add 1.0 for the sign byte, and 0.5 to force it to round up.
0803: */
0804: return (double) ((getPrecision() * 0.415) + 1.5);
0805:
0806: case StoredFormatIds.DOUBLE_TYPE_ID:
0807: return 8.0;
0808:
0809: case StoredFormatIds.INT_TYPE_ID:
0810: return 4.0;
0811:
0812: case StoredFormatIds.LONGINT_TYPE_ID:
0813: return 8.0;
0814:
0815: case StoredFormatIds.REAL_TYPE_ID:
0816: return 4.0;
0817:
0818: case StoredFormatIds.SMALLINT_TYPE_ID:
0819: return 2.0;
0820:
0821: case StoredFormatIds.TINYINT_TYPE_ID:
0822: return 1.0;
0823:
0824: case StoredFormatIds.REF_TYPE_ID:
0825: /* I think 12 is the right number */
0826: return 12.0;
0827:
0828: case StoredFormatIds.USERDEFINED_TYPE_ID_V3:
0829: if (typeId.userType()) {
0830: /* Who knows? Let's just use some medium-sized number */
0831: return 256.0;
0832: }
0833: case StoredFormatIds.DATE_TYPE_ID:
0834: case StoredFormatIds.TIME_TYPE_ID:
0835: case StoredFormatIds.TIMESTAMP_TYPE_ID:
0836: return 12.0;
0837:
0838: default:
0839: return 0.0;
0840: }
0841: }
0842:
0843: /**
0844: * Compare JdbcTypeIds to determine if they represent equivalent
0845: * SQL types. For example Types.NUMERIC and Types.DECIMAL are
0846: * equivalent
0847: *
0848: * @param existingType JDBC type id of Cloudscape data type
0849: * @param jdbcTypeId JDBC type id passed in from application.
0850: *
0851: * @return boolean true if types are equivalent, false if not
0852: */
0853:
0854: public static boolean isJDBCTypeEquivalent(int existingType,
0855: int jdbcTypeId) {
0856: // Any type matches itself.
0857: if (existingType == jdbcTypeId)
0858: return true;
0859:
0860: // To a numeric type
0861: if (DataTypeDescriptor.isNumericType(existingType)) {
0862: if (DataTypeDescriptor.isNumericType(jdbcTypeId))
0863: return true;
0864:
0865: if (DataTypeDescriptor.isCharacterType(jdbcTypeId))
0866: return true;
0867:
0868: return false;
0869: }
0870:
0871: // To character type.
0872: if (DataTypeDescriptor.isCharacterType(existingType)) {
0873:
0874: if (DataTypeDescriptor.isCharacterType(jdbcTypeId))
0875: return true;
0876:
0877: if (DataTypeDescriptor.isNumericType(jdbcTypeId))
0878: return true;
0879:
0880: switch (jdbcTypeId) {
0881: case Types.DATE:
0882: case Types.TIME:
0883: case Types.TIMESTAMP:
0884: return true;
0885: default:
0886: break;
0887: }
0888:
0889: return false;
0890:
0891: }
0892:
0893: // To binary type
0894: if (DataTypeDescriptor.isBinaryType(existingType)) {
0895:
0896: if (DataTypeDescriptor.isBinaryType(jdbcTypeId))
0897: return true;
0898:
0899: return false;
0900: }
0901:
0902: // To DATE, TIME
0903: if (existingType == Types.DATE || existingType == Types.TIME) {
0904: if (DataTypeDescriptor.isCharacterType(jdbcTypeId))
0905: return true;
0906:
0907: if (jdbcTypeId == Types.TIMESTAMP)
0908: return true;
0909:
0910: return false;
0911: }
0912:
0913: // To TIMESTAMP
0914: if (existingType == Types.TIMESTAMP) {
0915: if (DataTypeDescriptor.isCharacterType(jdbcTypeId))
0916: return true;
0917:
0918: if (jdbcTypeId == Types.DATE)
0919: return true;
0920:
0921: return false;
0922: }
0923:
0924: // To CLOB
0925: if (existingType == Types.CLOB
0926: && DataTypeDescriptor.isCharacterType(jdbcTypeId))
0927: return true;
0928:
0929: return false;
0930: }
0931:
0932: public static boolean isNumericType(int jdbcType) {
0933:
0934: switch (jdbcType) {
0935: case Types.BIT:
0936: case org.apache.derby.iapi.reference.JDBC30Translation.SQL_TYPES_BOOLEAN:
0937: case Types.TINYINT:
0938: case Types.SMALLINT:
0939: case Types.INTEGER:
0940: case Types.BIGINT:
0941: case Types.REAL:
0942: case Types.FLOAT:
0943: case Types.DOUBLE:
0944: case Types.DECIMAL:
0945: case Types.NUMERIC:
0946: return true;
0947: default:
0948: return false;
0949: }
0950: }
0951:
0952: /**
0953: * Check whether a JDBC type is one of the character types that are
0954: * compatible with the Java type <code>String</code>.
0955: *
0956: * <p><strong>Note:</strong> <code>CLOB</code> is not compatible with
0957: * <code>String</code>. See tables B-4, B-5 and B-6 in the JDBC 3.0
0958: * Specification.
0959: *
0960: * <p> There are some non-character types that are compatible with
0961: * <code>String</code> (examples: numeric types, binary types and
0962: * time-related types), but they are not covered by this method.
0963: *
0964: * @param jdbcType a JDBC type
0965: * @return <code>true</code> iff <code>jdbcType</code> is a character type
0966: * and compatible with <code>String</code>
0967: * @see java.sql.Types
0968: */
0969: private static boolean isCharacterType(int jdbcType) {
0970:
0971: switch (jdbcType) {
0972: case Types.CHAR:
0973: case Types.VARCHAR:
0974: case Types.LONGVARCHAR:
0975: return true;
0976: default:
0977: return false;
0978: }
0979: }
0980:
0981: /**
0982: * Check whether a JDBC type is compatible with the Java type
0983: * <code>byte[]</code>.
0984: *
0985: * <p><strong>Note:</strong> <code>BLOB</code> is not compatible with
0986: * <code>byte[]</code>. See tables B-4, B-5 and B-6 in the JDBC 3.0
0987: * Specification.
0988: *
0989: * @param jdbcType a JDBC type
0990: * @return <code>true</code> iff <code>jdbcType</code> is compatible with
0991: * <code>byte[]</code>
0992: * @see java.sql.Types
0993: */
0994: private static boolean isBinaryType(int jdbcType) {
0995: switch (jdbcType) {
0996: case Types.BINARY:
0997: case Types.VARBINARY:
0998: case Types.LONGVARBINARY:
0999: return true;
1000: default:
1001: return false;
1002: }
1003: }
1004:
1005: /**
1006: * Determine if an ASCII stream can be inserted into a column or parameter
1007: * of type <code>jdbcType</code>.
1008: *
1009: * @param jdbcType JDBC type of column or parameter
1010: * @return <code>true</code> if an ASCII stream can be inserted;
1011: * <code>false</code> otherwise
1012: */
1013: public static boolean isAsciiStreamAssignable(int jdbcType) {
1014: return jdbcType == Types.CLOB || isCharacterType(jdbcType);
1015: }
1016:
1017: /**
1018: * Determine if a binary stream can be inserted into a column or parameter
1019: * of type <code>jdbcType</code>.
1020: *
1021: * @param jdbcType JDBC type of column or parameter
1022: * @return <code>true</code> if a binary stream can be inserted;
1023: * <code>false</code> otherwise
1024: */
1025: public static boolean isBinaryStreamAssignable(int jdbcType) {
1026: return jdbcType == Types.BLOB || isBinaryType(jdbcType);
1027: }
1028:
1029: /**
1030: * Determine if a character stream can be inserted into a column or
1031: * parameter of type <code>jdbcType</code>.
1032: *
1033: * @param jdbcType JDBC type of column or parameter
1034: * @return <code>true</code> if a character stream can be inserted;
1035: * <code>false</code> otherwise
1036: */
1037: public static boolean isCharacterStreamAssignable(int jdbcType) {
1038: // currently, we support the same types for ASCII streams and
1039: // character streams
1040: return isAsciiStreamAssignable(jdbcType);
1041: }
1042:
1043: public String toString() {
1044: return typeDescriptor.toString();
1045: }
1046:
1047: // Formatable methods
1048:
1049: /**
1050: * Read this object from a stream of stored objects.
1051: *
1052: * @param in read this.
1053: *
1054: * @exception IOException thrown on error
1055: * @exception ClassNotFoundException thrown on error
1056: */
1057: public void readExternal(ObjectInput in) throws IOException,
1058: ClassNotFoundException {
1059: /* NOTE: We only write out the generic type id.
1060: * typeId will be reset to be the generic type id
1061: * when we get read back in since the generic
1062: * one is all that is needed at execution time.
1063: */
1064: typeId = (TypeId) in.readObject();
1065: typeDescriptor = (TypeDescriptorImpl) in.readObject();
1066: }
1067:
1068: /**
1069: * Write this object to a stream of stored objects.
1070: *
1071: * @param out write bytes here.
1072: *
1073: * @exception IOException thrown on error
1074: */
1075: public void writeExternal(ObjectOutput out) throws IOException {
1076: out.writeObject(typeId);
1077: out.writeObject(typeDescriptor);
1078: }
1079:
1080: /**
1081: * Get the formatID which corresponds to this class.
1082: *
1083: * @return the formatID of this class
1084: */
1085: public int getTypeFormatId() {
1086: return StoredFormatIds.DATA_TYPE_SERVICES_IMPL_V01_ID;
1087: }
1088: }
|