001: /*
002: * Copyright 2002 (C) TJDO.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the TJDO License version 1.0.
006: * See the terms of the TJDO License in the documentation provided with this software.
007: *
008: * $Id: ColumnInfo.java,v 1.6 2003/02/05 18:15:14 jackknifebarber Exp $
009: */
010:
011: package com.triactive.jdo.store;
012:
013: import java.io.PrintWriter;
014: import java.io.StringWriter;
015: import java.sql.DatabaseMetaData;
016: import java.sql.ResultSet;
017: import java.sql.SQLException;
018: import java.sql.Types;
019: import javax.jdo.JDOFatalDataStoreException;
020:
021: /**
022: * Represents the metadata of a specific table column. This class is
023: * basically a data structure that makes accessing the JDBC column metadata
024: * easier. Each of the items returned by
025: * {@link DatabaseMetaData#getColumns(String,String,String,String)}
026: * is represented by a public field in this class.
027: *
028: * Subclasses of ColumnInfo can be created on a per-DBMS basis to supply missing
029: * metadata or correct faulty metadata obtained from that DBMS's JDBC driver(s).
030: *
031: * @author <a href="mailto:mmartin5@austin.rr.com">Mike Martin</a>
032: * @version $Revision: 1.6 $
033: *
034: * @see StoreManager#getColumnInfo
035: * @see DatabaseAdapter#newColumnInfo
036: * @see DatabaseMetaData#getColumns
037: */
038:
039: class ColumnInfo {
040: /**
041: * The table catalog, which may be <tt>null</tt>.
042: */
043: public String tableCat;
044:
045: /**
046: * The table schema, which may be <tt>null</tt>.
047: */
048: public String tableSchem;
049:
050: /**
051: * The table name.
052: */
053: public String tableName;
054:
055: /**
056: * The column name.
057: */
058: public String columnName;
059:
060: /**
061: * Indicates the JDBC (SQL) data type from {@link java.sql.Types}.
062: */
063: public short dataType;
064:
065: /**
066: * The local type name used by the data source.
067: */
068: public String typeName;
069:
070: /**
071: * Indicates the column size. For char or date types, this is the maximum
072: * number of characters; for numeric or decimal types, this is the precision.
073: */
074: public int columnSize;
075:
076: /**
077: * Indicates the number of fractional digits.
078: */
079: public int decimalDigits;
080:
081: /**
082: * Indicates the radix, which is typically either 10 or 2.
083: */
084: public int numPrecRadix;
085:
086: /**
087: * Indicates whether the column can be NULL.
088: *
089: * @see DatabaseMetaData#columnNoNulls
090: * @see DatabaseMetaData#columnNullable
091: * @see DatabaseMetaData#columnNullableUnknown
092: */
093: public int nullable;
094:
095: /**
096: * An explanatory comment on the column; may be <tt>null</tt>.
097: */
098: public String remarks;
099:
100: /**
101: * The default value for the column; may be <tt>null</tt>.
102: */
103: public String columnDef;
104:
105: /**
106: * Indicates the maximum number of bytes in the column (for char types
107: * only).
108: */
109: public int charOctetLength;
110:
111: /**
112: * Indicates the index of the column in its table; the first column is 1,
113: * the second column is 2, and so on.
114: */
115: public int ordinalPosition;
116:
117: /**
118: * Either "NO" indicating that the column definitely does not allow
119: * <tt>null</tt> values, "YES" indicating that the column might allow
120: * <tt>null</tt> values, or an empty string ("") indicating that nullability
121: * is unknown.
122: */
123: public String isNullable;
124:
125: private int hash = 0;
126:
127: /**
128: * Constructs a column information object from the current row of the given
129: * result set. The {@link ResultSet} object passed must have been obtained
130: * from a call to DatabaseMetaData.getColumns().
131: *
132: * <p>This method only retrieves the values from the current row; the caller
133: * is required to advance to the next row with {@link ResultSet#next}.
134: *
135: * @param rs The result set returned from DatabaseMetaData.getColumns().
136: *
137: * @exception JDOFatalDataStoreException
138: * if a column of column information could not be retrieved from the
139: * result set.
140: */
141:
142: public ColumnInfo(ResultSet rs) throws JDOFatalDataStoreException {
143: try {
144: tableCat = rs.getString(1);
145: tableSchem = rs.getString(2);
146: tableName = rs.getString(3);
147: columnName = rs.getString(4);
148: dataType = rs.getShort(5);
149: typeName = rs.getString(6);
150: columnSize = rs.getInt(7);
151: decimalDigits = rs.getInt(9);
152: numPrecRadix = rs.getInt(10);
153: nullable = rs.getInt(11);
154: remarks = rs.getString(12);
155: columnDef = rs.getString(13);
156: charOctetLength = rs.getInt(16);
157: ordinalPosition = rs.getInt(17);
158: isNullable = rs.getString(18);
159: } catch (SQLException e) {
160: throw new JDOFatalDataStoreException(
161: "Can't read JDBC metadata from result set", e);
162: }
163:
164: if (dataType == Types.OTHER) {
165: /*
166: * This nonsense is for drivers (like Oracle's) that inexplicably
167: * declare some columns to be of type Types.OTHER when they should
168: * obviously know better.
169: */
170: String upperTypeName = typeName.toUpperCase();
171:
172: if (upperTypeName.equals("BLOB"))
173: dataType = Types.BLOB;
174: else if (upperTypeName.equals("CLOB"))
175: dataType = Types.CLOB;
176: else if (upperTypeName.equals("FLOAT"))
177: dataType = Types.FLOAT;
178: else if (upperTypeName.endsWith("LONGVARBINARY"))
179: dataType = Types.LONGVARBINARY;
180: else if (upperTypeName.endsWith("LONGVARCHAR"))
181: dataType = Types.LONGVARCHAR;
182: }
183: }
184:
185: /**
186: * Constructs a column information object from its individual attributes.
187: *
188: * <p>This can be useful to subclasses and/or custom DatabaseAdapters that
189: * need to modify and/or correct the metadata returned by the JDBC driver.
190: */
191:
192: public ColumnInfo(String tableCat, String tableSchem,
193: String tableName, String columnName, short dataType,
194: String typeName, int columnSize, int decimalDigits,
195: int numPrecRadix, int nullable, String remarks,
196: String columnDef, int charOctetLength, int ordinalPosition,
197: String isNullable) {
198: this .tableCat = tableCat;
199: this .tableSchem = tableSchem;
200: this .tableName = tableName;
201: this .columnName = columnName;
202: this .dataType = dataType;
203: this .typeName = typeName;
204: this .columnSize = columnSize;
205: this .decimalDigits = decimalDigits;
206: this .numPrecRadix = numPrecRadix;
207: this .nullable = nullable;
208: this .remarks = remarks;
209: this .columnDef = columnDef;
210: this .charOctetLength = charOctetLength;
211: this .ordinalPosition = ordinalPosition;
212: this .isNullable = isNullable;
213: }
214:
215: /**
216: * Indicates whether some object is "equal to" this one. Two <tt>ColumnInfo
217: * </tt> objects are considered equal if their catalog, schema, table, and
218: * column names are all equal.
219: *
220: * @param obj the reference object with which to compare
221: *
222: * @return <tt>true</tt> if this object is equal to the obj argument;
223: * <tt>false</tt> otherwise.
224: */
225:
226: public final boolean equals(Object obj) {
227: if (obj == this )
228: return true;
229:
230: if (!(obj instanceof ColumnInfo))
231: return false;
232:
233: ColumnInfo ci = (ColumnInfo) obj;
234:
235: return (tableCat == null ? ci.tableCat == null : tableCat
236: .equals(ci.tableCat))
237: && (tableSchem == null ? ci.tableSchem == null
238: : tableSchem.equals(ci.tableSchem))
239: && tableName.equals(ci.tableName)
240: && columnName.equals(ci.columnName);
241: }
242:
243: /**
244: * Returns a hash code value for this object.
245: *
246: * @return a hash code value for this object.
247: */
248:
249: public final int hashCode() {
250: if (hash == 0) {
251: hash = (tableCat == null ? 0 : tableCat.hashCode())
252: ^ (tableSchem == null ? 0 : tableSchem.hashCode())
253: ^ tableName.hashCode() ^ columnName.hashCode();
254: }
255:
256: return hash;
257: }
258:
259: /**
260: * Returns the string representation of this object.
261: *
262: * @return string representation of this object.
263: */
264:
265: public String toString() {
266: StringWriter sw = new StringWriter();
267: PrintWriter pw = new PrintWriter(sw);
268:
269: pw.println(this .getClass().getName());
270: pw.print(" tableCat = ");
271: pw.println(tableCat);
272: pw.print(" tableSchem = ");
273: pw.println(tableSchem);
274: pw.print(" tableName = ");
275: pw.println(tableName);
276: pw.print(" columnName = ");
277: pw.println(columnName);
278: pw.print(" dataType = ");
279: pw.println(dataType);
280: pw.print(" typeName = ");
281: pw.println(typeName);
282: pw.print(" columnSize = ");
283: pw.println(columnSize);
284: pw.print(" decimalDigits = ");
285: pw.println(decimalDigits);
286: pw.print(" numPrecRadix = ");
287: pw.println(numPrecRadix);
288: pw.print(" nullable = ");
289: pw.println(nullable);
290: pw.print(" remarks = ");
291: pw.println(remarks);
292: pw.print(" columnDef = ");
293: pw.println(columnDef);
294: pw.print(" charOctetLength = ");
295: pw.println(charOctetLength);
296: pw.print(" ordinalPosition = ");
297: pw.println(ordinalPosition);
298: pw.print(" isNullable = ");
299: pw.println(isNullable);
300: pw.close();
301:
302: return sw.toString();
303: }
304: }
|