001: /*
002:
003: Derby - Class org.apache.derby.catalog.types.TypeDescriptorImpl
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.catalog.types;
023:
024: import org.apache.derby.iapi.services.io.StoredFormatIds;
025: import org.apache.derby.iapi.services.io.Formatable;
026:
027: import org.apache.derby.catalog.TypeDescriptor;
028:
029: import java.io.ObjectOutput;
030: import java.io.ObjectInput;
031: import java.io.IOException;
032: import java.sql.Types;
033:
034: public class TypeDescriptorImpl implements TypeDescriptor, Formatable {
035: /********************************************************
036: **
037: ** This class implements Formatable. That means that it
038: ** can write itself to and from a formatted stream. If
039: ** you add more fields to this class, make sure that you
040: ** also write/read them with the writeExternal()/readExternal()
041: ** methods.
042: **
043: ** If, inbetween releases, you add more fields to this class,
044: ** then you should bump the version number emitted by the getTypeFormatId()
045: ** method.
046: **
047: ********************************************************/
048:
049: private BaseTypeIdImpl typeId;
050: private int precision;
051: private int scale;
052: private boolean isNullable;
053: private int maximumWidth;
054:
055: /**
056: * Public niladic constructor. Needed for Formatable interface to work.
057: *
058: */
059: public TypeDescriptorImpl() {
060: }
061:
062: /**
063: * Constructor for use with numeric types
064: *
065: * @param typeId The typeId of the type being described
066: * @param precision The number of decimal digits.
067: * @param scale The number of digits after the decimal point.
068: * @param isNullable TRUE means it could contain NULL, FALSE means
069: * it definitely cannot contain NULL.
070: * @param maximumWidth The maximum number of bytes for this datatype
071: */
072: public TypeDescriptorImpl(BaseTypeIdImpl typeId, int precision,
073: int scale, boolean isNullable, int maximumWidth) {
074: this .typeId = typeId;
075: this .precision = precision;
076: this .scale = scale;
077: this .isNullable = isNullable;
078: this .maximumWidth = maximumWidth;
079: }
080:
081: /**
082: * Constructor for use with non-numeric types
083: *
084: * @param typeId The typeId of the type being described
085: * @param isNullable TRUE means it could contain NULL, FALSE means
086: * it definitely cannot contain NULL.
087: * @param maximumWidth The maximum number of bytes for this datatype
088: */
089: public TypeDescriptorImpl(BaseTypeIdImpl typeId,
090: boolean isNullable, int maximumWidth) {
091: this .typeId = typeId;
092: this .isNullable = isNullable;
093: this .maximumWidth = maximumWidth;
094: }
095:
096: /**
097: * Constructor for internal uses only.
098: * (This is useful when the precision and scale are potentially wider than
099: * those in the source, like when determining the dominant data type.)
100: *
101: * @param source The DTSI to copy
102: * @param precision The number of decimal digits.
103: * @param scale The number of digits after the decimal point.
104: * @param isNullable TRUE means it could contain NULL, FALSE means
105: * it definitely cannot contain NULL.
106: * @param maximumWidth The maximum number of bytes for this datatype
107: */
108: public TypeDescriptorImpl(TypeDescriptorImpl source, int precision,
109: int scale, boolean isNullable, int maximumWidth) {
110: this .typeId = source.typeId;
111: this .precision = precision;
112: this .scale = scale;
113: this .isNullable = isNullable;
114: this .maximumWidth = maximumWidth;
115: }
116:
117: /**
118: * Constructor for internal uses only
119: *
120: * @param source The DTSI to copy
121: * @param isNullable TRUE means it could contain NULL, FALSE means
122: * it definitely cannot contain NULL.
123: * @param maximumWidth The maximum number of bytes for this datatype
124: */
125: public TypeDescriptorImpl(TypeDescriptorImpl source,
126: boolean isNullable, int maximumWidth) {
127: this .typeId = source.typeId;
128: this .precision = source.precision;
129: this .scale = source.scale;
130: this .isNullable = isNullable;
131: this .maximumWidth = maximumWidth;
132: }
133:
134: /**
135: * @see TypeDescriptor#getMaximumWidth
136: */
137: public int getMaximumWidth() {
138: return maximumWidth;
139: }
140:
141: /**
142: * Return the length of this type in bytes. Note that
143: * while the JDBC API _does_ define a need for
144: * returning length in bytes of a type, it doesn't
145: * state clearly what that means for the various
146: * types. We assume therefore that the values here
147: * are meant to match those specified by the ODBC
148: * specification (esp. since ODBC clients are more
149: * likely to need this value than a Java client).
150: * The ODBC spec that defines the values we use here
151: * can be found at the following link:
152: *
153: * http://msdn.microsoft.com/library/default.asp?url=/library/
154: * en-us/odbc/htm/odbctransfer_octet_length.asp
155: *
156: * @see TypeDescriptor#getMaximumWidthInBytes
157: */
158: public int getMaximumWidthInBytes() {
159: switch (typeId.getJDBCTypeId()) {
160:
161: case Types.BIT:
162: case Types.TINYINT:
163: case Types.SMALLINT:
164: case Types.INTEGER:
165: case Types.REAL:
166: case Types.DOUBLE:
167: case Types.FLOAT:
168: case Types.BINARY:
169: case Types.VARBINARY:
170: case Types.LONGVARBINARY:
171: case Types.BLOB:
172:
173: // For all of these, just take the maximumWidth,
174: // since that already holds the length in bytes.
175: return maximumWidth;
176:
177: // For BIGINT values, ODBC spec says to return
178: // 40 because max length of a C/C++ BIGINT in
179: // string form is 20 and we assume the client
180: // character set is Unicode (spec says to
181: // multiply by 2 for unicode).
182: case Types.BIGINT:
183: return 40;
184:
185: // ODBC spec explicitly declares what the lengths
186: // should be for datetime values, based on the
187: // declared fields of SQL_DATE_STRUCT, SQL_TIME_STRUCT,
188: // and SQL_TIMESTAMP_STRUCT. So we just use those
189: // values.
190: case Types.DATE:
191: case Types.TIME:
192: return 6;
193:
194: case Types.TIMESTAMP:
195: return 16;
196:
197: // ODBC spec says that for numeric/decimal values,
198: // we should use max number of digits plus 2
199: // (for sign and decimal point), since that's
200: // the length of a decimal value in string form.
201: // And since we assume client character set
202: // is unicode, we have to multiply by 2 to
203: // get the number of bytes.
204: case Types.NUMERIC:
205: case Types.DECIMAL:
206: return 2 * (precision + 2);
207:
208: // ODBC spec says to use length in chars
209: // for character types, times two if we
210: // assume client character set is unicode.
211: // If 2 * character length is greater than
212: // variable type (in this case, integer),
213: // then we return the max value for an
214: // integer.
215: case Types.CHAR:
216: case Types.VARCHAR:
217: case Types.LONGVARCHAR:
218: case Types.CLOB:
219: if ((maximumWidth > 0) && (2 * maximumWidth < 0))
220: // integer overflow; return max integer possible.
221: return Integer.MAX_VALUE;
222: else
223: return 2 * maximumWidth;
224:
225: case Types.ARRAY:
226: case Types.DISTINCT:
227: case Types.NULL:
228: case Types.OTHER:
229: case Types.REF:
230: case Types.STRUCT:
231: case Types.JAVA_OBJECT:
232: default:
233:
234: // For these we don't know, so return the "don't-know"
235: // indicator.
236: return -1;
237:
238: }
239:
240: }
241:
242: /**
243: * Get the jdbc type id for this type. JDBC type can be
244: * found in java.sql.Types.
245: *
246: * @return a jdbc type, e.g. java.sql.Types.DECIMAL
247: *
248: * @see Types
249: */
250: public int getJDBCTypeId() {
251: return typeId.getJDBCTypeId();
252: }
253:
254: /**
255: * Gets the name of this datatype.
256: *
257: *
258: * @return the name of this datatype
259: */
260: public String getTypeName() {
261: return typeId.getSQLTypeName();
262: }
263:
264: /**
265: * Returns the number of decimal digits for the datatype, if applicable.
266: *
267: * @return The number of decimal digits for the datatype. Returns
268: * zero for non-numeric datatypes.
269: */
270: public int getPrecision() {
271: return precision;
272: }
273:
274: /**
275: * Returns the number of digits to the right of the decimal for
276: * the datatype, if applicable.
277: *
278: * @return The number of digits to the right of the decimal for
279: * the datatype. Returns zero for non-numeric datatypes.
280: */
281: public int getScale() {
282: return scale;
283: }
284:
285: /**
286: * Returns TRUE if the datatype can contain NULL, FALSE if not.
287: * JDBC supports a return value meaning "nullability unknown" -
288: * I assume we will never have columns where the nullability is unknown.
289: *
290: * @return TRUE if the datatype can contain NULL, FALSE if not.
291: */
292: public boolean isNullable() {
293: return isNullable;
294: }
295:
296: /**
297: * Set the nullability of the datatype described by this descriptor
298: *
299: * @param nullable TRUE means set nullability to TRUE, FALSE
300: * means set it to FALSE
301: */
302: public void setNullability(boolean nullable) {
303: isNullable = nullable;
304: }
305:
306: /**
307: * Converts this data type descriptor (including length/precision)
308: * to a string. E.g.
309:
310:
311: *
312: * VARCHAR(30)
313: *
314: * or
315: *
316: * java.util.Hashtable
317: *
318: * @return String version of datatype, suitable for running through
319: * the Parser.
320: */
321: public String getSQLstring() {
322: return typeId.toParsableString(this );
323: }
324:
325: public String toString() {
326: String s = getSQLstring();
327: if (!isNullable())
328: return s + " NOT NULL";
329: return s;
330: }
331:
332: /**
333: * Get the type Id stored within this type descriptor.
334: */
335: public BaseTypeIdImpl getTypeId() {
336: return typeId;
337: }
338:
339: /**
340: Compare if two TypeDescriptors are exactly the same
341: @param object the dataTypeDescriptor to compare to.
342: */
343: public boolean equals(Object object) {
344: TypeDescriptor typeDescriptor = (TypeDescriptor) object;
345:
346: if (!this .getTypeName().equals(typeDescriptor.getTypeName())
347: || this .precision != typeDescriptor.getPrecision()
348: || this .scale != typeDescriptor.getScale()
349: || this .isNullable != typeDescriptor.isNullable()
350: || this .maximumWidth != typeDescriptor
351: .getMaximumWidth())
352: return false;
353: else
354: return true;
355: }
356:
357: // Formatable methods
358:
359: /**
360: * Read this object from a stream of stored objects.
361: *
362: * @param in read this.
363: *
364: * @exception IOException thrown on error
365: * @exception ClassNotFoundException thrown on error
366: */
367: public void readExternal(ObjectInput in) throws IOException,
368: ClassNotFoundException {
369: typeId = (BaseTypeIdImpl) in.readObject();
370: precision = in.readInt();
371: scale = in.readInt();
372: isNullable = in.readBoolean();
373: maximumWidth = in.readInt();
374: }
375:
376: /**
377: * Write this object to a stream of stored objects.
378: *
379: * @param out write bytes here.
380: *
381: * @exception IOException thrown on error
382: */
383: public void writeExternal(ObjectOutput out) throws IOException {
384: out.writeObject(typeId);
385: out.writeInt(precision);
386: out.writeInt(scale);
387: out.writeBoolean(isNullable);
388: out.writeInt(maximumWidth);
389: }
390:
391: /**
392: * Get the formatID which corresponds to this class.
393: *
394: * @return the formatID of this class
395: */
396: public int getTypeFormatId() {
397: return StoredFormatIds.DATA_TYPE_IMPL_DESCRIPTOR_V01_ID;
398: }
399: }
|